/* ============================================================
   MADE VISIBLE — Portal stylesheet
   portal.html + portal-dashboard.html only. Loaded AFTER css/style.css,
   which still provides the site's tokens (:root), base typography, the
   header/logo, buttons (.btn), .label, .container, .field.
   The main site never downloads this file.

   Feature styles live in their own files, linked from
   portal-dashboard.html after this one (contract v3 §10):
     css/portal-training.css    Training tab (§6)
     css/portal-onboarding.css  Client onboarding card (§8)
     css/portal-reports.css     Reports tab (§9)
   ============================================================ */

/* ------------------------------------------------------------
   Portal (portal.html + portal-dashboard.html)
   Client & team login and the role-based dashboard. Self-contained:
   these pages do not load main.js, so nothing here depends on the
   site's animation classes.
   ------------------------------------------------------------ */

.portal-body {
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
}
.portal-body [hidden] { display: none !important; }

/* No flash of the wrong view: without JS only the <noscript> panel shows. */
.no-js .portal-main > [data-view] { display: none !important; }

.portal-skip {
  position: absolute;
  left: 1rem;
  top: -4rem;
  z-index: 200;
  padding: 0.6rem 1rem;
  border-radius: 999px;
  background: var(--ivory);
  color: var(--obsidian);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
.portal-skip:focus { top: 1rem; }

.portal-visually-hidden {
  position: absolute !important;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* Header */
.portal-header {
  position: relative;
  z-index: 2;
  border-bottom: 1px solid var(--line);
}
.portal-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem 1.25rem;
  padding-block: 1.35rem;
}
.portal-header__actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  flex-wrap: wrap;
  gap: 0.6rem;
}
/* "Back to site": a quiet text link like the site's nav (underline sweeps in on hover) */
.portal-header__actions { gap: 1.5rem; }
.portal-header__back {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  padding-block: 0.25rem;
  font-size: 0.7rem;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.18em;
  color: var(--stone);
  transition: color 0.35s ease;
}
.portal-header__back::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 1px;
  background: var(--champagne);
  transform: scaleX(0);
  transform-origin: right;
  transition: transform 0.45s var(--ease-out);
}
.portal-header__back .arrow { transition: transform 0.4s var(--ease-out); }
.portal-header__back:hover,
.portal-header__back:focus-visible { color: var(--ivory); }
.portal-header__back:hover::after,
.portal-header__back:focus-visible::after { transform: scaleX(1); transform-origin: left; }
.portal-header__back:hover .arrow { transform: translateX(-3px); }

/* "Log out": the site's ghost pill button (.btn .btn--ghost .btn--nav) */
.portal-signout { font-family: inherit; cursor: pointer; }
.portal-signout:disabled { opacity: 0.6; cursor: progress; }

/* Main stage */
.portal-main {
  flex: 1;
  position: relative;
  overflow: hidden;
  padding-block: clamp(3.5rem, 9vw, 7rem);
}
.portal-main:focus { outline: none; }
.portal-glow {
  position: absolute;
  left: 50%;
  top: -18rem;
  width: min(70rem, 160vw);
  height: 36rem;
  transform: translateX(-50%);
  background: radial-gradient(ellipse at center, rgba(198, 174, 130, 0.13), rgba(198, 174, 130, 0) 62%);
  pointer-events: none;
}
/* The dashboard stage does not clip: its tab bar sticks to the viewport
   (position: sticky stops working inside an overflow clip). The glow clips
   itself instead: a full-width box from the top of the stage holding the same
   ellipse, so the light looks exactly as before. A tighter top: the welcome
   is a greeting, the content starts on the first screen. */
.portal-main--dashboard {
  overflow: visible;
  padding-block: clamp(1.75rem, 4vw, 3rem) clamp(3.5rem, 9vw, 7rem);
}
.portal-main--dashboard > .portal-glow {
  left: 0;
  right: 0;
  top: 0;
  width: auto;
  height: 18rem;
  overflow: hidden;
  transform: none;
  background: none;
}
.portal-main--dashboard > .portal-glow::before {
  content: "";
  position: absolute;
  left: 50%;
  top: -18rem;
  width: min(70rem, 160vw);
  height: 36rem;
  transform: translateX(-50%);
  background: radial-gradient(ellipse at center, rgba(198, 174, 130, 0.13), rgba(198, 174, 130, 0) 62%);
}

.portal-panel {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: calc(34rem + 2 * var(--gutter));
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.portal-title {
  margin-top: 1.4rem;
  font-size: clamp(2.3rem, 6.5vw, 3.75rem);
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.04;
}
.portal-title .serif { font-size: 1.12em; }
.portal-lead {
  margin-top: 1.25rem;
  color: var(--stone);
  font-size: clamp(1rem, 1.4vw, 1.1rem);
  line-height: 1.65;
  max-width: 40ch;
  text-wrap: pretty;
}
.portal-note {
  margin-top: 1.75rem;
  color: var(--stone);
  font-size: 0.85rem;
  text-align: center;
}
.portal-note--left { text-align: left; }
.portal-inline-link {
  color: var(--champagne);
  text-decoration: underline;
  text-decoration-color: rgba(198, 174, 130, 0.4);
  text-underline-offset: 3px;
  transition: color 0.3s ease, text-decoration-color 0.3s ease;
}
.portal-inline-link:hover { color: var(--ivory); text-decoration-color: var(--ivory); }
.portal-email { color: var(--ivory); font-weight: 500; overflow-wrap: anywhere; }

.portal-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.9rem;
  margin-top: 2rem;
}

/* Cards and forms */
.portal-card {
  background: var(--charcoal);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: clamp(1.5rem, 4vw, 2.5rem);
}
.portal-form { margin-top: 2.25rem; }
.portal-form .field:last-of-type { margin-bottom: 1.1rem; }
.portal-form input:-webkit-autofill,
.portal-form input:-webkit-autofill:hover,
.portal-form input:-webkit-autofill:focus {
  -webkit-text-fill-color: var(--ivory);
  -webkit-box-shadow: 0 0 0 100px var(--charcoal) inset;
  caret-color: var(--ivory);
}
.portal-form--flat { margin-top: 1.75rem; padding-top: 1.5rem; border-top: 1px solid var(--line); }
/* a folded section of the account panel (Change password): a hairline row that opens */
.portal-drawer__fold { margin-top: 1.5rem; border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
.portal-drawer__fold-toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.85rem 0.1rem;
  list-style: none;
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--ivory);
  cursor: pointer;
  transition: color 0.3s ease;
}
.portal-drawer__fold-toggle::-webkit-details-marker { display: none; }
.portal-drawer__fold-toggle::after {
  content: "+";
  flex: none;
  color: var(--champagne);
  font-size: 1.1rem;
  font-weight: 400;
  letter-spacing: 0;
  line-height: 1;
  transition: transform 0.35s var(--ease-out);
}
.portal-drawer__fold[open] > .portal-drawer__fold-toggle::after { transform: rotate(45deg); }
.portal-drawer__fold-toggle:hover { color: var(--champagne); }
.portal-drawer__fold-toggle:focus-visible { outline: 1px solid var(--champagne); outline-offset: 2px; }
.portal-drawer__fold > .portal-form--flat { margin-top: 0; padding-top: 0.25rem; padding-bottom: 0.5rem; border-top: 0; }
@media (prefers-reduced-motion: reduce) { .portal-drawer__fold-toggle, .portal-drawer__fold-toggle::after { transition: none; } }
.portal-form__legend {
  margin-bottom: 1.25rem;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--ivory);
}
.portal-form__foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem 1.5rem;
  margin-top: 0.5rem;
}
.portal-hint { font-size: 0.74rem; color: var(--stone); opacity: 0.8; }

.portal-submit:disabled { cursor: progress; opacity: 0.75; }
.portal-submit:disabled::before { transform: translateY(101%); }

.portal-link {
  background: none;
  border: 0;
  padding: 0.25rem 0;
  color: var(--stone);
  font-size: 0.8rem;
  letter-spacing: 0.04em;
  text-decoration: underline;
  text-decoration-color: rgba(170, 166, 157, 0.35);
  text-underline-offset: 4px;
  transition: color 0.3s ease, text-decoration-color 0.3s ease;
}
.portal-link:hover { color: var(--champagne); text-decoration-color: var(--champagne); }

.portal-message {
  min-height: 0;
  font-size: 0.88rem;
  line-height: 1.55;
  color: var(--stone);
}
.portal-message:empty { display: none; }
.portal-message:not(:empty) { margin-bottom: 1.25rem; }
.portal-message.is-error { color: #D98C74; }
.portal-message.is-success { color: var(--champagne); }
.portal-message--notice {
  padding: 0.9rem 1rem;
  border: 1px solid rgba(198, 174, 130, 0.35);
  border-radius: 4px;
  background: rgba(198, 174, 130, 0.06);
  color: var(--ivory);
}

/* Loading */
.portal-loading { text-align: center; padding-block: 3rem; }
.portal-loading__text {
  display: inline-flex;
  align-items: center;
  gap: 0.75rem;
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--stone);
}
.portal-loading__slow {
  margin-top: 1rem;
  font-size: 0.85rem;
  color: var(--stone);
  opacity: 0;
  animation: portal-fade-in 0.6s ease 8s forwards;
}
@keyframes portal-fade-in { to { opacity: 1; } }

