/* ==========================================================================
   Belong — shared brand tokens
   Extracted from brand-guideline.html (Brand Hub). Single source of truth for
   index.html, join/index.html, and the careers dashboard.

   Deliberately NOT included here: the Brand Hub's own `--s: 12px` base size and
   `body { font-weight: 700 }`. Those are the dense chrome of a documentation
   tool. The public pages carry long-form prose and keep their fluid clamp()
   scale; the dashboard opts into the .ui-* layer below instead.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Type — PP Object Sans, 400 / 700 / 900.
   There is no 500. ABC Diatype Semi Mono is retired; Object Sans carries the
   whole system, so --label is an alias rather than a second family.
   -------------------------------------------------------------------------- */
@font-face {
  font-family: "PP Object Sans";
  src: url("/fonts/belong-object-sans-regular.woff2") format("woff2");
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "PP Object Sans";
  src: url("/fonts/belong-object-sans-bold.woff2") format("woff2");
  font-weight: 700; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "PP Object Sans";
  src: url("/fonts/belong-object-sans-heavy.woff2") format("woff2");
  font-weight: 900; font-style: normal; font-display: swap;
}

:root {
  --font: "PP Object Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
  /* the utility face: labels, hints, data readouts. Never headlines, never
     body copy, so the sweep stays a discipline instead of a decoration */
  --label: "PP Object Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;

  /* Tell the UA which way this surface runs, so form controls, scrollbars and
     autofill match the ground. Without it a light page on a dark-mode OS gets
     dark native inputs sitting on white panels. It has to be paired for dark
     below, exactly like the tokens. */
  color-scheme: light;

  /* ---- ground and ink (light) ---- */
  --fg: #000;
  /* The ground sits high on purpose: a light grey makes both a white plate and a
     black one pop off it, where a darker ground only flattered the black. */
  --bg: #EBEBEB;
  --paper: #fff;
  --panel: #E2E2E2;
  --hair: rgba(0, 0, 0, .07);
  /* Surfaces are SOLID, not frosted — an opaque plate on the ground, the way the
     brand ships. These two are steps AWAY from the card ground: --tint is one
     step, --tint-2 is two. They read as grey chips and tiles on a white card, and
     as lifted greys on a black one, so the direction is consistent in both themes
     even though the ground flips. Nothing samples what is behind it.

     The whole light ladder descends in ~9-point steps — 255 paper, 235 ground,
     226 panel, 220 tint, 210 tint-2 — because chips built from --tint sit BOTH on
     white cards and directly on the ground. At the old values --tint was lighter
     than the new ground and those chips disappeared into it. */
  --tint: #DCDCDC;
  --tint-2: #D2D2D2;
  /* Letterboxing behind video and audio, and the flash wipe's plate. Fixed
     black in BOTH themes — this is the absence of picture, not a ground, so it
     must not follow --paper (which flips to white and would frame the media in
     a white bar). The wipe borrows it for the same reason: the plate is the
     absence of the page, and it has to be the same black on the surface being
     left and the surface being arrived at. */
  --letterbox: #000;

  /* Secondary and tertiary ink — the roles the old flat palette called Slate and
     Gray. Derived from --fg rather than fixed, so one declaration inverts for
     dark instead of needing a paired override. Every page carrying prose needs
     these; keeping them here is what stops the two public pages drifting again. */
  --fg-2: color-mix(in srgb, var(--fg) 72%, transparent);
  --fg-3: color-mix(in srgb, var(--fg) 48%, transparent);

  /* No highlighter token. Emphasis is weight (700), not a drawn band behind the
     phrase — the band read as an underline, which is not a brand asset. */

  /* ---- accent: the Flash Gradient's two stops ---- */
  /* Ink for text and icons sitting ON an accent fill. Stays white in both themes
     — both Ink stops clear 4.5:1 against white, and --paper cannot do this job
     because it flips to black. Anything filled with --acc-a, --ui or --error
     labels itself with this. */
  --on-acc: #fff;
  /* House "Ink" — the no-artist default pair (guideline line 2981: the house pair
     is Ink; the violet-to-orange ramp was a placeholder). These are a sampled
     gradient pair, not a ground, so they are FIXED in both themes and never
     invert. They are light, not a swatch: use them for the wash, not for fills. */
  --acc-a: #0A0A14;   /* Ink — gradient dark stop */
  --acc-b: #33335A;   /* Ink — gradient light stop */

  /* Active — the interactive fill. Ink in light, and it inverts in dark because
     #0A0A14 is invisible on a black ground ("everything inverts"). --on-ui rides
     --paper, so it lands white on Ink and black on the inverted fill. */
  --ui: var(--acc-a);
  --on-ui: var(--paper);

  /* ---- functional colour ----
     Narrower meanings than generic success/warn/error. Honour them.
     success  confirms something that already happened
     caution  a window is closing, not a mistake — nothing has gone wrong yet
     error    something failed, or a field needs a fix                       */
  --success: #1F8B4C;
  --caution: #B7791B;
  --error:   #C4342B;

  /* Disabled is a tint of the ground's own ink, never a colour — an unavailable
     control has not failed, so it must not borrow --error's red. Paired for dark
     below, so it inverts instead of dissolving into a dark card. */
  --disabled-bg: rgba(0, 0, 0, .13);
  --disabled-fg: rgba(0, 0, 0, .40);

  /* ---- geometry ---- */
  --r-card: 30px;
  --r-panel: 26px;
  --r-tile: 22px;
  --r-inner: 18px;
  --r-pill: 999px;

  /* ---- depth ---- */
  --sh-panel: 0 14px 36px rgba(0, 0, 0, .10);
  --sh-lift:  0 22px 50px rgba(0, 0, 0, .15);
  --sh-float: 0 18px 44px rgba(0, 0, 0, .20);
  /* No --blur token: surfaces are solid, so nothing reads what is behind it.
     Depth is the shadow and the tonal step, not a sampled backdrop. */

  --pad: max(72px, 5vw);
}

