/* ═══════════════════════════════════════════════════════════════════════════
   ValWithProof — the lockup, and the product's motion.

   Two things live here, and they are together because they are the two things
   that had no home. Everything else in this product is either a page's own
   <style> or one of the four shared sheets, and both of these are
   cross-cutting: the lockup has to be identical in six documents, and the
   motion has to be switched off from one place.

   Loaded LAST, next to polish.css, by every document the shell serves.

   Written against each page's own variables with a literal fallback beside
   each, the same contract polish.css keeps — six documents declare six
   palettes and a rule that renders invisible in one of them is worse than a
   rule that is a shade off in the other five.
   ═══════════════════════════════════════════════════════════════════════════ */


/* ══ 1. THE LOCKUP ═══════════════════════════════════════════════════════════
   Mark, then wordmark, top-left, going home.

   One class, because the six documents had six answers: the shell had
   `.brand`, the mentor and admin consoles `.logo > .mark`, the meeting room
   `.rbrand`, the founder's door a bare `<img class="mk">` and the founder app
   a `<span class="mark">V</span>` — a letter V in a rounded box, which was the
   one surface in the product still not showing the logo at all.

   The wordmark is TEXT, not artwork. It is the product's own typeface at the
   product's own weight, so it inherits the page's colour on a dark bar and
   its size from one token here — and it is selectable, searchable and
   translatable, which a flattened SVG wordmark is none of.

   Under 560px the words come off and the mark stands alone. That is the same
   rule the collapsed rail already follows, and it is why the mark keeps its
   ground: a lockup that degrades to a mark has to have a mark that works by
   itself. */

.vwp-brand {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
  color: inherit;
  text-decoration: none;
  /* The whole lockup is the home link, so it gets one focus ring and one
     hover, not two. */
  border-radius: 10px;
  transition: opacity var(--t-fast, .16s) var(--ease, ease);
}
.vwp-brand:hover { opacity: .86; }

.vwp-brand-mark {
  flex: none;
  display: block;
  width: 30px;
  height: 30px;
  border-radius: 9px;
  /* The mark is a 64×64 drawing with its own ground. Nothing here may add a
     second one — a box-shadow or a border around it reads as a sticker. */
  transition: transform var(--t-mid, .28s) var(--ease-out-back, ease);
}
.vwp-brand:hover .vwp-brand-mark { transform: rotate(-4deg) scale(1.06); }