/* Dashboard */
.portal-dash {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 90rem;
  margin-inline: auto;
  padding-inline: var(--gutter);
}
.portal-dash__head { margin-bottom: clamp(1.25rem, 2.6vw, 2rem); }
.portal-title--dash { margin-top: 0.9rem; font-size: clamp(1.9rem, 4.4vw, 3.25rem); }
/* A section link or a focused control never lands under the sticky tab bar */
html:has(#dash-tabs:not([hidden])) { scroll-padding-top: 4.5rem; }
.portal-dash__name { overflow-wrap: anywhere; }

/* Cards flow in rows: full-width cards take a row each; the others share a
   row and grow to fill it (two cards split it in half, three in thirds), so a
   row never ends in an empty column. */
.portal-grid {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(1rem, 2vw, 1.5rem);
  align-items: stretch;
  counter-reset: portal-tile;
}
.portal-tile { min-width: 0; flex: 1 1 min(100%, 22rem); }
.portal-tile--wide { flex-basis: 100%; }

/* Dashboard tab bar (js/portal.js). Hidden while Overview is the only tab.
   One row that scrolls sideways when it does not fit (no scrollbar; snaps to
   a tab; a fade on the edge that has more), sticky at the top of the screen
   while the dashboard is scrolled. .portal-tabbar is the sticky layer: it
   takes the obsidian ground once stuck (data-stuck, js/portal.js), so the
   faded edges of the row still sit on obsidian. Empty (zero height) while
   the bar is hidden. */
.portal-tabbar {
  position: sticky;
  top: -1px;               /* 1px out of view once stuck: how js/portal.js sees it */
  z-index: 5;
}
.portal-tabbar[data-stuck] { background: var(--obsidian); }
.portal-tabs {
  --fade: 2.5rem;
  display: flex;
  flex-wrap: nowrap;
  gap: 1.75rem;
  margin-bottom: clamp(1rem, 2vw, 1.5rem);
  overflow-x: auto;
  overflow-y: hidden;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  scroll-padding-inline: var(--fade);
  scrollbar-width: none;
  box-shadow: inset 0 -1px 0 var(--line-strong);   /* the rule: under the tabs' own underline */
}
.portal-tabs::-webkit-scrollbar { display: none; }
/* The fade: the tabs dim out on an edge with more to scroll to; the rule
   (the bottom 1px) stays whole. */
.portal-tabs[data-fade] {
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-size: 100% 1px, 100% 100%;
  mask-size: 100% 1px, 100% 100%;
  -webkit-mask-position: 0 100%, 0 0;
  mask-position: 0 100%, 0 0;
}
.portal-tabs[data-fade="start"] {
  -webkit-mask-image: linear-gradient(#000, #000), linear-gradient(to right, transparent, #000 var(--fade));
  mask-image: linear-gradient(#000, #000), linear-gradient(to right, transparent, #000 var(--fade));
}
.portal-tabs[data-fade="end"] {
  -webkit-mask-image: linear-gradient(#000, #000), linear-gradient(to left, transparent, #000 var(--fade));
  mask-image: linear-gradient(#000, #000), linear-gradient(to left, transparent, #000 var(--fade));
}
.portal-tabs[data-fade="both"] {
  -webkit-mask-image: linear-gradient(#000, #000), linear-gradient(to right, transparent, #000 var(--fade), #000 calc(100% - var(--fade)), transparent);
  mask-image: linear-gradient(#000, #000), linear-gradient(to right, transparent, #000 var(--fade), #000 calc(100% - var(--fade)), transparent);
}
.portal-tabs__tab {
  position: relative;
  flex: none;
  scroll-snap-align: start;
  white-space: nowrap;
  padding: 0.85rem 0.1rem;
  border: 0;
  border-bottom: 1px solid transparent;
  background: none;
  color: var(--stone);
  font: inherit;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  cursor: pointer;
  transition: color 0.3s var(--ease-out), border-color 0.3s var(--ease-out);
}
.portal-tabs__tab:hover { color: var(--ivory); }
.portal-tabs__tab[aria-selected="true"] { color: var(--ivory); border-bottom-color: var(--champagne); }
.portal-tabs__tab:focus-visible { outline: 1px solid var(--champagne); outline-offset: -1px; }   /* inside: the row clips */
.portal-tabpanel:focus { outline: none; }
.portal-tabpanel:focus-visible { outline: 1px solid var(--line-strong); outline-offset: 0.5rem; }

/* Dashboard filter row: ONE date range for every metric section below. A
   quiet toolbar: a small stone label and the 7 / 30 / 90 switch; what it
   applies to is said to screen readers (the hint, visually hidden). */
.portal-filterbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 1rem;
  margin-bottom: clamp(0.85rem, 1.6vw, 1.15rem);
}
.portal-filterbar__label {
  font-size: 0.64rem;
  font-weight: 600;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--stone);
}
.portal-filterbar__hint { font-size: 0.8rem; color: var(--stone); }
.portal-tile__num {
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.25em;
  color: var(--champagne);
}
.portal-tile__num::before {
  counter-increment: portal-tile;
  content: counter(portal-tile, decimal-leading-zero);
}
/* A tab with a single card has nothing to count: no "01" there (the Overview
   keeps its numbers). A card is alone when no card shows after it and none
   before it; the second rule puts the number back on a last card that has a
   shown card before it. */
.portal-tabpanel:not([data-tab-panel="overview"]) .portal-card:not([hidden]):not(:has(~ .portal-card:not([hidden]))) .portal-tile__num { display: none; }
.portal-tabpanel:not([data-tab-panel="overview"]) .portal-card:not([hidden]) ~ .portal-card .portal-tile__num { display: block; }
.portal-tile__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5rem 1rem;
}
.portal-tile__title {
  margin-top: 1rem;
  font-size: clamp(1.45rem, 2.4vw, 1.9rem);
  font-weight: 600;
  letter-spacing: -0.01em;
}
.portal-tile__title .serif { font-size: 1.15em; }
.portal-tile__count {
  font-size: 0.7rem;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--stone);
}
.portal-tile__text { margin-top: 0.9rem; color: var(--stone); font-size: 0.95rem; max-width: 46ch; }
.portal-tile .portal-actions { margin-top: 1.5rem; }

.portal-links { margin-top: 1.25rem; border-top: 1px solid var(--line); }
.portal-links a {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.85rem 0.1rem;
  border-bottom: 1px solid var(--line);
  font-size: 0.8rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ivory);
  transition: color 0.3s ease, padding-inline 0.4s var(--ease-out);
}
.portal-links a .arrow { color: var(--champagne); transition: transform 0.4s var(--ease-out); }
.portal-links a:hover { color: var(--champagne); padding-inline: 0.5rem; }
.portal-links a:hover .arrow { transform: translate(2px, -2px); }

.portal-meta { margin-top: 1.25rem; }
.portal-meta dt {
  font-size: 0.68rem;
  font-weight: 500;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--stone);
}
.portal-meta dd { margin-top: 0.35rem; font-size: 1rem; }

/* Accounts table (admin) */
.portal-accounts__state { margin-top: 1.5rem; color: var(--stone); font-size: 0.9rem; }
.portal-accounts__state--error .portal-message { margin-bottom: 1rem; }
.portal-accounts__note { margin-top: 1.5rem; }
.portal-table-wrap { margin-top: 1.5rem; overflow-x: auto; }
.portal-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.9rem;
}
.portal-table th {
  padding: 0 1rem 0.8rem 0;
  border-bottom: 1px solid var(--line-strong);
  font-size: 0.66rem;
  font-weight: 500;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  text-align: left;
  color: var(--stone);
  white-space: nowrap;
}
.portal-table td {
  padding: 0.9rem 1rem 0.9rem 0;
  border-bottom: 1px solid var(--line);
  vertical-align: middle;
  color: var(--ivory);
}
.portal-table td:last-child, .portal-table th:last-child { padding-right: 0; white-space: nowrap; color: var(--stone); }
.portal-table__email { overflow-wrap: anywhere; }
.portal-role {
  display: inline-block;
  padding: 0.2rem 0.7rem;
  border: 1px solid rgba(198, 174, 130, 0.45);
  border-radius: 999px;
  font-size: 0.64rem;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--champagne);
  white-space: nowrap;
}
.portal-role--pending { border-color: var(--line-strong); color: var(--stone); }
.portal-role--unknown { border-style: dashed; border-color: var(--line-strong); color: var(--stone); }

@media (max-width: 640px) {
  .portal-table thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  .portal-table, .portal-table tbody, .portal-table tr, .portal-table td { display: block; width: 100%; }
  .portal-table tr { padding-block: 0.75rem; border-bottom: 1px solid var(--line); }
  .portal-table td,
  .portal-table td:last-child {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 1rem;
    padding: 0.3rem 0;
    border-bottom: 0;
    text-align: right;
    white-space: normal;
  }
  .portal-table td::before {
    content: attr(data-label);
    flex: none;
    font-size: 0.64rem;
    font-weight: 500;
    letter-spacing: 0.22em;
    text-transform: uppercase;
    color: var(--stone);
    text-align: left;
  }
  .portal-table td > * { min-width: 0; }
  .portal-table td[data-empty] { display: none; }   /* an empty value ("—") is left out, label and all */
}

/* Phones: the list pattern (.portal-table--list). Each row reads as one entry,
   not a dumped table. The renderer marks the cells (the DOM order and the th/td
   semantics stay as they are; only the visual order changes):
     .portal-table__lead   the heading line (a name, a date)
     .portal-table__tag    sits beside the heading, no label (a role chip)
     .portal-table__sub    one quiet line under the heading, no label (an email)
     .portal-table__bare   a self-describing value in the run, no label (status chips)
     [data-empty]          left out on phones (rule above)
   Every other cell joins a wrapping run of small "LABEL value" pairs, and the
   actions keep their own line on the right. */
@media (max-width: 640px) {
  .portal-table--list tr {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.4rem 1.25rem;
    padding-block: 0.95rem;
  }
  .portal-table--list td,
  .portal-table--list td:last-child {
    display: inline-flex;
    justify-content: flex-start;
    align-items: baseline;
    gap: 0.2rem 0.45rem;   /* a long value wraps beside its label */
    width: auto;
    max-width: 100%;
    min-width: 0;
    padding: 0;
    text-align: left;
    font-variant-numeric: tabular-nums;
  }
  .portal-table--list td::before { font-size: 0.6rem; letter-spacing: 0.2em; }
  .portal-table--list td.portal-table__lead {
    order: -3;
    display: block;
    flex: 1 1 100%;
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--ivory);
    overflow-wrap: anywhere;
  }
  /* a tag shares the heading line: the heading gives up its full width */
  .portal-table--list td.portal-table__lead:has(~ .portal-table__tag) { flex: 0 1 auto; }
  .portal-table--list td.portal-table__tag { order: -2; align-self: center; margin-left: -0.5rem; }
  .portal-table--list td.portal-table__sub {
    order: -1;
    display: block;
    flex: 1 1 100%;
    margin-top: -0.2rem;
    font-size: 0.8rem;
    color: var(--stone);
    overflow-wrap: anywhere;
  }
  .portal-table--list td.portal-table__lead::before,
  .portal-table--list td.portal-table__tag::before,
  .portal-table--list td.portal-table__sub::before,
  .portal-table--list td.portal-table__bare::before,
  .portal-table--list td.portal-table__actions::before { content: none; }
  .portal-table--list td.portal-table__actions {
    order: 1;
    flex: 1 1 100%;
    justify-content: flex-end;
    margin-top: 0.2rem;
  }
}

/* ---- Social metrics: performance view, charts, data entry, clients ----
   Platform series colours, validated for the charcoal card surface (#1B1B1B)
   with the dataviz palette validator (dark mode: OKLCH L band, chroma floor,
   CVD separation, normal-vision floor, >= 3:1 contrast — all pass).
   Colour follows the platform everywhere (lines, dots, keys, legend).
   The website (Visits line + "Where visitors come from" bars, one colour
   for every bar) is always a single series on a card of its own, so it
   takes no hue at all: a light stone (10.4:1 on #1B1B1B), one hue fewer
   on the page than the dusty rose it replaces.
   Facebook, validated with TikTok and Instagram (the platforms it is drawn
   beside) as one palette on #1B1B1B, all pairs: jade — oklch(0.545 0.10 170),
   inside the dark-mode lightness band (0.48-0.67); 3.7:1; normal-vision
   ΔE >= 16.5, colour-blind ΔE >= 9.5 (protan, deutan), 8.8 (tritan). */
.portal-body {
  --portal-series-tiktok: #5590CC;      /* cool blue — oklch(0.64 0.11 250) */
  --portal-series-instagram: #B48B40;   /* deep champagne — oklch(0.66 0.105 80) */
  --portal-series-facebook: #1B8367;    /* jade — oklch(0.545 0.10 170) */
  --portal-series-website: #CFC9BC;     /* light stone — oklch(0.83 0.017 85) */
  --portal-chart-grid: #2C2C2A;
  --portal-chart-axis: #45443F;
  --portal-chart-ink: var(--ivory);
  --portal-chart-muted: var(--stone);
}

.portal-perf { margin-top: 1.75rem; container: perf / inline-size; }
.portal-perf.is-refreshing .portal-perf__body { opacity: 0.55; transition: opacity 0.2s ease; }

.portal-perf__meta { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.25rem 1.25rem; margin-bottom: 1.25rem; }
.portal-perf__updated {
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--champagne);
}
.portal-perf__through { font-size: 0.82rem; color: var(--stone); }

.portal-seg {
  display: inline-flex;
  padding: 3px;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
}
.portal-seg__btn {
  min-height: 2.25rem;
  padding: 0.35rem 1rem;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: var(--stone);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  white-space: nowrap;
  transition: color 0.2s ease, background-color 0.2s ease;
}
.portal-seg__btn:hover { color: var(--ivory); }
.portal-seg__btn[aria-pressed="true"] { background: var(--ivory); color: var(--obsidian); }
.portal-perf__span { font-size: 0.9rem; color: var(--ivory); font-variant-numeric: tabular-nums; }

/* One row of tiles per platform (never combined). Phones: name on top, two
   tiles per line (the fifth spans the line). Medium: 3 + 2. Wide: five in a
   row, and from ~64rem the platform name sits at the start of its row. */