/* Dark. Paired overrides only — everything else inherits.
   Reached two ways: explicitly, by a surface that adds .inv (the dashboard's
   theme toggle), or automatically from the OS via the media query below — which
   the three public pages opt out of with .no-auto-theme. */
html.inv {
  color-scheme: dark;
  --fg: #fff;
  --bg: #171717;
  --paper: #000;
  --panel: #1B1B1B;
  --hair: rgba(255, 255, 255, .13);
  /* Solid, as in light — the flat values the translucent whites resolved to. */
  --tint: #2A2A2A;
  --tint-2: #3E3E3E;
  /* --acc-a/--acc-b do NOT invert — a sampled gradient pair is not a ground.
     --ui does: #0A0A14 is invisible on black, so Active takes the ink instead and
     --on-ui follows --paper to #000. */
  --ui: var(--fg);
  --disabled-bg: rgba(255, 255, 255, .13);
  --disabled-fg: rgba(255, 255, 255, .42);
}

/* Follow the OS — but only for surfaces that have not opted out. The dashboard
   is the one that does follow it (and can override with its own toggle, which
   sets .no-auto-theme). The manifesto, the assessment and the privacy notice all
   carry .no-auto-theme in their markup: the brand ground is #EBEBEB with black
   and white plates on it, and an OS setting is not a reason to repaint it. */
@media (prefers-color-scheme: dark) {
  html:not(.no-auto-theme):not(.inv) {
    color-scheme: dark;
    --fg: #fff;
    --bg: #171717;
    --paper: #000;
    --panel: #1B1B1B;
    --hair: rgba(255, 255, 255, .13);
    --tint: #2A2A2A;
    --tint-2: #3E3E3E;
    --ui: var(--fg);
    --disabled-bg: rgba(255, 255, 255, .13);
    --disabled-fg: rgba(255, 255, 255, .42);
  }
}