.vwp-brand-name {
  font-weight: 700;
  font-size: 18px;
  letter-spacing: -.02em;
  line-height: 1;
  white-space: nowrap;
  color: var(--ink, var(--text, var(--th-ink,#000000)));
}
/* On a dark bar the wordmark takes the bar's ink rather than the page's. */
:where(.topbar-dark, .cwh, .rbrand, .sidebar, .authhead, [data-on-dark]) .vwp-brand-name,
.vwp-brand[data-on-dark] .vwp-brand-name { color: #fff; }

/* The second line some placements carry — MENTOR CONSOLE, MENTOR CONNECT,
   ADMIN. It belongs to the lockup rather than beside it, so the two lines
   stay locked when the wordmark size changes. */
.vwp-brand-stack { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.vwp-brand-sub {
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
  line-height: 1;
  color: var(--g600, var(--brand, var(--th-ink,#000000)));
  white-space: nowrap;
}
:where(.cwh, .rbrand, .sidebar, .authhead, [data-on-dark]) .vwp-brand-sub,
.vwp-brand[data-on-dark] .vwp-brand-sub { color: #16B8B0; }

.vwp-brand-sm .vwp-brand-mark { width: 26px; height: 26px; border-radius: 8px; }
.vwp-brand-sm .vwp-brand-name { font-size: 15.5px; }
.vwp-brand-lg .vwp-brand-mark { width: 38px; height: 38px; border-radius: 11px; }
.vwp-brand-lg .vwp-brand-name { font-size: 22px; }

@media (max-width: 560px) {
  .vwp-brand-name, .vwp-brand-sub { display: none; }
  .vwp-brand { gap: 0; }
}


/* ══ 2. MOTION ═══════════════════════════════════════════════════════════════
   The product had transitions on hover and nothing else: every screen
   appeared at full opacity, fully laid out, in one frame. That is not
   "fast" — with no arrival there is nothing to tell a person that the thing
   they are looking at is the thing that just answered them, and on a screen
   that repaints on a filter change it is indistinguishable from not having
   worked.

   Four rules for the whole product:

     1. Motion explains a CHANGE. Nothing loops, nothing moves for decoration,
        and nothing animates that was already on screen and did not change.
     2. Arrivals are under 400 ms and hovers are under 200 ms. Past that a
        person is waiting on an animation, which is worse than no animation.
     3. Nothing moves more than ~10 px. A card that flies in from off-screen
        drags the eye away from where it is about to need to be.
     4. Every rule here is named `vwp-*` and every one of them is switched off
        at the bottom of this file. One media query, one place to look.

   Opacity and transform only — both composite on the GPU and neither causes
   layout. No animation here touches height, width, top or margin. */

@keyframes vwp-rise   { from { opacity: 0; transform: translateY(8px);  } to { opacity: 1; transform: none; } }
@keyframes vwp-fade   { from { opacity: 0; } to { opacity: 1; } }
@keyframes vwp-pop    { from { opacity: 0; transform: translateY(10px) scale(.985); } to { opacity: 1; transform: none; } }
@keyframes vwp-markin { from { opacity: 0; transform: translateY(-4px) rotate(-14deg) scale(.7); } to { opacity: 1; transform: none; } }
@keyframes vwp-shimmer{ from { background-position: 200% 0; } to { background-position: -200% 0; } }
@keyframes vwp-ring   { 0% { box-shadow: 0 0 0 0 rgba(22, 184, 176, .38); } 70%, 100% { box-shadow: 0 0 0 10px rgba(22, 184, 176, 0); } }

/* ── the page arriving ──────────────────────────────────────────────────── */
.vwp-rise { animation: vwp-rise var(--t-mid, .28s) var(--ease, ease) both; }
.vwp-fade { animation: vwp-fade var(--t-mid, .28s) var(--ease, ease) both; }
.vwp-pop  { animation: vwp-pop  var(--t-slow, .5s) var(--ease-out-back, ease) both; }

/* A stagger without a script. Six steps and then it stops — past the sixth
   card the delay is longer than the animation and the list reads as loading
   rather than as arriving, and below the fold nobody sees it anyway. */
.vwp-stagger > * { animation: vwp-rise var(--t-mid, .28s) var(--ease, ease) both; }
.vwp-stagger > :nth-child(1) { animation-delay: 0ms;  }
.vwp-stagger > :nth-child(2) { animation-delay: 45ms; }
.vwp-stagger > :nth-child(3) { animation-delay: 90ms; }
.vwp-stagger > :nth-child(4) { animation-delay: 135ms;}
.vwp-stagger > :nth-child(5) { animation-delay: 180ms;}
.vwp-stagger > :nth-child(n+6) { animation-delay: 225ms; }

/* The mark, once, on the first paint of every document. The overshoot curve
   is the reason it reads as the logo landing rather than as a fade. */
.vwp-brand-mark, .brand-mark, .logo .mark, .authhead .mk, .mk {
  animation: vwp-markin var(--t-slow, .5s) var(--ease-out-back, ease) both;
}

/* ── a screen arriving ──────────────────────────────────────────────────── */
/* Opacity ONLY at container level, and this is not fussiness. `transform`
   makes an element a containing block for `position: fixed` descendants, so a
   modal rendered inside a pane that is mid-rise would be positioned against
   the pane instead of against the viewport and would visibly jump when the
   animation ended. Panes fade; the things inside them are what move.

   These are the containers each of the six documents swaps when you change
   tab or route, so this fires on the change and not on a re-render — React
   keeps the DOM node when it only updates it, and an animation restarts only
   on mount. */
:where(.view, .app, .content, .main, .shell-main) > * {
  animation: vwp-fade var(--t-mid, .28s) var(--ease, ease) both;
}

/* ── things that arrive over the page ───────────────────────────────────── */
:where(.modal, .sheet, .ringsheet, .acct-pop, .pop, .menu, .toast, .drawer) {
  animation: vwp-pop var(--t-mid, .28s) var(--ease-out-back, ease) both;
}
:where(.backdrop, .scrim, .modal-bg, .ringwrap) {
  animation: vwp-fade var(--t-fast, .16s) var(--ease, ease) both;
}

/* ── hover, on the things you press ─────────────────────────────────────── */
:where(.btn, .btn-primary, .btn-ghost, .primary, .cta, button.go):not(:disabled) {
  transition: transform var(--t-fast, .16s) var(--ease, ease),
              box-shadow var(--t-fast, .16s) var(--ease, ease),
              background var(--t-fast, .16s) var(--ease, ease),
              border-color var(--t-fast, .16s) var(--ease, ease),
              color var(--t-fast, .16s) var(--ease, ease);
}
/* Cards lift only where a card is a TARGET — one you click through to. A
   dashboard tile that lifts under the pointer is an invitation to click
   something that does nothing. */
:where(a.card, a.tile, .card[role='button'], .card.clickable, .mrow, .mcard, .apicard) {
  transition: transform var(--t-fast, .16s) var(--ease, ease),
              box-shadow var(--t-fast, .16s) var(--ease, ease),
              border-color var(--t-fast, .16s) var(--ease, ease);
}
:where(a.card, a.tile, .card[role='button'], .card.clickable, .mrow, .mcard, .apicard):hover {
  transform: translateY(-2px);
  border-color: rgba(22, 184, 176, .38);
  box-shadow: 0 14px 30px -18px rgba(0, 0, 0, .34), 0 1px 2px rgba(0, 0, 0, .05);
}

/* Tabs and rail rows: colour and ground, never size. A nav item that grows on
   hover moves the item under it. */
:where(.tabs button, .cwtabs button, .nav-item, .sidenav a, .sidenav button, .topnav a) {
  transition: background var(--t-fast, .16s) var(--ease, ease),
              color var(--t-fast, .16s) var(--ease, ease),
              border-color var(--t-fast, .16s) var(--ease, ease);
}

/* ── waiting ────────────────────────────────────────────────────────────── */
/* A block that is the shape of the thing that is coming, rather than a
   spinner in the middle of an empty page. */
.vwp-sk {
  border-radius: 8px;
  background: linear-gradient(100deg,
    rgba(var(--th-ink-rgb,0, 0, 0), .06) 30%,
    rgba(22, 184, 176, .14) 50%,
    rgba(var(--th-ink-rgb,0, 0, 0), .06) 70%);
  background-size: 200% 100%;
  animation: vwp-shimmer 1.5s linear infinite;
}
.vwp-sk + .vwp-sk { margin-top: 8px; }
.vwp-sk-line { height: 12px; }
.vwp-sk-line.w70 { width: 70%; }
.vwp-sk-line.w45 { width: 45%; }

/* One attention ring, for the one thing on a screen that is waiting on the
   person — an incoming call, an unanswered request. It loops, which every
   other rule here is forbidden from doing, because the thing it marks is
   itself still happening. */
.vwp-attn { animation: vwp-ring 1.9s cubic-bezier(0, 0, .2, 1) infinite; }

/* ── the brand hairline ─────────────────────────────────────────────────── */
/* Along the bottom of whatever bar is at the top of the page, fading out at
   both ends. It sits ON the existing 1px border rather than adding a second
   one, so no bar changes height and nothing below it shifts.

   This is the one piece of pure decoration in the chrome and it earns its
   place: bar, rail and page are three whites separated by three hairlines of
   the same grey, and until now a person could cross four screens of this
   product without seeing the colour of its logo anywhere above the fold.

   Not on the dark bars — .cwh, .rbrand and the meeting room's .rhead are
   already the brand navy, and a teal line under a navy bar is a second idea
   where there was one. */
:where(.topbar, .sitebar) { position: relative; }
:where(.topbar, .sitebar)::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: -1px;
  height: 2px;
  background: var(--grad-hair,
    linear-gradient(90deg, transparent, rgba(22, 184, 176, .55), transparent));
  pointer-events: none;
}

/* A teal rule that fades at both ends, for the top of a panel or under a
   heading. The logo's own two stops, used where they are free to be
   decorative rather than legible. */
.vwp-hair {
  height: 2px;
  border: 0;
  border-radius: 2px;
  background: var(--grad-hair,
    linear-gradient(90deg, transparent, rgba(22, 184, 176, .55), transparent));
}
/* The same line as a panel's top edge, drawn rather than added to the box. */
.vwp-edge { position: relative; }
.vwp-edge::before {
  content: '';
  position: absolute;
  left: 0; right: 0; top: 0;
  height: 2px;
  border-radius: 2px 2px 0 0;
  background: linear-gradient(90deg, #000000, #16B8B0 55%, #16B8B0);
  opacity: .9;
}


/* ══ 3. OFF ══════════════════════════════════════════════════════════════════
   Everything above, from one place. `!important` for the same reason
   polish.css uses it: the transitions this has to beat are declared inline in
   six documents.

   `animation: none` rather than a 0.001 ms duration for the keyframed rules —
   a zero-length animation with `both` still applies its FROM state for a
   frame, which on `vwp-rise` means the page flashes transparent for anyone
   who asked for no motion. Setting them to none leaves the element at its
   natural state, which is the state the animation was ending at. */
@media (prefers-reduced-motion: reduce) {
  :where(.view, .app, .content, .main, .shell-main) > *,
  .vwp-rise, .vwp-fade, .vwp-pop, .vwp-stagger > *,
  .vwp-brand-mark, .brand-mark, .logo .mark, .authhead .mk, .mk,
  .vwp-sk, .vwp-attn,
  :where(.modal, .sheet, .ringsheet, .acct-pop, .pop, .menu, .toast, .drawer),
  :where(.backdrop, .scrim, .modal-bg, .ringwrap) {
    animation: none !important;
    opacity: 1 !important;
    transform: none !important;
  }
  .vwp-brand:hover .vwp-brand-mark { transform: none !important; }
  :where(a.card, a.tile, .card[role='button'], .card.clickable, .mrow, .mcard, .apicard):hover {
    transform: none !important;
  }
}

/* ══ ICONS ═══════════════════════════════════════════════════════════════
   The set in /assets/icons.js, wrapped in a `.ico` span by the `Ico`
   component each portal defines. Two rules and no more: the drawing is a
   block inside its own box so it does not sit on a text baseline it was
   never measured against, and an icon in a line of text is centred against
   the line rather than hung below it.
   ═══════════════════════════════════════════════════════════════════════ */
.ico { display: inline-flex; align-items: center; justify-content: center; flex: none; }
.ico > svg { display: block; }
/* The big one at the top of an empty state keeps the block layout those
   rules already give it, and centres itself. */
.empty .ico { display: block; }
.empty .ico > svg { margin: 0 auto; }
/* An icon in a banner is the banner's colour, and it must not shrink when
   the sentence beside it is long. */
.banner .ico, .gateerr .ico { align-self: flex-start; margin-top: 1px; }