.portal-perf__platforms { display: grid; gap: 1rem; margin-top: 1rem; }
.portal-perf__platform {
  min-width: 0;
  border: 1px solid var(--line);
  border-radius: 6px;
  overflow: hidden;   /* clips the outer half of each tile's hairline */
}
.portal-perf__platform-name {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.75rem 1.25rem;
  border-bottom: 1px solid var(--line);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ivory);
}
.portal-perf__stats { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
.portal-perf__stats > .portal-stat:last-child:nth-child(odd) { grid-column: 1 / -1; }
@container perf (min-width: 34rem) {
  .portal-perf__stats { grid-template-columns: repeat(6, minmax(0, 1fr)); }
  .portal-perf__stats > .portal-stat,
  .portal-perf__stats > .portal-stat:last-child:nth-child(odd) { grid-column: span 2; }
  .portal-perf__stats > .portal-stat:nth-child(n+4) { grid-column: span 3; }
}
@container perf (min-width: 56rem) {
  .portal-perf__stats { grid-template-columns: repeat(5, minmax(0, 1fr)); }
  .portal-perf__stats > .portal-stat,
  .portal-perf__stats > .portal-stat:nth-child(n+4),
  .portal-perf__stats > .portal-stat:last-child:nth-child(odd) { grid-column: auto; }
}
@container perf (min-width: 68rem) {
  .portal-perf__platform { display: grid; grid-template-columns: 9rem minmax(0, 1fr); }
  .portal-perf__platform-name { align-items: flex-start; padding-top: 1.2rem; border-bottom: 0; border-right: 1px solid var(--line); }
  .portal-perf__platform-name .portal-chart__key { margin-top: 0.4em; }
}
.portal-perf__compare { margin-top: 0.75rem; font-size: 0.78rem; line-height: 1.5; color: var(--stone); }
.portal-stat {
  min-width: 0;
  margin: -1px 0 0 -1px;
  padding: 1.1rem 1.25rem 1.2rem;
  border-top: 1px solid var(--line);
  border-left: 1px solid var(--line);
}
.portal-stat__label {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  line-height: 1.4;
  font-size: 0.68rem;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--stone);
}
.portal-stat__value {
  margin-top: 0.4rem;
  font-size: clamp(1.75rem, 3vw, 2.25rem);
  font-weight: 600;
  line-height: 1.1;
  letter-spacing: -0.01em;
  color: var(--ivory);
}
.portal-stat__delta { margin-top: 0.35rem; font-size: 0.82rem; line-height: 1.45; color: var(--stone); }
.portal-stat__delta[data-direction="up"] .portal-stat__arrow,
.portal-stat__delta[data-direction="down"] .portal-stat__arrow { color: var(--ivory); }
.portal-stat__arrow { font-size: 0.72em; }
.portal-stat__note { margin-top: 0.2rem; font-size: 0.75rem; color: var(--stone); opacity: 0.85; }

.portal-perf__charts-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem 1.5rem;
  margin-top: 1.75rem;
}
.portal-perf__charts-head .portal-legend[hidden] + .portal-perf__toggle { margin-left: auto; }
.portal-legend { display: flex; flex-wrap: wrap; gap: 0.4rem 1.25rem; }
.portal-legend__item { display: inline-flex; align-items: center; gap: 0.5rem; font-size: 0.82rem; color: var(--ivory); }
.portal-perf__toggle { font-size: 0.78rem; }

.portal-perf__charts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 26rem), 1fr));
  gap: 1.25rem 2rem;
  margin-top: 1rem;
}
.portal-perf__chart { min-width: 0; }
.portal-perf__chart-title {
  margin-bottom: 0.5rem;
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ivory);
}
.portal-perf__table { margin-top: 0.5rem; }
.portal-perf__empty {
  padding: 2.5rem 1.5rem;
  border: 1px dashed var(--line-strong);
  border-radius: 6px;
  text-align: center;
}
.portal-perf__empty-text { color: var(--stone); font-size: 0.95rem; }
.portal-perf__error .portal-message { margin-bottom: 1rem; }

/* Loading skeleton (holds the layout; shimmer only without reduced motion) */
.portal-skeleton { border-radius: 6px; background: rgba(242, 239, 231, 0.05); }
.portal-skeleton--row { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 8rem), 1fr)); gap: 1px; margin-top: 1rem; background: none; }
.portal-skeleton--row span { height: 6.5rem; border-radius: 4px; background: rgba(242, 239, 231, 0.05); }
.portal-skeleton--chart { height: 12rem; margin-top: 1.25rem; }
@media (prefers-reduced-motion: no-preference) {
  /* shimmer: a champagne sheen sweeping across, like the site's hero light sweep */
  .portal-skeleton--chart, .portal-skeleton--row span {
    background-image: linear-gradient(100deg, rgba(198, 174, 130, 0) 20%, rgba(198, 174, 130, 0.07) 50%, rgba(198, 174, 130, 0) 80%);
    background-size: 200% 100%;
    background-repeat: no-repeat;
    animation: portal-shimmer 1.6s linear infinite;
  }
}
@keyframes portal-shimmer { from { background-position: 150% 0; } to { background-position: -50% 0; } }
@keyframes portal-pulse { 50% { opacity: 0.45; } }

/* Chart (js/portal-chart.js) */
.portal-chart { position: relative; min-width: 0; }
.portal-chart__plot {
  position: relative;
  overflow: hidden;
  border-radius: 4px;
  touch-action: pan-y;
  cursor: crosshair;
}
.portal-chart__plot:focus-visible { outline: 1px solid var(--champagne); outline-offset: 4px; }
.portal-chart__svg { display: block; max-width: 100%; height: auto; overflow: visible; }
.portal-chart__gridline { stroke: var(--portal-chart-grid); stroke-width: 1; shape-rendering: crispEdges; }
.portal-chart__baseline { stroke: var(--portal-chart-axis); stroke-width: 1; shape-rendering: crispEdges; }
.portal-chart__tick {
  fill: var(--portal-chart-muted);
  font-family: var(--font-sans);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
}
.portal-chart__line {
  fill: none;
  stroke-width: 2;
  stroke-linejoin: round;
  stroke-linecap: round;
}
.portal-chart__line--tiktok { stroke: var(--portal-series-tiktok); }
.portal-chart__line--instagram { stroke: var(--portal-series-instagram); }
.portal-chart__line--facebook { stroke: var(--portal-series-facebook); }
.portal-chart__line--website { stroke: var(--portal-series-website); }
.portal-chart__line--other { stroke: var(--stone); }
.portal-chart__dot { stroke: var(--charcoal); stroke-width: 2; }
.portal-chart__dot--tiktok { fill: var(--portal-series-tiktok); }
.portal-chart__dot--instagram { fill: var(--portal-series-instagram); }
.portal-chart__dot--facebook { fill: var(--portal-series-facebook); }
.portal-chart__dot--website { fill: var(--portal-series-website); }
.portal-chart__dot--other { fill: var(--stone); }
.portal-chart__direct { fill: var(--portal-chart-ink); font-family: var(--font-sans); font-size: 12px; font-weight: 500; }
.portal-chart__leader { stroke: var(--portal-chart-axis); stroke-width: 1; }
.portal-chart__crossline { stroke: var(--stone); stroke-width: 1; opacity: 0.6; shape-rendering: crispEdges; }
.portal-chart__hit { cursor: crosshair; }

.portal-chart__key {
  display: inline-block;
  flex: none;
  width: 14px;
  height: 2px;
  border-radius: 1px;
  background: var(--stone);
}
.portal-chart__key--tiktok { background: var(--portal-series-tiktok); }
.portal-chart__key--instagram { background: var(--portal-series-instagram); }
.portal-chart__key--facebook { background: var(--portal-series-facebook); }
.portal-chart__key--website { background: var(--portal-series-website); }

.portal-chart__tip {
  position: absolute;
  z-index: 2;
  top: 0;
  left: 0;
  min-width: 9.5rem;
  max-width: 14rem;
  padding: 0.6rem 0.75rem;
  border: 1px solid var(--line-strong);
  border-radius: 4px;
  background: rgba(10, 10, 10, 0.94);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45);
  pointer-events: none;
}
.portal-chart__tip-date { font-size: 0.72rem; color: var(--stone); margin-bottom: 0.3rem; white-space: nowrap; }
.portal-chart__tip-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.8rem;
  line-height: 1.6;
  white-space: nowrap;
}
.portal-chart__tip-value { color: var(--ivory); font-weight: 600; font-variant-numeric: tabular-nums; }
.portal-chart__tip-label { color: var(--stone); }

.portal-table__num { text-align: right; font-variant-numeric: tabular-nums; }
.portal-table th.portal-table__num { text-align: right; }
@media (min-width: 641px) {
  .portal-table--compact td { padding-block: 0.6rem; }
  .portal-table--compact th, .portal-table--compact td { padding-right: 1.1rem; }
  .portal-table--compact td:last-child, .portal-table--compact th:last-child { padding-right: 0; }
}

/* Staff: Client metrics */
.portal-metrics { margin-top: 1.75rem; }
.portal-metrics__pick {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.75rem 2rem;
}
/* the two halves, one tap apart (js/portal-metrics.js); only with the update tools */
.portal-metrics__jump { margin-left: auto; align-self: center; }
.portal-metrics:has(#metrics-entry[hidden]) .portal-metrics__jump { display: none; }
#metrics-see, #metrics-entry { scroll-margin-top: 1rem; }
@media (max-width: 560px) {
  .portal-metrics__jump { margin-left: 0; width: 100%; }
  .portal-metrics__jump .portal-seg__btn { flex: 1 1 0; min-width: 0; padding-inline: 0.5rem; }
}
.portal-metrics select,
.portal-client-add input,
.portal-client__field input {
  width: 100%;
}
.portal-metrics__business { flex: 0 1 22rem; min-width: 0; margin-bottom: 0; }
.portal-metrics__handles { display: flex; flex-wrap: wrap; gap: 0.5rem 1.5rem; padding-bottom: 0.8rem; font-size: 0.9rem; }
.portal-metrics__handle { display: inline-flex; align-items: center; gap: 0.5rem; min-width: 0; }
.portal-metrics__platform { color: var(--stone); }
.portal-metrics__at { color: var(--ivory); overflow-wrap: anywhere; }
.portal-metrics__handle--none { color: var(--stone); }
.portal-metrics__preview {
  margin-top: 1.75rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--line);
}
.portal-metrics__eyebrow {
  font-size: 0.66rem;
  font-weight: 500;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--stone);
}
.portal-metrics__preview .portal-perf { margin-top: 1rem; }
.portal-metrics__entry { margin-top: 2.25rem; padding-top: 1.75rem; border-top: 1px solid var(--line); }
.portal-metrics__entry-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 0.75rem 2rem;
}
.portal-metrics__title { font-size: clamp(1.2rem, 2vw, 1.45rem); font-weight: 600; }
.portal-metrics__account { flex: 0 1 22rem; min-width: 0; margin-bottom: 0; }
.portal-metrics__forms {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 24rem), 1fr));
  gap: 1.5rem 0;
  margin-top: 1.5rem;
  align-items: start;
  container: metrics-forms / inline-size;
}
/* no boxes in the box: a hairline between the two panels (above the second
   when they stack, to its left when they sit side by side) */