/* --------------------------------------------------------------------------
   Atmospheric wash — the ground the solid surfaces sit on. It shows in the
   gaps between cards, not through them.
   Opt in per page with <body class="wash">, so it never forces itself onto a
   surface that hasn't been designed for it.

   Achromatic. Built from white and black only, because that is literally what
   the rule asks for: the gradient "is light, not a swatch", and light on a
   monochrome ground is white. Tinting these radials with the Ink pair put a
   blue-violet field across every page — the exact failure the ramp it replaced
   was retired for. The pair stays defined for gradient plates; the wash does not
   carry hue.

   In light it only ever SHADES. --bg is #EBEBEB because that specific grey is
   what makes a white plate and a black one both pop, so #EBEBEB has to be the
   brightest the ground gets — white glows on top of it lifted the top-left
   toward #F6F6F6 and quietly undid the choice. The light comes from the white
   cards now; the wash just lets the far corners fall away behind them. On black
   there is nothing below the ground, so there the wash lifts instead.
   -------------------------------------------------------------------------- */
.wash { position: relative; }
.wash::before {
  content: ''; position: fixed; inset: -20vh -20vw; z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(60vw 60vw at 62% 92%,  rgba(0, 0, 0, .055), transparent 66%),
    radial-gradient(52vw 52vw at 92% 14%,  rgba(0, 0, 0, .035), transparent 64%),
    radial-gradient(46vw 46vw at 10% 100%, rgba(0, 0, 0, .030), transparent 62%);
  filter: blur(30px);
}
/* On black the same light reads far stronger, so the glows drop by roughly a
   factor of five and the vignette deepens to keep the corners falling away. */
html.inv .wash::before {
  background:
    radial-gradient(46vw 46vw at 14% 8%,  rgba(255, 255, 255, .10), transparent 62%),
    radial-gradient(52vw 52vw at 88% 22%, rgba(255, 255, 255, .07), transparent 64%),
    radial-gradient(60vw 60vw at 62% 92%, rgba(0, 0, 0, .30), transparent 66%),
    radial-gradient(40vw 40vw at 32% 62%, rgba(255, 255, 255, .05), transparent 60%);
  filter: blur(30px);
}
/* Mirrored for the auto theme, like the token block above, so the pair stays
   complete. Nothing reaches it today — the only surfaces that carry .wash are the
   three public pages, and they opt out of auto-theming — but a dark surface that
   adopts the wash later should not have to rediscover these values. */
@media (prefers-color-scheme: dark) {
  html:not(.no-auto-theme):not(.inv) .wash::before {
    background:
      radial-gradient(46vw 46vw at 14% 8%,  rgba(255, 255, 255, .10), transparent 62%),
      radial-gradient(52vw 52vw at 88% 22%, rgba(255, 255, 255, .07), transparent 64%),
      radial-gradient(60vw 60vw at 62% 92%, rgba(0, 0, 0, .30), transparent 66%),
      radial-gradient(40vw 40vw at 32% 62%, rgba(255, 255, 255, .05), transparent 60%);
    filter: blur(30px);
  }
}
@media (prefers-reduced-motion: reduce) {
  .wash::before { filter: blur(30px); }  /* static either way — no animation to suppress */
}


/* --------------------------------------------------------------------------
   The flash wipe — the manifesto's exit and the assessment's entrance.

   The star belongs to the EXIT, and only to the exit. It is the Brand Hub's
   Motion chapter `expose` (brand-guideline.html, motionFrame): the production
   star grows from a seed to past the edge of the frame on the guideline's own
   in-out ease, and then the frame floods to black behind it. /join/ opens from
   that same black by simply lifting the plate.

   A star-shaped aperture on the arrival was tried and dropped. It is not that
   it did not work — it did — but two stars in nine hundred milliseconds is the
   mark performing rather than the move carrying. One gesture, one shape: the
   star closes, and the next page is already behind it. The guideline's line
   still fits, and now describes one arc rather than two: "it opens, holds, and
   never quite fades."

   The star is concave, so it can never cover a rectangle on its own: four
   wedges reach in from the corners however far it grows. That is what the flood
   is for, and it is why the exit has a second phase at all.

   Structure, identical on both pages:

     <div class="flash-wipe" aria-hidden="true">
       <span class="fw-star"></span>
       <span class="fw-flood"></span>
     </div>

   .fw-star is the exit's ink star. .fw-flood is the plate, and it carries both
   halves of the move: it fades IN behind the star on the way out, and it is the
   thing that fades OUT on the way in. That is why the arrival needs no mask, no
   compositing and no geometry — only an opacity.

   Driven by /assets/flash-wipe.js, which sets exactly three custom properties:
   --fw-x / --fw-y (where the star was struck, viewport coordinates) and --fw-h
   (its height, the one value that animates). Everything else derives here, so
   the script never has to know the artwork's proportions or restate a calc.

   The plate is --letterbox, the one token that is black in both themes: this is
   the absence of the page, exactly as the letterbox is the absence of picture,
   and it has to stay black because the document on the other side of the
   navigation opens from black regardless of which surface it is.
   -------------------------------------------------------------------------- */