.portal-metrics__panel { min-width: 0; }
.portal-metrics__panel + .portal-metrics__panel { padding-top: 1.5rem; border-top: 1px solid var(--line); }
@container metrics-forms (min-width: 48rem) {
  .portal-metrics__panel:first-child { padding-right: 2.5rem; }
  .portal-metrics__panel + .portal-metrics__panel { padding-top: 0; padding-left: 2.5rem; border-top: 0; border-left: 1px solid var(--line); }
}
.portal-metrics__hint { margin-bottom: 1rem; max-width: 52ch; line-height: 1.55; }
.portal-body input[type="date"] { color-scheme: dark; }
.portal-metrics__file input[type="file"] {
  width: 100%;
  padding: 0.6rem 0;
  border: 0;
  color: var(--stone);
  font-size: 0.85rem;
}
.portal-metrics__file input[type="file"]::file-selector-button {
  margin-right: 0.9rem;
  padding: 0.5rem 1rem;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  background: transparent;
  color: var(--ivory);
  font: inherit;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  cursor: pointer;
}
.portal-metrics__panel .portal-message:not(:empty) { margin-top: 1rem; margin-bottom: 0; }
.portal-metrics__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 7rem), 1fr));
  gap: 0 1rem;
}
.portal-metrics__grid .field { min-width: 0; }
.portal-metrics__date { grid-column: 1 / -1; max-width: 14rem; }
.portal-metrics__grid .field:last-child { grid-column: 1 / -1; }
.portal-metrics__editing { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.25rem 0.75rem; }
.portal-metrics__csv {
  margin-top: 1.5rem;
  padding: 1.25rem;
  border: 1px solid rgba(198, 174, 130, 0.35);
  border-radius: 6px;
  background: rgba(198, 174, 130, 0.03);
}
.portal-metrics__csv-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 0.5rem 1.5rem; }
.portal-metrics__csv-head .portal-form__legend { margin-bottom: 0.5rem; }
.portal-metrics__file-name { color: var(--stone); letter-spacing: 0.08em; text-transform: none; font-weight: 500; overflow-wrap: anywhere; }
.portal-metrics__counts { display: flex; flex-wrap: wrap; gap: 0.25rem 1.25rem; font-size: 0.85rem; color: var(--stone); }
.portal-metrics__counts strong { color: var(--ivory); font-weight: 600; }
.portal-metrics__mapping {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 7rem), 1fr));
  gap: 0 1rem;
  margin-top: 0.75rem;
}
.portal-metrics__map { min-width: 0; margin-bottom: 1rem; }
.portal-metrics__mapping { align-items: end; }   /* a wrapped label never pushes its select down */
.portal-metrics__csv .portal-table td:last-child { color: var(--ivory); }   /* data, not an actions column */
.portal-metrics__notes { margin-top: 0.25rem; font-size: 0.85rem; line-height: 1.55; color: var(--stone); }
.portal-metrics__notes li { position: relative; padding-left: 1rem; margin-top: 0.3rem; overflow-wrap: anywhere; }
.portal-metrics__notes li::before { content: "·"; position: absolute; left: 0.2rem; color: var(--champagne); }
.portal-metrics__notes li.is-error { color: #D98C74; }
.portal-metrics__csv-actions { margin-top: 1.25rem; }
.portal-metrics__recent { margin-top: 2rem; }
.portal-metrics__recent .portal-form__legend { margin-bottom: 0; }
.portal-table__actions { white-space: nowrap; text-align: right; }
.portal-link--action { margin-left: 0.9rem; font-size: 0.78rem; }
.portal-link--action:first-child { margin-left: 0; }
.portal-link--danger:hover { color: #D98C74; text-decoration-color: #D98C74; }
.portal-link:disabled { opacity: 0.5; cursor: progress; }

/* Accounts: each employee's access (read-only) */
.portal-table td.portal-table__access { color: var(--stone); font-size: 0.85rem; }

/* Team permissions (engineers) */
.portal-team__note { margin-top: 0.75rem; max-width: 62ch; line-height: 1.55; }
.portal-team__message:not(:empty) { margin-top: 1.25rem; margin-bottom: 0; }
.portal-team { margin-top: 1.25rem; border-top: 1px solid var(--line); container: team / inline-size; }
/* "What each permission allows": reference text, closed until asked for
   (generated from js/portal-permissions.js; hairlines like the site's FAQ) */
.portal-team__help { margin-top: 1.5rem; border-top: 1px solid var(--line); }
.portal-team__help + .portal-team__message:not(:empty) { margin-top: 1rem; }
.portal-team__help-toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.85rem 0.1rem;
  list-style: none;
  font-size: 0.66rem;
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--stone);
  cursor: pointer;
  transition: color 0.3s ease;
}
.portal-team__help-toggle::-webkit-details-marker { display: none; }
.portal-team__help-toggle::after {
  content: "+";
  flex: none;
  color: var(--champagne);
  font-size: 1.1rem;
  font-weight: 400;
  letter-spacing: 0;
  line-height: 1;
  transition: transform 0.35s var(--ease-out);
}
.portal-team__help[open] > .portal-team__help-toggle::after { transform: rotate(45deg); }
.portal-team__help-toggle:hover { color: var(--ivory); }
.portal-team__help-toggle:focus-visible { outline: 1px solid var(--champagne); outline-offset: 2px; }
.portal-team__legend {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 14rem), 1fr));
  gap: 0.9rem 2rem;
  padding: 0.25rem 0.1rem 1.25rem;
  font-size: 0.8rem;
  line-height: 1.5;
}
.portal-team__legend dt { color: var(--ivory); font-weight: 600; }
.portal-team__legend dd { margin: 0.1rem 0 0; color: var(--stone); }

/* One row per employee: who they are (name, email, team lead), then their
   permissions as one row of equal chips that line up from person to person.
   Phones first: identity above two columns of chips. */
.portal-team__person {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  align-items: start;
  gap: 0.9rem 2rem;
  padding-block: 1.25rem;
  border-bottom: 1px solid var(--line);
}
.portal-team__who { min-width: 0; }
.portal-team__name { color: var(--ivory); font-weight: 600; overflow-wrap: anywhere; }
.portal-team__email { margin-top: 0.15rem; color: var(--stone); font-size: 0.85rem; overflow-wrap: anywhere; }
.portal-team__perms {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  align-items: start;
  gap: 0.5rem;
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}
.portal-team__perm { display: flex; flex-direction: column; min-width: 0; }
/* a permission chip: the whole box is the hit area */
.portal-team__perm .portal-check {
  display: flex;
  width: 100%;
  min-height: 2.6rem;
  padding: 0.45rem 0.75rem;
  gap: 0.6rem;
  border: 1px solid var(--line-strong);
  border-radius: 6px;
  font-size: 0.84rem;
  line-height: 1.3;
  transition: border-color 0.25s ease, background-color 0.25s ease;
}
.portal-team__perm .portal-check:hover { border-color: rgba(242, 239, 231, 0.28); }
.portal-team__perm .portal-check:has(.portal-check__box:checked) {
  border-color: rgba(198, 174, 130, 0.5);
  background: rgba(198, 174, 130, 0.07);
}
.portal-team__perm .portal-check.is-implied {
  border-style: dashed;
  border-color: var(--line-strong);
  background: transparent;
}
.portal-team__perm .portal-check:has(.portal-check__box:focus-visible) { border-color: var(--champagne); }
.portal-team__perm .portal-check__label { min-width: 0; overflow-wrap: anywhere; }
.portal-team__hint { margin-top: 0.35rem; padding-left: 0.1rem; line-height: 1.4; }
.portal-check {
  display: inline-flex;
  align-items: center;
  gap: 0.65rem;
  min-height: 2.25rem;           /* >= 24px hit area */
  color: var(--ivory);
  font-size: 0.9rem;
  cursor: pointer;
}
.portal-check__box {
  flex: none;
  width: 1.1rem;
  height: 1.1rem;
  accent-color: var(--champagne);
  color-scheme: dark;            /* dark unchecked boxes on the charcoal card */
  cursor: pointer;
}
.portal-check__box:focus-visible { outline: 2px solid var(--champagne); outline-offset: 3px; }
.portal-check.is-implied { color: var(--stone); cursor: default; }
.portal-check.is-implied .portal-check__box { cursor: default; opacity: 0.75; }
.portal-team__person[aria-busy="true"] .portal-check { cursor: progress; }
/* the team lead an employee reports to (js/portal-team.js) */
.portal-team__admin { display: flex; align-items: center; gap: 0.75rem; margin-top: 0.6rem; min-width: 0; }
.portal-team__admin-label {
  flex: none;
  font-size: 0.62rem;
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--stone);
}
.portal-team__admin-select {
  flex: 0 1 auto;
  min-width: 0;
  max-width: 100%;
  padding: 0.35rem 1.6rem 0.35rem 0.1rem;
  border: 0;
  border-bottom: 1px solid var(--line-strong);
  border-radius: 0;
  background: transparent url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' fill='none' stroke='%23AAA69D' stroke-width='1.5'/%3E%3C/svg%3E") no-repeat right 0.25rem center / 0.65rem;
  color: var(--ivory);
  font: inherit;
  font-size: 0.88rem;
  text-overflow: ellipsis;
  cursor: pointer;
  appearance: none;
  -webkit-appearance: none;
}
.portal-team__admin-select:focus { outline: none; border-bottom-color: var(--champagne); }
.portal-team__admin-select:focus-visible { outline: 1px solid var(--champagne); outline-offset: 3px; }
.portal-team__admin-select:disabled { cursor: default; opacity: 0.55; }
.portal-team__admin-select option { background: var(--charcoal); color: var(--ivory); }
.portal-team__person[aria-busy="true"] .portal-team__admin-select { cursor: progress; }
/* tablets: still stacked, the team lead beside the name; chips 3 + 2, then all five */
@container team (min-width: 40rem) {
  .portal-team__who { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; column-gap: 2rem; }
  .portal-team__who > :not(.portal-team__admin) { grid-column: 1; }
  .portal-team__who > .portal-team__admin { grid-column: 2; grid-row: 1 / span 2; margin-top: 0; }
  .portal-team__perms { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@container team (min-width: 56rem) {
  .portal-team__perms { grid-template-columns: repeat(5, minmax(0, 1fr)); }
}
/* desktops: identity on the left, the five chips on the right */
@container team (min-width: 70rem) {
  .portal-team__person { grid-template-columns: minmax(0, 15rem) minmax(0, 1fr); }
  .portal-team__who { display: block; }
  .portal-team__who > .portal-team__admin { margin-top: 0.6rem; }
}
@media (prefers-reduced-motion: reduce) {
  .portal-team__help-toggle, .portal-team__help-toggle::after, .portal-team__perm .portal-check { transition: none; }
}

/* Clients (clients.manage) */
.portal-client-add {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0 1.25rem;
  margin-top: 1.5rem;
}
.portal-client-add .field { flex: 0 1 26rem; min-width: 0; margin-bottom: 1rem; }
.portal-client-add .btn { margin-bottom: 1rem; }
/* --client-btn: every Save / Add button is the same width, so the fields
   above and below each other end at the same place */
.portal-clients { --client-btn: 6.5rem; margin-top: 1.25rem; border-top: 1px solid var(--line); container: clients / inline-size; }
.portal-client { padding-block: 1.5rem 1.6rem; border-bottom: 1px solid var(--line); }
.portal-client__head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 0.5rem 1.5rem; }
.portal-client__name { font-size: 1.15rem; font-weight: 600; letter-spacing: 0; overflow-wrap: anywhere; min-width: 0; }
/* the platforms in an even grid: one column on phones, two, then
   TikTok | Instagram | Facebook side by side on a wide card */
.portal-client__accounts {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 1.25rem 2rem;
  margin-top: 1.1rem;
}
@container clients (min-width: 40rem) {
  .portal-client__accounts { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@container clients (min-width: 62rem) {
  .portal-client__accounts { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
/* one platform: its label with Remove at the right, then the handle and its
   Save / Add button (the wrappers step aside so the parts share one grid) */
.portal-client__account {
  display: grid;
  grid-template-columns: minmax(0, 1fr) var(--client-btn);
  align-items: center;
  gap: 0.55rem 1rem;
  min-width: 0;
}
.portal-client__account > .portal-client__field,
.portal-client__account .portal-client__actions { display: contents; }
.portal-client__field label { display: flex; flex-wrap: wrap; align-items: center; gap: 0.25rem 0.5rem; min-width: 0; }
.portal-client__account > .portal-client__field > label { grid-column: 1; grid-row: 1; }
.portal-client__account > .portal-client__field > input { grid-column: 1; grid-row: 2; min-width: 0; }
.portal-client__save {
  grid-column: 2;
  grid-row: 2;
  justify-content: center;
  width: 100%;
  padding: 0.55rem 0.5rem;
}
/* Remove keeps its padded hit area without making its label line taller than its neighbours' */
.portal-client__actions > .portal-link--danger { grid-column: 2; grid-row: 1; justify-self: end; margin-block: -0.4rem; font-size: 0.78rem; line-height: 1.4; }

@media (max-width: 560px) {
  .portal-seg { width: 100%; }
  .portal-seg__btn { flex: 1; padding-inline: 0.5rem; }
  .portal-stat { padding: 0.95rem 1rem 1rem; }
  .portal-metrics__panel, .portal-metrics__csv { padding: 1rem; }
  .portal-metrics__csv-actions .btn { flex: 1 1 auto; justify-content: center; white-space: nowrap; padding-inline: 1.25rem; }
  .portal-table__actions { text-align: right; }
}
/* ---- Website traffic (js/portal-website.js): client card + staff preview ---- */
.portal-web { margin-top: 1.75rem; container: web / inline-size; }
.portal-web.is-refreshing .portal-perf__body { opacity: 0.55; transition: opacity 0.2s ease; }
.portal-web__domain { overflow-wrap: anywhere; }

/* Staff only: sync status + Sync now */
.portal-web__sync {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem 1.5rem;
  margin-bottom: 1.25rem;
  padding: 0.85rem 1rem;
  border: 1px solid var(--line);
  border-radius: 6px;
}
.portal-web__status {
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
  flex: 1 1 18rem;
  min-width: 0;
  font-size: 0.86rem;
  line-height: 1.5;
  color: var(--ivory);
}
.portal-web__status-dot {
  flex: none;
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: var(--stone);
  transform: translateY(-0.05em);
}
.portal-web__status[data-status="ok"] .portal-web__status-dot { background: var(--champagne); }
.portal-web__status[data-status="permission_denied"] .portal-web__status-dot,
.portal-web__status[data-status="not_found"] .portal-web__status-dot,
.portal-web__status[data-status="invalid_credentials"] .portal-web__status-dot,
.portal-web__status[data-status="quota"] .portal-web__status-dot,
.portal-web__status[data-status="error"] .portal-web__status-dot { background: #D98C74; }
.portal-web__status[data-status="manual"], .portal-web__status[data-status="never"] { color: var(--stone); }
.portal-web__sync-btn { flex: none; padding-block: 0.55rem; }
.portal-web__sync .portal-message:not(:empty) { flex-basis: 100%; margin: 0; font-size: 0.86rem; }

/* Three tiles: phones two per line (the third spans), then one row of three */
.portal-web__stats {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  margin-top: 1rem;
  border: 1px solid var(--line);
  border-radius: 6px;
  overflow: hidden;   /* clips the outer half of each tile's hairline */
}
.portal-web__stats > .portal-stat:last-child:nth-child(odd) { grid-column: 1 / -1; }
@container web (min-width: 34rem) {
  .portal-web__stats { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .portal-web__stats > .portal-stat:last-child:nth-child(odd) { grid-column: auto; }
}
.portal-web__charts-head { justify-content: flex-end; }
.portal-web__charts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 26rem), 1fr));
  gap: 1.75rem 2.5rem;
  margin-top: 1rem;
}
.portal-web__sources { min-width: 0; }
.portal-web__sources-note { margin-bottom: 0.85rem; font-size: 0.8rem; color: var(--stone); }
.portal-web__table .portal-table-wrap + .portal-accounts__state + .portal-table-wrap,
.portal-web__table .portal-table-wrap + .portal-table-wrap { margin-top: 2rem; }

/* "Where visitors come from": sorted bars, one colour; labels always visible */
.portal-src { display: grid; gap: 0.2rem; margin: 0; padding: 0; list-style: none; }   /* already sorted: no rank numbers */
.portal-src__row {
  min-width: 0;
  padding: 0.45rem 0.5rem 0.55rem;
  margin-inline: -0.5rem;
  border-radius: 4px;
  transition: background-color 0.2s ease;
}
.portal-src__row:hover { background: rgba(242, 239, 231, 0.04); }
.portal-src__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.1rem 1rem;
  font-size: 0.86rem;
  line-height: 1.4;
}
.portal-src__name { min-width: 0; color: var(--ivory); overflow-wrap: anywhere; }
.portal-src__row--other .portal-src__name { color: var(--stone); }
.portal-src__value { display: inline-flex; align-items: baseline; gap: 0.6rem; margin-left: auto; font-variant-numeric: tabular-nums; white-space: nowrap; }
.portal-src__share { color: var(--ivory); font-weight: 600; }
.portal-src__count { color: var(--stone); font-size: 0.8rem; }
.portal-src__track { display: block; margin-top: 0.4rem; height: 6px; border-radius: 0 3px 3px 0; background: rgba(242, 239, 231, 0.05); }
.portal-src__bar {
  display: block;
  height: 100%;
  min-width: 2px;
  border-radius: 0 3px 3px 0;       /* rounded data end, square at the baseline */
  background: var(--portal-series-website);
  transition: filter 0.2s ease;
}
.portal-src__row:hover .portal-src__bar { filter: brightness(1.15); }

/* Staff preview: social and website sections */
.portal-metrics__section + .portal-metrics__section { margin-top: 2.25rem; padding-top: 1.75rem; border-top: 1px solid var(--line); }
.portal-metrics__section-title {
  margin-top: 1rem;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ivory);
}
.portal-metrics__section .portal-perf, .portal-metrics__section .portal-web { margin-top: 1rem; }
.portal-metrics__templates { display: flex; flex-wrap: wrap; gap: 0.35rem 1.5rem; }
.portal-metrics__grid--web .field:last-child { grid-column: auto; }
.portal-metrics__recent-note { margin-top: 0.75rem; }
.portal-table td.portal-table__source { color: var(--stone); }

/* Clients: the Website row spans the row, on the same columns as the
   platforms above it: website (with Remove) | GA4 property id + Save,
   then the hint, "not synced yet" and the confirm box underneath.
   Phones: website, then the GA4 property id under it. */
.portal-client__accounts > .portal-client__website {
  grid-column: 1 / -1;
  grid-template-columns: minmax(0, 1fr) 1rem var(--client-btn);
  column-gap: 0;
}
.portal-client__ga4-group,
.portal-client__ga4-group > .portal-client__field { display: contents; }
.portal-client__website > .portal-client__field > label { grid-area: 1 / 1; }
.portal-client__website > .portal-client__field > input { grid-area: 2 / 1 / 3 / 4; }
.portal-client__website .portal-client__field--ga4 > label { grid-area: 3 / 1 / 4 / 4; margin-top: 0.7rem; }
.portal-client__website .portal-client__field--ga4 > input { grid-area: 4 / 1; min-width: 0; }
.portal-client__website .portal-client__save { grid-area: 4 / 3; }
.portal-client__website .portal-client__actions > .portal-link--danger { grid-area: 1 / 3; }
@container clients (min-width: 40rem) {
  .portal-client__accounts > .portal-client__website {
    grid-template-columns: minmax(0, 1fr) 1rem var(--client-btn) 2rem minmax(0, 1fr) 1rem var(--client-btn);
  }
  .portal-client__website .portal-client__field--ga4 > label { grid-area: 1 / 5 / 2 / 8; margin-top: 0; }
  .portal-client__website .portal-client__field--ga4 > input { grid-area: 2 / 5; }
  .portal-client__website .portal-client__save { grid-area: 2 / 7; }
}
@container clients (min-width: 62rem) {
  .portal-client__accounts > .portal-client__website {
    grid-template-columns: minmax(0, 1fr) 1rem var(--client-btn) 2rem minmax(0, 1fr) 1rem var(--client-btn) 2rem minmax(0, 1fr) 1rem var(--client-btn);
  }
}
.portal-client__website-hint { grid-column: 1 / -1; margin-top: 0.2rem; max-width: 70ch; }
/* a GA4 property id that has not synced yet (just added or changed) + Sync now */
.portal-client__sync {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.25rem 1.25rem;
  margin: 0;
}
.portal-client__sync-text { font-size: 0.8rem; line-height: 1.5; color: var(--stone); max-width: 70ch; overflow-wrap: anywhere; }
.portal-client__sync-btn { flex: none; }
/* "Change the GA4 property ID?" asked in place, under the fields */
.portal-client__confirm {
  grid-column: 1 / -1;
  margin: 0.35rem 0 0.2rem;
  padding: 0.85rem 1rem 0.9rem;
  border: 1px solid var(--line);
  border-left: 2px solid #D98C74;
  border-radius: 6px;
}
.portal-client__confirm-text { font-size: 0.86rem; line-height: 1.55; color: var(--ivory); max-width: 70ch; overflow-wrap: anywhere; }
.portal-client__confirm-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem 1.25rem; margin-top: 0.75rem; }
.portal-client__confirm-yes { padding-block: 0.55rem; }

/* Phones: the recent-entries list keeps date, views, interactions, followers
   and the actions; the other parts are one tap away via Edit. */
@media (max-width: 640px) {
  .portal-table .portal-table__opt { display: none; }
  .portal-table td.portal-table__actions .portal-link--action:first-of-type { margin-left: auto; }
}

/* Footer */
.portal-footer {
  border-top: 1px solid var(--line);
  color: var(--stone);
  font-size: 0.72rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
.portal-footer__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 1rem;
  padding-block: 1.75rem;
}

/* Small screens: keep the header on one line down to 360px */
@media (max-width: 560px) {
  /* "Back to site" becomes a round arrow button; the words stay for screen readers */
  .portal-header__back-text {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
  }
  .portal-header__back {
    justify-content: center;
    width: 2.35rem;
    height: 2.35rem;
    padding: 0;
    border: 1px solid var(--line-strong);
    border-radius: 50%;
    font-size: 0.85rem;
    transition: color 0.35s ease, border-color 0.35s ease;
  }
  .portal-header__back::after { display: none; }
  .portal-header__back:hover,
  .portal-header__back:focus-visible { border-color: var(--champagne); }
  .portal-header__actions { gap: 0.6rem; }
  .portal-header .portal-logo { font-size: 0.8rem; letter-spacing: 0.3em; gap: 0.5rem; }
  .portal-header .logo__mark { height: 1.6rem; }
  .portal-header .portal-signout { padding: 0.6rem 1.05rem; letter-spacing: 0.14em; }
  .portal-form__foot .btn { width: 100%; justify-content: center; }
  .portal-form__foot { justify-content: center; }
}

@media (max-width: 400px) {
  .portal-header .portal-logo { font-size: 0.72rem; letter-spacing: 0.22em; gap: 0.45rem; }
  .portal-header .logo__mark { height: 1.45rem; }
  .portal-header__actions { gap: 0.45rem; }
  .portal-header__back { width: 2.15rem; height: 2.15rem; }
  .portal-header .portal-signout { padding-inline: 0.85rem; letter-spacing: 0.1em; }
}

/* ------------------------------------------------------------
   Motion & theme parity with the main site (contract v3 §7).
   Motion itself is js/portal-motion.js; the site's .preloader, .flash,
   .cursor-cross / .cursor-trail, .label, .btn and reduced-motion rules come
   from css/style.css. Only the brand tokens are used — no new colours.
   ------------------------------------------------------------ */

/* Preloader failsafe: should no script hand it off, it fades out by itself
   (js/portal-motion.js normally does so at load + 650 ms, 3 s at the latest). */
.portal-body .preloader { animation: portal-preloader-failsafe 0.8s var(--ease-out) 4s forwards; }
@keyframes portal-preloader-failsafe { to { opacity: 0; visibility: hidden; pointer-events: none; } }

/* The loading view (visible only if the auth wait outlasts the preloader):
   the site's label rule, breathing. */
.portal-loading__text::before {
  content: "";
  display: inline-block;
  width: 2rem;
  height: 1px;
  background: var(--champagne);
}
@media (prefers-reduced-motion: no-preference) {
  .portal-loading__text::before { animation: portal-pulse 1.6s ease-in-out infinite; }
}

/* Headline line mask (the site's [data-reveal-line] .line), only while the
   entrance runs; js/portal-motion.js unwraps it afterwards. */
.portal-line {
  display: block;
  overflow: hidden;
  padding-block: 0.08em 0.16em;
  margin-block: -0.08em -0.16em;
}
.portal-line__inner { display: inline-block; }

/* Cards: the service-card glow (champagne radial, top right) on hover */
.portal-card {
  position: relative;
  isolation: isolate;
  transition: border-color 0.5s ease;
}
.portal-card::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  background: radial-gradient(15.5rem circle at calc(100% - 3rem) 3rem, rgba(198, 174, 130, 0.09), rgba(198, 174, 130, 0) 65%);
  opacity: 0;
  transition: opacity 0.6s ease;
  pointer-events: none;
}
@media (hover: hover) {
  .portal-card:hover { border-color: var(--line-strong); }
  .portal-card:hover::before { opacity: 1; }
}