/* Hidden until something plays it. On /join/ the arrival plate has to be up at
   FIRST paint — before the deferred script has run, before the flow's own
   markup is parsed — so html.fw-arriving, set by an inline <head> script, is
   what shows it. .fw-out / .fw-in are the script's own two states. */
.flash-wipe { display: none; }
html.fw-arriving .flash-wipe,
.flash-wipe.fw-out,
.flash-wipe.fw-in { display: block; }

/* Black behind the page from the first frame, so nothing light can flash
   between the plate being asked for and the plate being painted. The plate that
   does the arriving is the flood: opaque in CSS, before the script has run and
   before it has a value of its own to fade from. The star takes no part in the
   arrival, so it is not merely invisible here — it is out of the box. */
html.fw-arriving { background: var(--letterbox); }
html.fw-arriving .fw-flood,
.flash-wipe.fw-in .fw-flood { opacity: 1; }
html.fw-arriving .fw-star,
.flash-wipe.fw-in .fw-star { display: none; }

.flash-wipe {
  position: fixed; inset: 0; z-index: 2147483000;
  /* Never in the way: leaving, the page is going anyway; arriving, the flow is
     already live underneath and a stray tap must reach it. */
  pointer-events: none;
  /* Where the star was struck. Defaulted HERE and not on .fw-star, because the
     script sets them on this element and a declaration on the child would beat
     the inherited value rather than fall back to it — the star would grow from
     the middle of the screen however it was struck. */
  --fw-x: 50vw;
  --fw-y: 50vh;
}
.flash-wipe > span { position: absolute; inset: 0; display: block; background: var(--letterbox); }

.fw-star {
  /* The artwork's own width ÷ height, from the viewBox of flash-star.svg. The
     star is much taller than it is wide, which is why the height that clears a
     WIDE viewport is set by the width it needs — see reach() in the script. */
  --fw-ratio: .60308;
  --fw-h: 0px;
  /* derived, so the mask declarations below stay readable */
  --fw-w: calc(var(--fw-h) * var(--fw-ratio));
  --fw-px: calc(var(--fw-x) - var(--fw-w) / 2);
  --fw-py: calc(var(--fw-y) - var(--fw-h) / 2);

  -webkit-mask-image: url("/assets/flash-star.svg");
          mask-image: url("/assets/flash-star.svg");
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
  /* Both axes stated. `auto` would ask the engine to recover the ratio from an
     SVG that carries no width or height, and they do not all agree about that. */
  -webkit-mask-size: var(--fw-w) var(--fw-h);
          mask-size: var(--fw-w) var(--fw-h);
  -webkit-mask-position: var(--fw-px) var(--fw-py);
          mask-position: var(--fw-px) var(--fw-py);
}

/* Transparent by default: the flood is asked for, never assumed. The two rules
   that turn it on are above, next to the arrival they belong to. */
.fw-flood { opacity: 0; }

/* No motion, no wipe — the links navigate the ordinary way and /join/ never
   sets fw-arriving, so this only has to catch a preference changed mid-visit. */