/* Card numbers read like the site's section labels: "01 ——" */
.portal-tile__num { display: inline-flex; align-items: center; gap: 0.75rem; }
.portal-tile__num::after {
  content: "";
  display: inline-block;
  width: 2rem;
  height: 1px;
  background: var(--champagne);
  opacity: 0.55;
  transition: width 0.5s var(--ease-out), opacity 0.5s ease;
}
@media (hover: hover) {
  .portal-card:hover .portal-tile__num::after { width: 3rem; opacity: 1; }
}

/* Tabs: the site nav's underline, drawn from the left (on the bar's rule) */
.portal-tabs__tab[aria-selected="true"] { border-bottom-color: transparent; }
.portal-tabs__tab::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 1px;
  background: var(--champagne);
  transform: scaleX(0);
  transform-origin: right;
  transition: transform 0.45s var(--ease-out);
}
.portal-tabs__tab:hover::after,
.portal-tabs__tab[aria-selected="true"]::after { transform: scaleX(1); transform-origin: left; }

/* Stat tiles and table rows: the site's quiet hover lift (ivory text, faint wash) */
.portal-stat { transition: background-color 0.5s ease; }
.portal-stat__label { transition: color 0.3s ease; }
@media (hover: hover) {
  .portal-stat:hover { background-color: rgba(242, 239, 231, 0.025); }
  .portal-stat:hover .portal-stat__label { color: var(--ivory); }
  .portal-table tbody tr { transition: background-color 0.3s ease; }
  .portal-table tbody tr:hover { background-color: rgba(242, 239, 231, 0.025); }
}

/* Custom cursor layer: the site's .cursor-cross + .cursor-trail live in one
   fixed, clipped layer, so a pointer left beyond a narrowed window never
   widens the page. */
.portal-cursor { position: fixed; inset: 0; z-index: 300; overflow: hidden; pointer-events: none; }

/* Custom cursor (css/style.css): selects keep the native arrow (the custom
   cursor hides there, like over text fields); checkboxes, radios and file
   pickers get the custom cursor's hover state instead of an I-beam. */
html.has-cursor select { cursor: default !important; }
html.has-cursor input[type="checkbox"],
html.has-cursor input[type="radio"],
html.has-cursor input[type="file"],
html.has-cursor input[type="range"],
html.has-cursor input[type="color"],
html.has-cursor input[type="button"],
html.has-cursor input[type="submit"] { cursor: none !important; }

@media (prefers-reduced-motion: reduce) {
  .portal-body .preloader { transition-duration: 0.01ms; }
}

/* ---------------------------------------------------------- form field contrast (portal only)
   A field's underline is its only visible boundary, so on the portal it meets 3:1
   against the cards and the page (WCAG 1.4.11: 0.42 ivory is 3.7:1 on #1B1B1B and
   #0A0A0A; the site's 0.14 is 1.5:1). Placeholders that carry a hint meet 4.5:1
   (0.85 stone is 5.5:1). Focus (champagne) and error colours stay the site's. */
.portal-body .field input:not([type="checkbox"]):not([type="radio"]),
.portal-body .field select,
.portal-body .field textarea { border-bottom-color: rgba(242, 239, 231, 0.42); }
.portal-body .field input:not([type="checkbox"]):not([type="radio"]):focus,
.portal-body .field select:focus,
.portal-body .field textarea:focus { border-bottom-color: var(--champagne); }
.portal-body .field.is-error input:not([type="checkbox"]):not([type="radio"]),
.portal-body .field.is-error select,
.portal-body .field.is-error textarea { border-bottom-color: #C4735C; }
.portal-body .field input::placeholder,
.portal-body .field textarea::placeholder { color: rgba(170, 166, 157, 0.85); }
.portal-label-optional { color: var(--stone); text-transform: none; letter-spacing: 0.02em; }

/* ------------------------------------------------------------
   Sign-in "zoom in and pop" (js/portal-motion.js signIn / popIn).
   The lens clip was made with Higgsfield (assets/portal/signin-zoom.*).
   ------------------------------------------------------------ */
.portal-signin-fx {
  position: fixed;
  inset: 0;
  z-index: 400;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  background: var(--obsidian);
  opacity: 0;
  cursor: pointer;
}
.portal-signin-fx__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.portal-signin-fx::after {                 /* vignette: keeps the eye on the aperture */
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background: radial-gradient(ellipse at center, transparent 38%, rgba(10, 10, 10, 0.82) 100%);
  pointer-events: none;
}
.portal-signin-fx__logo {
  position: relative;
  z-index: 2;
  width: clamp(64px, 9vw, 120px);
  height: auto;
  filter: drop-shadow(0 0 24px rgba(198, 174, 130, 0.55));
}
.portal-signin-fx__flash,
.portal-pop-flash {
  position: absolute;
  inset: 0;
  z-index: 3;
  opacity: 0;
  background: radial-gradient(circle at 50% 50%, #fffbf2 0%, var(--ivory) 45%, #d9c6a0 100%);
  pointer-events: none;
}
.portal-pop-flash {
  position: fixed;
  z-index: 400;
  display: none;
  /* the shutter: js/portal-motion.js popIn opens --mv-iris from 0% (solid) to 125% (clear) */
  --mv-iris: 0%;
  -webkit-mask-image: radial-gradient(circle at 50% 42%, transparent calc(var(--mv-iris) - 16%), #000 var(--mv-iris));
          mask-image: radial-gradient(circle at 50% 42%, transparent calc(var(--mv-iris) - 16%), #000 var(--mv-iris));
}
/* Visible from the first paint on portal-dashboard.html#mv-pop; the timed fade is
   only a safety net in case the script never runs. */
.portal-pop-flash:target,
.portal-pop-flash.is-held {
  display: block;
  opacity: 1;
}
.portal-pop-flash:target { animation: portal-pop-safety 0.6s ease 4.5s forwards; }
@keyframes portal-pop-safety { to { opacity: 0; visibility: hidden; } }
@media (prefers-reduced-motion: reduce) {
  .portal-pop-flash:target,
  .portal-pop-flash.is-held { display: none; }
}

/* ============================================================
   Overview summaries (js/portal-home.js), the account panel and
   the core staff tabs (js/portal.js).
   ============================================================ */
:root {
  --up: #8fc79b;             /* a rise: sage green (AA on charcoal) */
  --down: #e0897e;           /* a drop: soft coral red (AA on charcoal) */
}

/* Changes read at a glance: green up, red down (text and arrow) */
.portal-stat__delta[data-direction="up"],
.portal-stat__delta[data-direction="up"] .portal-stat__arrow { color: var(--up); }
.portal-stat__delta[data-direction="down"],
.portal-stat__delta[data-direction="down"] .portal-stat__arrow { color: var(--down); }

/* The date range shows only on the tabs with numbers */
.portal-dash:not([data-active-tab="overview"]):not([data-active-tab="numbers"]) #dash-range { display: none; }
/* A client with a monthly report: the range sits in the grid, just above the
   daily cards it drives (js/portal-monthly.js), and opens their section */
.portal-grid > .portal-filterbar {
  flex: 1 1 100%;
  margin: clamp(0.75rem, 2.5vw, 1.75rem) 0 0;
  padding-top: clamp(1.5rem, 3vw, 2.25rem);
  border-top: 1px solid var(--line-strong);
}
.portal-filterbar__title { flex-basis: 100%; margin: 0 0 0.5rem; }

/* ---- Client: the headline strip ---- */
.portal-glance {
  padding: clamp(1.5rem, 3.2vw, 2.5rem);
  border-color: rgba(198, 174, 130, 0.26);
  background:
    radial-gradient(40rem 18rem at 0% 0%, rgba(198, 174, 130, 0.12), rgba(198, 174, 130, 0) 70%),
    var(--charcoal);
}
.portal-glance__title {
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--stone);
}
/* letter-spacing: .serif sets 0, which would squeeze "at a glance" against the tracked words before it */
.portal-glance__title em { font-family: inherit; font-style: normal; font-size: 1em; letter-spacing: inherit; }
.portal-glance__summary {
  max-width: 44ch;
  margin-top: 0.9rem;
  font-family: var(--font-serif);
  font-size: clamp(1.45rem, 2.8vw, 2.1rem);
  font-weight: 500;
  line-height: 1.2;
  color: var(--ivory);
}
.portal-glance__summary:empty { display: none; }
.portal-glance__stats {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  margin-top: clamp(1.25rem, 2.5vw, 2rem);
  border-bottom: 1px solid var(--line);
  border-right: 1px solid var(--line);
}
@media (min-width: 900px) {
  .portal-glance__stats { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .portal-glance[data-tiles="3"] .portal-glance__stats { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .portal-glance[data-tiles="2"] .portal-glance__stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.portal-glance[data-tiles="1"] .portal-glance__stats { grid-template-columns: minmax(0, 1fr); }
.portal-glance[data-tiles="3"] .portal-glance__stats > .portal-stat:last-child { grid-column: 1 / -1; }
@media (min-width: 900px) { .portal-glance[data-tiles="3"] .portal-glance__stats > .portal-stat:last-child { grid-column: auto; } }
.portal-glance .portal-stat { padding: 1.25rem 1.4rem 1.35rem; }
.portal-glance .portal-stat__value { font-size: clamp(2rem, 4.2vw, 3.1rem); }
/* The result figures in the sentence (js/portal-home.js emphasize()): champagne, lining numerals */
.portal-glance__fig { color: var(--champagne); font-weight: 600; font-variant-numeric: lining-nums; }

/* Once the strip has risen in, a champagne light sweeps across it, behind the
   words, like the site's camera flash (js/portal-home.js light(); motion on only) */
.portal-glance { overflow: hidden; }
.portal-glance::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  background: linear-gradient(100deg, rgba(198, 174, 130, 0) 34%, rgba(198, 174, 130, 0.13) 46%, rgba(242, 239, 231, 0.08) 50%, rgba(198, 174, 130, 0.13) 54%, rgba(198, 174, 130, 0) 66%);
  opacity: 0;
  transform: translateX(-100%);
  pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
  .portal-glance.is-lit::after { animation: portal-glance-sweep 2.4s cubic-bezier(0.45, 0.05, 0.2, 1) both; }
}
@keyframes portal-glance-sweep {
  0% { opacity: 0; transform: translateX(-100%); }
  12%, 88% { opacity: 1; }
  100% { opacity: 0; transform: translateX(100%); }
}

/* A stat tile's trend (js/portal-chart.js sparkline()): a stone line over a faint
   wash, the latest point in champagne; it draws in left to right once on screen */
.portal-spark { display: block; width: 100%; height: 2.25rem; margin-top: 0.9rem; overflow: visible; }
.portal-spark__stop { stop-color: var(--champagne); stop-opacity: 0.16; }
.portal-spark__stop--end { stop-opacity: 0; }
.portal-spark__line { fill: none; stroke: var(--stone); stroke-width: 1.5; stroke-linejoin: round; stroke-linecap: round; vector-effect: non-scaling-stroke; }
.portal-spark__dot { fill: none; stroke: var(--champagne); stroke-width: 7; stroke-linecap: round; vector-effect: non-scaling-stroke; }
@media (prefers-reduced-motion: no-preference) {
  .portal-spark[data-draw] { clip-path: inset(-6px 100% -6px -6px); transition: clip-path 1.4s cubic-bezier(0.65, 0, 0.35, 1) 0.15s; }
  .portal-spark[data-draw].is-drawn { clip-path: inset(-6px -6px -6px -6px); }
}

/* ---- Client: "Getting you set up" ---- */
.portal-progress {
  position: relative;
  height: 6px;
  margin-top: 1.4rem;
  overflow: hidden;
  border-radius: 999px;
  background: rgba(242, 239, 231, 0.08);
}
.portal-progress__bar {
  position: absolute;
  inset: 0 auto 0 0;
  width: 0;
  border-radius: inherit;
  background: linear-gradient(90deg, rgba(198, 174, 130, 0.55), var(--champagne));
  transition: width 0.9s var(--ease-out);
}
.portal-setup__steps {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 17rem), 1fr));
  gap: 0 2rem;
  margin-top: 1.25rem;
}
.portal-setup__step {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.7rem 0;
  border-bottom: 1px solid var(--line);
  font-size: 0.92rem;
  color: var(--stone);
}
.portal-setup__mark {
  flex: 0 0 auto;
  display: inline-grid;
  place-items: center;
  width: 1.2rem;
  height: 1.2rem;
  border: 1px solid var(--line-strong);
  border-radius: 50%;
}
.portal-setup__title { min-width: 0; }
.portal-setup__step[data-status="done"] { color: var(--ivory); }
.portal-setup__step[data-status="done"] .portal-setup__mark { border-color: var(--champagne); background: var(--champagne); }
.portal-setup__step[data-status="done"] .portal-setup__mark::after {
  content: "";
  width: 0.32rem;
  height: 0.6rem;
  margin-top: -0.12rem;
  border: solid var(--obsidian);
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}
.portal-setup__step[data-status="next"] { color: var(--ivory); }
.portal-setup__step[data-status="next"] .portal-setup__mark { border-color: var(--champagne); box-shadow: inset 0 0 0 3px var(--charcoal), inset 0 0 0 10px var(--champagne); }
.portal-setup__next {
  flex: 0 0 auto;
  margin-left: auto;
  white-space: nowrap;
  font-size: 0.62rem;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--champagne);
}

/* Nearly done (js/portal-home.js, [data-compact]): what is left, one per line,
   and the done steps behind "Show all N steps" */
.portal-setup[data-compact]:not([data-open]) .portal-setup__steps { grid-template-columns: minmax(0, 1fr); }
.portal-setup[data-compact]:not([data-open]) .portal-setup__step { border-bottom-color: transparent; }
.portal-setup__toggle { margin-top: 1rem; font-size: 0.8rem; }

/* ---- Client: "Talk to your team" as a banner ---- */
.portal-talk {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1.25rem 2.5rem;
}
.portal-talk__text { flex: 1 1 26rem; min-width: 0; }
.portal-talk__text .portal-tile__title { margin-top: 0; }
.portal-talk .portal-actions { margin-top: 0; }

/* ---- Employee: "My work" ---- */
.portal-mywork__group { margin-top: 1.75rem; }
.portal-mywork__group + .portal-mywork__group { padding-top: 1.75rem; border-top: 1px solid var(--line); }
.portal-mywork__title {
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--ivory);
}
.portal-mywork__summary { margin-top: 0.4rem; font-size: 0.85rem; color: var(--stone); }
.portal-mywork__list { margin-top: 0.9rem; border-top: 1px solid var(--line); }
.portal-mywork__item {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.25rem 1.5rem;
  padding: 0.8rem 0;
  border-bottom: 1px solid var(--line);
}
.portal-mywork__name { min-width: 0; overflow-wrap: anywhere; color: var(--ivory); }
.portal-mywork__meta { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 0.6rem; font-size: 0.82rem; color: var(--stone); }
.portal-mywork__item[data-state="overdue"] .portal-mywork__due { color: var(--down); }
.portal-mywork__tag {
  padding: 0.15rem 0.55rem;
  border: 1px solid rgba(198, 174, 130, 0.4);
  border-radius: 999px;
  font-size: 0.62rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--champagne);
}
.portal-mywork__open { margin-top: 1rem; font-size: 0.8rem; }
.portal-mywork__open .arrow { display: inline-block; color: var(--champagne); transition: transform 0.4s var(--ease-out); }
.portal-mywork__open:hover .arrow { transform: translateX(3px); }
.portal-mywork__clear { margin-top: 1.5rem; font-size: 0.95rem; color: var(--stone); }