@media (prefers-reduced-motion: reduce) {
  html.fw-arriving { background: var(--bg); }
  .flash-wipe { display: none !important; }
}

/* --------------------------------------------------------------------------
   Interface layer — the Brand Hub's Interface chapter components, verbatim.
   Used by the dashboard. The public pages keep their own fluid type scale and
   should not adopt these fixed sizes.
   -------------------------------------------------------------------------- */

/* The attribute has to win.
   The UA hides [hidden] with `display: none`, which is the weakest possible
   declaration — any author rule setting `display` on the same element beats it.
   `.ui-btn` below sets `display: inline-flex`, and the dashboards `.row` sets
   `display: grid`, so `el.hidden = true` on either did nothing at all: the
   element stayed on screen while every script reading it believed it was gone.
   Declared here rather than in a surface file because the rule it corrects is
   in this one. */
[hidden] { display: none !important; }

/* tracked label / eyebrow */
.ui-k {
  font-family: var(--label); font-size: 10px; letter-spacing: 0.1em;
  text-transform: uppercase; opacity: .5;
}
/* title / subtext pair */
.ui-t { font-size: 15px; font-weight: 700; letter-spacing: -0.018em; line-height: 1.25; }
.ui-s { font-size: 12.5px; line-height: 1.4; opacity: .55; margin-top: 4px; }

.ui-row { display: flex; align-items: center; gap: 11px; }

.ui-btn {
  display: inline-flex; align-items: center; gap: 8px; border-radius: var(--r-pill);
  padding: 11px 19px; font-size: 14px; font-weight: 700; letter-spacing: -0.012em;
  color: var(--on-ui); line-height: 1;
  background: var(--ui);
  border: none; cursor: pointer; font-family: var(--font);
}
.ui-btn.ghost { background: transparent; color: var(--fg); box-shadow: inset 0 0 0 1.5px currentColor; }
/* disabled is a tint of the ground's own ink, so it inverts with the theme
   instead of dissolving into a dark card */
.ui-btn.ui-off,
.ui-btn:disabled { background: var(--disabled-bg); color: var(--disabled-fg); cursor: default; box-shadow: none; }

.ui-dot { width: 9px; height: 9px; border-radius: 50%; flex: none; }

/* the status strip: a colour doing its one job, left-aligned like everything */
.ui-strip {
  display: flex; align-items: flex-start; gap: 11px; padding: 12px 14px;
  border-radius: 12px; font-size: 13px; line-height: 1.38;
}
.ui-strip b { display: block; font-size: 13.5px; letter-spacing: -0.012em; }
.ui-strip i { font-style: normal; opacity: .72; }

/* progress — uploads and recording both use this, not a new invention */
.ui-bar { height: 6px; border-radius: 99px; background: rgba(0, 0, 0, .10); overflow: hidden; }
html.inv .ui-bar { background: rgba(255, 255, 255, .14); }
/* --ui, not --acc-a: the fill has to stay visible when the ground inverts */
.ui-bar span { display: block; height: 100%; border-radius: 99px; background: var(--ui); }

.ui-field {
  margin-top: 9px; border-radius: 11px; padding: 11px 13px; font-size: 13.5px;
  /* The inset ring IS the border, which is what keeps a focused field from
     shifting its own text by a pixel. So the UA border has to go with it —
     without this every native control drew a second, squarer outline outside
     the ring, and each control type drew it at a different thickness. */
  appearance: none; -webkit-appearance: none; border: 0;
  box-shadow: inset 0 0 0 1.5px rgba(0, 0, 0, .12);
  background: transparent; color: var(--fg); font-family: var(--font); width: 100%;
}
html.inv .ui-field { box-shadow: inset 0 0 0 1.5px rgba(255, 255, 255, .16); }
.ui-field:focus { outline: none; box-shadow: inset 0 0 0 1.5px var(--ui); }

/* small readouts: word counts, sizes, durations. Data, not prose. */
.ui-hex {
  font-family: var(--label); font-size: 10.5px; opacity: .45;
  margin-top: 11px; letter-spacing: 0.03em;
}