/* ---- Staff: "Clients at a glance" ---- */
[data-portal-roster].is-refreshing #roster-root { opacity: 0.55; transition: opacity 0.3s ease; }
.portal-roster td { vertical-align: top; }
.portal-roster__business { min-width: 12rem; }
.portal-roster__name { display: block; font-weight: 600; color: var(--ivory); overflow-wrap: anywhere; }
.portal-roster__handles { display: block; margin-top: 0.2rem; font-size: 0.78rem; color: var(--stone); overflow-wrap: anywhere; }
.portal-roster__value { display: block; font-variant-numeric: tabular-nums; color: var(--ivory); }
.portal-roster__delta { display: block; margin-top: 0.15rem; font-size: 0.76rem; }
.portal-roster__when span { display: block; }
.portal-roster__ago { font-size: 0.78rem; color: var(--stone); }
.portal-roster__ob-text { display: block; font-size: 0.85rem; white-space: nowrap; }
.portal-roster__meter { display: block; width: 4.5rem; height: 4px; margin-top: 0.45rem; overflow: hidden; border-radius: 999px; background: rgba(242, 239, 231, 0.08); }
.portal-roster__meter-bar { display: block; height: 100%; border-radius: inherit; background: var(--champagne); }
.portal-roster__status { min-width: 9rem; }
.portal-roster__more { display: block; margin-top: 0.4rem; font-size: 0.76rem; line-height: 1.4; color: var(--stone); }
.portal-chip {
  display: inline-block;
  margin: 0 0.35rem 0.35rem 0;
  padding: 0.2rem 0.6rem;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  font-size: 0.72rem;
  line-height: 1.4;
  white-space: nowrap;
  color: var(--stone);
}
.portal-chip[data-level="ok"] { border-color: rgba(143, 199, 155, 0.4); color: var(--up); }
.portal-chip[data-level="warn"] { border-color: rgba(198, 174, 130, 0.45); color: var(--champagne); }
.portal-chip[data-level="bad"] { border-color: rgba(224, 137, 126, 0.5); color: var(--down); }
.portal-roster tr[data-attention="true"] .portal-roster__name::before {
  content: "";
  display: inline-block;
  width: 0.45rem;
  height: 0.45rem;
  margin: 0 0.5rem 0.12rem 0;
  border-radius: 50%;
  background: var(--champagne);
  vertical-align: middle;
}
@media (max-width: 640px) {
  /* the shared list pattern (.portal-table--list, Accounts table section): the
     business is the heading with its handles under it, its status chips on the
     next line, then each number with its change and the dates; Open on its own line */
  .portal-roster__business, .portal-roster__status { min-width: 0; }
  .portal-roster__handles { font-weight: 400; }
  .portal-roster__value, .portal-roster__delta { display: inline; margin-top: 0; }
  .portal-roster__when span, .portal-roster__report span { display: inline; }
  .portal-roster__ob-text { display: inline; font-size: inherit; }
  .portal-roster__meter { display: inline-block; width: 2.75rem; margin-top: 0; align-self: center; }
  .portal-table--list td.portal-roster__status { order: -1; flex: 1 1 100%; flex-wrap: wrap; gap: 0.35rem; margin-block: 0.1rem 0.15rem; }
  .portal-roster__status .portal-chip { margin: 0; white-space: normal; }
}

/* ---- Header: the account button ---- */
.portal-account-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  max-width: 14rem;
  padding: 0.3rem 0.9rem 0.3rem 0.3rem;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  background: transparent;
  color: var(--ivory);
  font: inherit;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  cursor: pointer;
  transition: border-color 0.35s ease, background-color 0.35s ease;
}
.portal-account-btn:hover,
.portal-account-btn[aria-expanded="true"] { border-color: var(--champagne); background: rgba(198, 174, 130, 0.08); }
.portal-account-btn:focus-visible { outline: 1px solid var(--champagne); outline-offset: 3px; }
.portal-account-btn__avatar {
  flex: 0 0 auto;
  display: inline-grid;
  place-items: center;
  width: 1.9rem;
  height: 1.9rem;
  border-radius: 50%;
  background: linear-gradient(135deg, var(--champagne), #9c8659);
  color: var(--obsidian);
  font-size: 0.68rem;
  letter-spacing: 0.04em;
}
.portal-account-btn__name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@media (max-width: 560px) {
  .portal-account-btn { padding: 0.2rem; }
  .portal-account-btn__name { display: none; }
  /* Phones: the logo already links back to the site, so the dashboard header keeps
     just the logo, the account button and Log out on one row. */
  .portal-body[data-portal-page="dashboard"] .portal-header__back { display: none; }
}
html.has-cursor .portal-account-btn,
html.has-cursor .portal-drawer__close { cursor: none !important; }

/* ---- The account panel ---- */
.portal-drawer {
  position: fixed;
  inset: 0;
  z-index: 250;               /* above the page, below the custom cursor layer (300) */
}
.portal-drawer__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(10, 10, 10, 0.6);
  -webkit-backdrop-filter: blur(4px);
          backdrop-filter: blur(4px);
  opacity: 0;
  transition: opacity 0.4s ease;
}
.portal-drawer__panel {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: min(100%, 26rem);
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: clamp(1.5rem, 4vw, 2.25rem);
  border-left: 1px solid var(--line-strong);
  background:
    radial-gradient(22rem 14rem at 100% 0%, rgba(198, 174, 130, 0.1), rgba(198, 174, 130, 0) 70%),
    var(--charcoal);
  box-shadow: -2rem 0 4rem rgba(0, 0, 0, 0.45);
  transform: translateX(102%);
  transition: transform 0.42s var(--ease-out);
}
.portal-drawer.is-open .portal-drawer__backdrop { opacity: 1; }
.portal-drawer.is-open .portal-drawer__panel { transform: none; }
.portal-drawer__head { display: flex; align-items: center; justify-content: space-between; gap: 1rem; }
.portal-drawer__close {
  display: inline-grid;
  place-items: center;
  width: 2.35rem;
  height: 2.35rem;
  border: 1px solid var(--line-strong);
  border-radius: 50%;
  background: transparent;
  color: var(--ivory);
  font-size: 1.25rem;
  line-height: 1;
  cursor: pointer;
  transition: border-color 0.3s ease, color 0.3s ease;
}
.portal-drawer__close:hover { border-color: var(--champagne); color: var(--champagne); }
.portal-drawer__close:focus-visible { outline: 1px solid var(--champagne); outline-offset: 3px; }
.portal-drawer__title { margin-top: 1.25rem; font-size: clamp(1.6rem, 5vw, 2rem); font-weight: 600; letter-spacing: -0.01em; }
.portal-drawer__title:focus { outline: none; }
.portal-drawer__title .serif { font-size: 1.15em; }
.portal-drawer .portal-form { margin-top: 1.75rem; padding-top: 1.5rem; border-top: 1px solid var(--line); }
.portal-drawer__section { margin-top: 2rem; }
.portal-drawer__subtitle {
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--stone);
}
.portal-drawer__section .portal-links { margin-top: 0.75rem; }
@media (prefers-reduced-motion: reduce) {
  .portal-drawer__panel,
  .portal-drawer__backdrop,
  .portal-progress__bar { transition: none; }
}

/* ============================================================
   The written monthly report (js/portal-monthly.js): the client's
   Overview cards, the report in the Reports tab, its editor
   ============================================================ */
.portal-body {
  /* Facebook's series colour is with the other platforms' (social metrics, above).
     Map positions (ranking scans): the traffic-light meaning (green good, red
     bad), softened into the palette, and the better a point ranks the more
     visible it is: lightness falls 0.88 -> 0.46 from the top 3 to 20+. Checked
     with the dataviz validator on #1B1B1B: monotone lightness, adjacent
     lightness steps >= 0.14, colour-blind (deutan) worst delta E 13.4,
     normal-vision worst 15.9 (the old set failed at 11.6), every digit >= 4.8:1
     on its fill (ivory digits on the darkest). */
  --rank-top3: #ADE9B8;    /* sage       oklch(0.88 0.09 150) */
  --rank-top10: #CEAD59;   /* gold       oklch(0.76 0.11 88) */
  --rank-mid: #C06E41;     /* amber      oklch(0.62 0.12 48) */
  --rank-low: #83423D;     /* terracotta oklch(0.46 0.09 26) */
  --rank-ink: #141414;
}

/* "02 —— September 2026 · Month 02": the gap after the number's rule matches the
   one before it; on a phone the month wraps under the number, flush left */
.portal-mr__kicker { display: flex; flex-wrap: wrap; align-items: center; gap: 0.35rem 0.75rem; margin-bottom: 0.65rem; }
.portal-mr__lead { max-width: 70ch; margin-top: 1.1rem; line-height: 1.65; color: var(--ivory); }
.portal-mr__lead + .portal-mr__lead { margin-top: 0.8rem; }
.portal-mr__para { max-width: 70ch; margin-top: 0.8rem; line-height: 1.6; color: var(--stone); }
.portal-mr__scan-note { margin-top: 1.25rem; }
.portal-mr__foot { margin-top: 0.55rem; font-size: 0.75rem; color: var(--stone); }
.portal-mr__table-wrap { margin-top: 1.5rem; container: mr-table / inline-size; }
.portal-mr__table tbody th {
  padding: 0.9rem 1rem 0.9rem 0;
  border-bottom: 1px solid var(--line);
  font-size: 0.9rem;
  font-weight: 500;
  letter-spacing: normal;
  text-transform: none;
  text-align: left;
  vertical-align: top;
  color: var(--ivory);
}
.portal-mr__table td { vertical-align: top; }
@media (min-width: 641px) {
  /* compact tables (the ranking scans) pad their cells 0.6rem: the row heading matches, so each number sits level with its label */
  .portal-mr__table.portal-table--compact tbody th { padding-block: 0.6rem; }
}
.portal-mr__table--work td:last-child,
.portal-mr__table--next td:last-child { white-space: normal; color: var(--stone); }
.portal-mr__table--work tbody th,
.portal-mr__table--next tbody th { width: 34%; }
.portal-mr__table--social td { font-variant-numeric: tabular-nums; color: var(--ivory); }
.portal-mr__table--social td:last-child { color: var(--ivory); }
.portal-mr__notes {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 21rem), 1fr));
  gap: 1.25rem 2.25rem;
  margin-top: 1.75rem;
}
.portal-mr__note-title { font-size: 0.95rem; font-weight: 600; line-height: 1.4; color: var(--ivory); }
.portal-mr__note-body { margin-top: 0.35rem; font-size: 0.92rem; line-height: 1.6; color: var(--stone); }
.portal-mr__note-body + .portal-mr__note-body { margin-top: 0.6rem; }
.portal-mr__actions { align-items: center; margin-top: 1.75rem; }
.portal-mr__prepared { font-size: 0.8rem; color: var(--stone); }
.portal-mr__stats { display: flex; flex-wrap: wrap; gap: 1rem 2.75rem; margin-top: 1.5rem; }
.portal-mr__stat dt {
  font-size: 0.66rem;
  font-weight: 600;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--stone);
}
.portal-mr__stat dd {
  margin: 0.35rem 0 0;
  font-size: clamp(1.75rem, 3vw, 2.25rem);
  font-weight: 600;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
  color: var(--ivory);
}

/* bars: one group per month, one bar per platform, the value on each bar */
.portal-mr__charts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
  gap: 1.75rem 2.5rem;
  margin-top: 1.75rem;
}
.portal-bars { margin: 0; min-width: 0; }
.portal-bars__title {
  margin-bottom: 0.9rem;
  font-size: 0.66rem;
  font-weight: 600;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--stone);
}
.portal-bars__plot { display: flex; gap: 1.25rem; height: 11.5rem; }
.portal-bars__group { display: flex; flex: 1 1 0; flex-direction: column; min-width: 0; }
.portal-bars__cols {
  display: flex;
  flex: 1 1 auto;
  align-items: flex-end;
  justify-content: center;
  gap: 0.45rem;
  min-height: 0;
  border-bottom: 1px solid var(--line-strong);
}
.portal-bars__col {
  display: flex;
  flex: 0 1 3.25rem;
  flex-direction: column;
  justify-content: flex-end;
  min-width: 1.4rem;
  height: 100%;
}
.portal-bars__value {
  padding-bottom: 0.3rem;
  font-size: 0.78rem;
  font-variant-numeric: tabular-nums;
  text-align: center;
  white-space: nowrap;
  color: var(--ivory);
}
.portal-bars__bar { display: block; flex: none; border-radius: 3px 3px 0 0; background: var(--stone); }
.portal-bars__bar--instagram { background: var(--portal-series-instagram); }
.portal-bars__bar--facebook { background: var(--portal-series-facebook); }
.portal-bars__bar--tiktok { background: var(--portal-series-tiktok); }
.portal-bars__label {
  overflow: hidden;
  padding-top: 0.5rem;
  font-size: 0.75rem;
  text-align: center;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--stone);
}
.portal-bars__legend,
.portal-rank__legend {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 1.15rem;
  margin: 0.85rem 0 0;
  padding: 0;
  list-style: none;
  font-size: 0.78rem;
  color: var(--stone);
}
.portal-bars__legend li,
.portal-rank__legend li { display: inline-flex; align-items: center; gap: 0.45rem; }

/* followers vs non-followers */
.portal-split { margin-top: 1.75rem; }
.portal-split__row {
  display: grid;
  grid-template-columns: 8.5rem minmax(0, 1fr);
  gap: 0.3rem 1rem;
  align-items: center;
  margin-top: 0.75rem;
}
.portal-split__label { display: inline-flex; align-items: center; gap: 0.45rem; font-size: 0.88rem; color: var(--ivory); }
.portal-split__bar { display: flex; height: 0.7rem; overflow: hidden; border-radius: 999px; background: var(--line); }
.portal-split__part--followers { background: var(--champagne); }
.portal-split__part--others { background: #57544E; }
.portal-split__legend {
  display: flex;
  grid-column: 2;
  justify-content: space-between;
  gap: 1rem;
  font-size: 0.75rem;
  color: var(--stone);
}
@media (max-width: 480px) {
  .portal-split__row { grid-template-columns: minmax(0, 1fr); }
  .portal-split__legend { grid-column: 1; }
}

/* ranking scans: the grid of map positions */
.portal-mr__scans { margin-top: 2rem; }
.portal-rank__row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
  gap: 1.5rem 2.5rem;
}
.portal-rank { margin: 0; min-width: 0; }
.portal-rank__label { font-size: 0.95rem; font-weight: 600; color: var(--ivory); }
.portal-rank__meta { margin-top: 0.2rem; font-size: 0.8rem; color: var(--stone); }
.portal-rank__grid {
  --rank-size: 9;
  display: grid;
  grid-template-columns: repeat(var(--rank-size), minmax(0, 1fr));
  gap: clamp(2px, 0.5vw, 5px);
  max-width: 26rem;
  margin-top: 0.8rem;
  container-type: inline-size;
}
.portal-rank__cell {
  display: grid;
  place-items: center;
  aspect-ratio: 1;
  border-radius: 50%;
  font-size: 0.62rem;
  font-size: calc(100cqi / var(--rank-size) * 0.34);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 1;
  letter-spacing: -0.02em;
  color: var(--rank-ink);
}
.portal-rank__cell[data-band="top3"], .portal-rank__swatch[data-band="top3"] { background: var(--rank-top3); }
.portal-rank__cell[data-band="top10"], .portal-rank__swatch[data-band="top10"] { background: var(--rank-top10); }
.portal-rank__cell[data-band="mid"], .portal-rank__swatch[data-band="mid"] { background: var(--rank-mid); }
.portal-rank__cell[data-band="low"], .portal-rank__swatch[data-band="low"] { background: var(--rank-low); }
.portal-rank__cell[data-band="low"] { color: var(--ivory); }
.portal-rank__swatch { display: inline-block; width: 0.75rem; height: 0.75rem; border-radius: 50%; }
.portal-mr__scans .portal-table-wrap { max-width: 34rem; }
.portal-mr__scans .portal-mr__table td,
.portal-mr__scans .portal-mr__table td:last-child { color: var(--ivory); }

/* The client's map (js/portal-monthly.js rankMap): one grid, the scans to flip
   between, the table beside it from 960px */
.portal-map { display: grid; gap: 1.75rem 3rem; margin-top: 0.25rem; }
@media (min-width: 960px) { .portal-map { grid-template-columns: minmax(0, 26rem) minmax(0, 1fr); align-items: start; } }
.portal-map__figure { margin: 0; }
.portal-map__bar { display: flex; flex-wrap: wrap; align-items: center; gap: 0.6rem 1.25rem; }
.portal-map__bar .portal-rank__meta { margin-top: 0; }
.portal-map__figure .portal-rank__grid { margin-top: 1.1rem; }
.portal-map__side .portal-mr__table-wrap { margin-top: 0; }
.portal-mr__scans .portal-map__side .portal-table-wrap { max-width: none; }
/* the table picks out the shown scan's column */
.portal-mr__scans .portal-map__side .portal-mr__table td:not([data-shown]) { color: var(--stone); }
.portal-map__side .portal-mr__table td { transition: color 0.4s ease; }
.portal-map__side .portal-mr__table td[data-shown] { font-weight: 600; }
.portal-map__side .portal-mr__table thead th[data-shown] { color: var(--champagne); }

/* A point turning into the next scan: its new colour at once (a blend between
   two of the four would pass through grey), popping in with a brief champagne
   glow, like a camera flash going off across the map */
.portal-rank__cell.is-turning { animation: portal-rank-turn 0.65s var(--ease-out); }
@keyframes portal-rank-turn {
  0% { transform: scale(0.78); }
  40% { transform: scale(1.16); box-shadow: 0 0 0 2px rgba(198, 174, 130, 0.35), 0 0 16px rgba(198, 174, 130, 0.4); }
  100% { transform: scale(1); }
}
@media (prefers-reduced-motion: reduce) {
  .portal-rank__cell.is-turning { animation: none; }
}
.portal-bars__legend .portal-chart__key,
.portal-split__label .portal-chart__key { width: 0.7rem; height: 0.7rem; border-radius: 2px; }
@media (max-width: 640px) {
  .portal-mr__table tbody th,
  .portal-mr__table--work tbody th,
  .portal-mr__table--next tbody th { display: block; width: auto; padding: 0 0 0.3rem; border-bottom: 0; }
  .portal-mr__table--work td, .portal-mr__table--work td:last-child,
  .portal-mr__table--next td, .portal-mr__table--next td:last-child { display: block; text-align: left; }
  .portal-mr__table--work td::before,
  .portal-mr__table--next td::before { content: none; }

  /* ...but numbers in up to three columns stay a table (js/portal-monthly.js table())
     while one fits: Metric | Instagram | Facebook ("Interactions", "52% to 48%") needs
     15.8rem, a 360px phone gives it 16.9rem; under 16.5rem they stack. */
  @container mr-table (min-width: 16.5rem) {
    .portal-mr__table.portal-mr__table--grid { display: table; }
    .portal-mr__table.portal-mr__table--grid thead { position: static; display: table-header-group; width: auto; height: auto; overflow: visible; clip: auto; }
    .portal-mr__table.portal-mr__table--grid tbody { display: table-row-group; }
    .portal-mr__table.portal-mr__table--grid tr { display: table-row; padding: 0; border-bottom: 0; }
    .portal-mr__table.portal-mr__table--grid th,
    .portal-mr__table.portal-mr__table--grid td,
    .portal-mr__table.portal-mr__table--grid td:last-child,
    .portal-mr__table.portal-mr__table--grid tbody th {
      display: table-cell;
      width: auto;
      padding: 0.65rem 0 0.65rem 0.5rem;
      border-bottom: 1px solid var(--line);
      vertical-align: top;
    }
    .portal-mr__table.portal-mr__table--grid th { white-space: normal; }
    .portal-mr__table.portal-mr__table--grid tbody th,
    .portal-mr__table.portal-mr__table--grid td { font-size: 0.85rem; }
    .portal-mr__table.portal-mr__table--grid thead th { padding-block: 0 0.65rem; border-bottom-color: var(--line-strong); letter-spacing: 0.1em; }
    .portal-mr__table.portal-mr__table--grid th:first-child { padding-left: 0; padding-right: 0.5rem; }
    .portal-mr__table.portal-mr__table--grid td { text-align: right; white-space: nowrap; }
    .portal-mr__table.portal-mr__table--grid td::before { content: none; }
  }
}

/* Profile pictures (js/portal-avatar.js): a picture, or initials on a tint */
.portal-avatar {
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  border-radius: 50%;
  border: 1px solid var(--line-strong);
  background: var(--charcoal-soft);
  color: var(--ivory);
  font-weight: 600;
  letter-spacing: 0.04em;
  line-height: 1;
  user-select: none;
}
.portal-avatar__img { display: block; width: 100%; height: 100%; object-fit: cover; }
