/*
 * Design tokens — Direction A
 * ───────────────────────────
 * Ported from design/ds/tokens/*.css, which is the design system's own source
 * of truth. Values are copied, not reinterpreted: if one looks wrong it is
 * wrong in the design system and belongs to be fixed there first.
 *
 * The rule the whole system rests on: THE FIGURE FACE MEANS READ FROM
 * INSTAGRAM'S API. Anything measured — reach, followers, engagement, prices,
 * payouts — is set in --font-data with tabular numerals. Anything a person
 * wrote stays in --font-ui. A figure iFluenz computes rather than reads (an
 * affinity score, a budget total) stays in the interface face even though it
 * is a number.
 *
 * It used to be phrased "mono means read", when --font-data was IBM Plex
 * Mono. Chivo took its place on 21 August 2026 and is a grotesque, so the
 * rule is named by its job rather than by the shape of the face.
 *
 * The two faces are linked from resources/views/index.blade.php rather than
 * imported here: a CSS @import has to come first in its file, and this one is
 * concatenated after Bootswatch.
 *
 * CSS custom properties on purpose: they resolve in the browser, so they
 * survive the move to Vue 3 and Vite untouched.
 */
/* ── colors ────────────────────────────────────────────────────────── */
/* Colour — direction A, validée sur la homepage, CreatorSearch, le dashboard
 * créateur mobile et le vocabulaire de motion.
 *
 * Trois valeurs portent l'interface : un blanc cassé, une encre très sombre et
 * un accent rare. La couleur vient des visuels créateurs, pas d'une palette
 * décorative. Les couleurs fonctionnelles — erreur, alerte, statut — restent
 * franches : le principe interdit la décoration, pas l'information. */
:root {
  /* Ground and surface. A tile is white on the plane; a well is tint on white.
     The hairline exists for real divisions only, never as layout structure. */
  --ground: #F8F8F7;
  --surface: #FFFFFF;
  --surface-tint: #EFEFEE;
  /* wells, table headers, inputs at rest */
  --surface-hover: #E7E7E6;
  --hairline: #E2E2E1;
  /* Ink. A dark slate, not pure black — it holds headings and every primary
     action. Colour is not how this interface says "press me". */
  --ink: #252C34;
  --ink-hover: #1B2128;
  /* the primary action, pressed on */
  --ink-soft: #4C555E;
  --ink-muted: #5F6A73;
  /* 5.0:1 on white, 4.7:1 on the ground */
  --ink-faint: #9AA1A9;
  /* decoration only — rules, guides. Never text. */
  --ink-inverse: #FFFFFF;
  /* The ink band: a full-bleed dark section, one every two or three sections
     on expressive surfaces, one per screen at most in the tool. */
  --ink-raise: #2F383F;
  /* a surface lifted off the ink band */
  --ink-line: #3C464D;
  /* a division inside the ink band */
  --on-ink: #F5F6F6;
  --on-ink-muted: #9AA3AC;
  /* 4.6:1 on --ink */
  /* Brand. The 2018 green, kept: it is what people who knew iFluenz recognise,
     and it is the dot of the logotype. It means MEASURED — a figure read from
     the API. Two forms: the full highlight behind one word, once per expressive
     screen; and the 5px provenance dot, which is the only form used in the tool.
     Too light to carry white text — never a button fill, never a heading. */
  --brand: #7DBF41;
  --brand-ink: #4E7A21;
  /* the brand as type on white, 5.0:1 */
  --brand-wash: #EFF7E4;
  /* Soft tints — for sorting things at a glance: a status, a category, a tile
     icon. Pale enough to sit under near-black text without shouting. */
  --tint-mint: #EAF4DC;
  --tint-mint-ink: #41661B;
  --tint-peach: #FCEEE4;
  --tint-peach-ink: #8A4A20;
  --tint-lilac: #EFEBFB;
  --tint-lilac-ink: #4B3A94;
  --tint-sky: #E7F0FD;
  --tint-sky-ink: #1F4C93;
  --tint-sand: #F5F1E8;
  --tint-sand-ink: #6E5A2A;
  --tint-rose: #FDEBEC;
  --tint-rose-ink: #99312F;
  /* Functional. Frank and legible — these are not decoration. */
  --flag: #F2665F;
  /* the attention dot */
  --flag-ink: #B93B33;
  /* error type and rings */
  --flag-wash: #FDEBEA;
  --warn: #B8730A;
  /* the marker: a dot, a rule, an icon — not text */
  --warn-ink: #8F5A08;
  /* alert type on --warn-wash, 4.9:1 */
  --warn-wash: #FBF0DE;
  /* The one control that goes to Instagram, and nothing else. */
  --instagram: linear-gradient(90deg, #F58529, #DD2A7B 45%, #8134AF 80%, #515BD4);
  /* @kind color */
  /* Ink at 35%, the veil behind a dialog or the open rail. */
  --scrim: rgba(37, 44, 52, 0.35);
}
/* ── typography ────────────────────────────────────────────────────────── */
/* Type — Schibsted Grotesk for the voice, Chivo for what was read.
 *
 * The signature: anything READ FROM THE API is set in the figure face with
 * tabular numerals. Written things — names, labels, prose — and anything
 * iFluenz COMPUTES rather than reads (an affinity score) stay in the
 * interface face. A reader learns within one screen that this face means
 * "this is a reading", which is what iFluenz sells.
 *
 * Chivo replaced IBM Plex Mono on 21 August 2026. It is a grotesque, not a
 * monospace, so the rule is no longer "mono means read" but "the figure face
 * means read". Its numerals are equal-width by design, so a column lines up
 * on its own; tabular-nums is still declared everywhere because the fallback
 * is Schibsted Grotesk, whose figures are proportional.
 *
 * Heavy is for display and for figures. Body and labels stay at regular or
 * medium: maximum weight everywhere is what makes a grotesque unreadable. */
:root {
  --font-ui: 'Schibsted Grotesk', -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
  --font-data: 'Chivo', 'Schibsted Grotesk', -apple-system, BlinkMacSystemFont, Helvetica, Arial, sans-serif;
  --text-xs: 0.75rem;
  /* 12 — the tiny label under a giant figure */
  --text-sm: 0.8125rem;
  /* 13 — dense rows and cards */
  --text-base: 0.9375rem;
  /* 15 — body */
  --text-md: 1.0625rem;
  /* 17 */
  --text-lg: 1.375rem;
  /* 22 */
  --text-xl: 2rem;
  /* 32 — a page title, a mobile greeting */
  --text-2xl: 2.75rem;
  /* 44 — a figure a decision turns on */
  --text-3xl: 3.5rem;
  /* 56 — one per screen, at most */
  --text-4xl: 4rem;
  /* 64 — expressive section titles */
  --text-display: clamp(3.25rem, 6.1vw, 5.875rem);
  /* the marketing headline */
  --weight-regular: 400;
  --weight-medium: 520;
  --weight-strong: 620;
  --weight-heavy: 800;
  --weight-black: 900;
  /* display only, never below 32px */
  --leading-tight: 1.03;
  /* display */
  --leading-snug: 1.35;
  --leading-normal: 1.6;
  --tracking-display: -0.045em;
  --tracking-tight: -0.035em;
  --tracking-snug: -0.012em;
  --tracking-normal: 0;
  --tracking-wide: 0.1em;
  /* Figures: tabular, so a column of them lines up. Chivo's numerals are
     already equal-width; this is what keeps the fallback honest. There is no
     slashed zero — Chivo does not draw one. */
  --numeric-figures: tabular-nums;
  /* @kind other */
}
/* ── spacing ────────────────────────────────────────────────────────── */
/* Space — ported from sass/_tokens.less
 * Roomier than a dense admin, because air is most of what makes this look
 * considered rather than crowded. */
:root {
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.5rem;
  --space-6: 2rem;
  --space-7: 3rem;
  --space-8: 4.5rem;
  --space-9: 7rem;
  --row-height: 3rem;
  --row-height-tight: 2.5rem;
  --control-height: 2.5rem;
  /* Layout constants read off the primitives. */
  --rail-width: 15rem;
  --rail-width-mobile: 17rem;
  --plane-max: 62rem;
  --breakpoint-rail: 60rem;
}
/* ── form ────────────────────────────────────────────────────────── */
/* Form — radii and shadow.
 * The radius scale is derived from the product's native frame: the post and the
 * story, 4:5 and 9:16 with generously rounded corners. The frame keeps the
 * largest radius and every smaller object steps down, so a filter chip is not a
 * scaled-up post. A single value applied mechanically makes dense UI go soft.
 * Depth comes from tint, not from shadow. */
:root {
  --radius-dense: 6px;
  /* filter chips, table cells, grid thumbnails */
  --radius-sm: 10px;
  /* inputs, buttons that are not pills, small plates */
  --radius: 16px;
  /* cards and panels */
  --radius-lg: 20px;
  /* the media frame and full-width blocks */
  --radius-xl: 24px;
  /* dialogs */
  --radius-pill: 999px;
  /* status pills and round buttons only */
  --shadow-sm: 0 1px 2px rgba(37, 44, 52, 0.04);
  --shadow: 0 2px 10px rgba(37, 44, 52, 0.06);
  --shadow-lg: 0 14px 40px rgba(37, 44, 52, 0.14);
  /* Focus is a 2px ring, not a border change — a border change moves layout. */
  --ring: 0 0 0 2px var(--ink);
  --ring-brand: 0 0 0 2px var(--brand-ink);
  --ring-invalid: 0 0 0 2px var(--flag-ink);
}
/* ── motion ────────────────────────────────────────────────────────── */
/* Motion — one curve, four durations.
 * Two things justify a movement here: the product is ALIVE (creator content)
 * and CREDIBLE (figures read from the API). A gesture that serves neither does
 * not ship. Expressive surfaces may stage a movement; in the tool a gesture
 * only reports what just changed, and nothing above 200ms is allowed. */
:root {
  --ease: cubic-bezier(0.2, 0.8, 0.2, 1);
  /* @kind other */
  --duration-fast: 130ms;
  /* hover, focus, tint, a message under a field @kind other */
  --duration: 200ms;
  /* an object that moves or arrives @kind other */
  --duration-slow: 340ms;
  /* a value that fills, a marker that lands @kind other */
  --duration-stage: 560ms;
  /* expressive only: UI entering a photograph @kind other */
  --z-sticky: 100;
  /* @kind other */
  --z-overlay: 900;
  /* @kind other */
  --z-modal: 1000;
  /* @kind other */
  --z-toast: 1100;
  /* @kind other */
}
/* Reduced motion is not "less animation", it is no travel at all. Every gesture
   in this system has an arrival state that stands on its own. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --duration-fast: 0ms;
    /* @kind other */
    --duration: 0ms;
    /* @kind other */
    --duration-slow: 0ms;
    /* @kind other */
    --duration-stage: 0ms;
    /* @kind other */
  }
}
/*
 * The same palette for the Bootstrap-era LESS still in the tree, so screens
 * that have not been rebuilt are at least the right colour.
 *
 * Literal values rather than var(): _variables.less runs darken() and
 * lighten() on @brand-success, and LESS cannot compute on a custom property.
 * Kept in step by hand, and both go when Bootstrap does.
 */
/*
 * Base — element defaults
 * ───────────────────────
 * Ported from design/ds/styles/base.css.
 *
 * Bootstrap 3 sets `html { font-size: 10px }` so that its own px values line
 * up with a 10px rem. Every token here is in rem, so on that page 1rem was
 * 10px and the whole design layer rendered at 62.5% — body copy at 9.4px, a
 * 62rem column at 620px. Back to the browser's own size; Bootstrap 3 itself
 * uses almost no rem, so nothing of its own moves.
 */
/* Base — ported from sass/app.less (the design-layer half; the Bootstrap-era
 * overrides in that file are not part of this system). */
html {
  font-size: 100%;
}
body {
  font-family: var(--font-ui);
  font-size: var(--text-base);
  line-height: var(--leading-normal);
  letter-spacing: var(--tracking-normal);
  color: var(--ink);
  background: var(--ground);
  -webkit-font-smoothing: antialiased;
}
h1,
h2,
h3,
h4 {
  color: var(--ink);
  font-weight: var(--weight-strong);
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-tight);
  text-transform: none;
  text-wrap: balance;
}
h1 {
  font-size: var(--text-xl);
}
h2 {
  font-size: var(--text-lg);
}
h3 {
  font-size: var(--text-md);
}
h4 {
  font-size: var(--text-base);
}
/* Every page title used to be uppercase, bold and brand green. A heading is
   found by its size and its position; shouting it in the accent colour spends
   the one thing on the page that should mean "this is the action". */
a {
  color: var(--brand-ink);
  text-underline-offset: 2px;
  transition: color var(--duration-fast) var(--ease);
}
a:hover,
a:focus {
  color: var(--ink);
}
:focus-visible {
  outline: 2px solid var(--brand-ink);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}
/* Measured figures, wherever they are not already in a primitive. */
.if-num {
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
}
/*
 * Primitives — the `if-*` classes
 * ───────────────────────────────
 * Ported from design/ds/styles/primitives.css, class names and values
 * unchanged. Prefixed `if-` so it can sit beside Bootstrap without either
 * winning by accident during the changeover.
 *
 * Nothing here carries a literal colour; everything reads from _tokens.less.
 *
 * The Vue components in resources/assets/js/components/ds/ wrap these classes
 * one for one. Prefer the component; reach for the class directly only inside
 * a screen that is doing something the component does not cover.
 */
/* Primitives — plain-CSS port of sass/_primitives.less, class names and values
 * unchanged. Prefixed `if-` so it can sit beside Bootstrap without either
 * winning by accident during the changeover.
 *
 * Nothing here carries a literal colour; everything reads from tokens. */
/* ══ SHELL ═══════════════════════════════════════════════════════════════
 * A white rail beside a grey plane. No border between them: the change of
 * tint is the division, which is the single habit that makes this read as
 * considered rather than boxed-in. */
.if-shell {
  display: flex;
  min-height: 100vh;
  background: var(--ground);
  color: var(--ink);
  font-family: var(--font-ui);
}
.if-rail {
  width: var(--rail-width);
  flex: none;
  padding: var(--space-5) var(--space-3);
  background: var(--surface);
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
}
.if-rail__mark {
  display: block;
  padding: 0 var(--space-3);
}
.if-rail__mark img {
  display: block;
  width: 6.5rem;
  height: auto;
}
.if-rail__group {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
/* What a group of links is for. Small, quiet, sentence case: the old rail
   shouted every section in uppercase brand green. */
.if-rail__label {
  padding: 0 var(--space-3) var(--space-2);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  color: var(--ink-muted);
}
.if-rail__link {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: var(--control-height);
  padding: 0 var(--space-3);
  border-radius: var(--radius);
  color: var(--ink-soft);
  font-size: var(--text-base);
  font-weight: var(--weight-medium);
  text-decoration: none;
  transition: background var(--duration-fast) var(--ease), color var(--duration-fast) var(--ease);
}
.if-rail__link:hover {
  background: var(--surface-tint);
  color: var(--ink);
}
/* Where you are: a filled pill, not a coloured bar. */
.if-rail__link.is-current,
.if-rail__link.active {
  background: var(--surface-tint);
  color: var(--ink);
}
.if-rail__text {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* A figure in the rail is measured like any other. */
.if-rail__count {
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
  font-size: var(--text-xs);
  color: var(--ink-muted);
}
.if-rail__avatar {
  width: 1.5rem;
  height: 1.5rem;
  border-radius: 50%;
  object-fit: cover;
  background: var(--surface-tint);
  flex: none;
}
/* Needs attention. A dot with a name on it, never a pulsing icon whose
   meaning lives in a tooltip. */
.if-rail__flag {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--flag);
  flex: none;
}
.if-rail__divider {
  height: 1px;
  background: var(--hairline);
  margin: 0 var(--space-3);
}
/* A component root has to be a single element, and that wrapper would
   otherwise become the shell's flex child. */
.if-rail-host {
  display: contents;
}
.if-rail-toggle {
  display: none;
  position: fixed;
  top: var(--space-4);
  left: var(--space-4);
  z-index: var(--z-modal);
  width: var(--control-height);
  height: var(--control-height);
  align-items: center;
  justify-content: center;
  border: 0;
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink);
  box-shadow: var(--shadow);
  cursor: pointer;
}
.if-rail-veil {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 899;
  background: var(--scrim);
}
/* Below the breakpoint the rail slides in over the plane. It used to become a
   full-width block pushed above the content, so every screen on a phone opened
   on a menu. */
@media (max-width: 60rem) {
  .if-rail {
    position: fixed;
    inset: 0 auto 0 0;
    z-index: var(--z-overlay);
    width: var(--rail-width-mobile);
    transform: translateX(-100%);
    transition: transform var(--duration) var(--ease);
    box-shadow: var(--shadow-lg);
    overflow-y: auto;
  }
  .if-rail.is-open {
    transform: none;
  }
  .if-rail-toggle {
    display: flex;
  }
  .if-rail-veil.is-open {
    display: block;
  }
}
.if-plane {
  flex: 1;
  min-width: 0;
  padding: var(--space-6) var(--space-6) var(--space-9);
}
.if-plane__inner {
  max-width: var(--plane-max);
  margin: 0 auto;
}
/* ══ WELCOME ═════════════════════════════════════════════════════════════
 * A screen opens by addressing the person using it, in the largest type on the
 * page, followed by the one thing they came to do. */
.if-welcome {
  text-align: center;
  padding: var(--space-8) 0 var(--space-7);
}
.if-welcome h1 {
  margin: 0;
  font-size: var(--text-xl);
  font-weight: var(--weight-heavy);
  letter-spacing: var(--tracking-tight);
  line-height: var(--leading-tight);
}
@media (min-width: 48rem) {
  .if-welcome h1 {
    font-size: 2.75rem;
  }
}
.if-search {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  width: 100%;
  max-width: 40rem;
  margin: var(--space-6) auto 0;
  height: 3.5rem;
  padding: 0 var(--space-5);
  border-radius: var(--radius-pill);
  background: var(--surface);
  box-shadow: var(--shadow-sm);
}
.if-search input {
  flex: 1;
  border: 0;
  background: none;
  font: inherit;
  font-size: var(--text-md);
  color: var(--ink);
}
.if-search input::placeholder {
  color: var(--ink-muted);
}
.if-search input:focus {
  outline: none;
}
.if-search__key {
  font-family: var(--font-data);
  font-size: var(--text-xs);
  color: var(--ink-muted);
}
/* ══ TILES ═══════════════════════════════════════════════════════════════
 * What the product can do, laid out as a row rather than hidden in a menu.
 * A soft square of colour, a name, and one line saying what it is for — no
 * card, no border, just space. */
.if-tiles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: var(--space-5);
}
.if-tile {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  text-decoration: none;
  color: inherit;
}
.if-tile__icon {
  width: 3rem;
  height: 3rem;
  display: grid;
  place-items: center;
  border-radius: var(--radius);
  font-size: var(--text-lg);
  transition: transform var(--duration) var(--ease);
}
.if-tile:hover .if-tile__icon {
  transform: translateY(-2px);
}
.if-tile__name {
  font-weight: var(--weight-strong);
  letter-spacing: var(--tracking-snug);
}
.if-tile__desc {
  font-size: var(--text-sm);
  color: var(--ink-muted);
  line-height: var(--leading-snug);
}
.if-tile.on-mint .if-tile__icon {
  background: var(--tint-mint);
  color: var(--tint-mint-ink);
}
.if-tile.on-peach .if-tile__icon {
  background: var(--tint-peach);
  color: var(--tint-peach-ink);
}
.if-tile.on-lilac .if-tile__icon {
  background: var(--tint-lilac);
  color: var(--tint-lilac-ink);
}
.if-tile.on-sky .if-tile__icon {
  background: var(--tint-sky);
  color: var(--tint-sky-ink);
}
.if-tile.on-sand .if-tile__icon {
  background: var(--tint-sand);
  color: var(--tint-sand-ink);
}
.if-tile.on-rose .if-tile__icon {
  background: var(--tint-rose);
  color: var(--tint-rose-ink);
}
/* ══ PANELS ══════════════════════════════════════════════════════════════
 * A block of content on its own ground. No border — the tint does it. */
.if-panel {
  background: var(--surface);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
}
.if-panel.is-sunk {
  background: var(--surface-tint);
}
.if-panel.is-interactive {
  cursor: pointer;
  transition: transform var(--duration) var(--ease), box-shadow var(--duration) var(--ease);
}
.if-panel.is-interactive:hover {
  transform: translateY(-3px);
  box-shadow: var(--shadow);
}
.if-panel__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
}
.if-panel__title {
  font-weight: var(--weight-strong);
  letter-spacing: var(--tracking-snug);
}
/* A creator's work, edge to edge, with the panel's corners. */
.if-plate {
  display: block;
  width: 100%;
  aspect-ratio: 1.5;
  object-fit: cover;
  background: var(--surface-tint);
  border-radius: var(--radius);
}
/* ══ THE SIGNATURE ═══════════════════════════════════════════════════════
 * Measured figures are set in the figure face with tabular numerals. Written
 * things stay in the interface face. Within a screen a reader learns that this face means
 * "read from the API" — which is exactly what the old scraped numbers were
 * not, and what the product now sells. */
.if-measure {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}
.if-measure__value {
  font-family: var(--font-data);
  font-size: var(--text-2xl);
  font-weight: var(--weight-medium);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.005em;
  line-height: var(--leading-tight);
}
.if-measure__unit {
  font-size: 0.42em;
  color: var(--ink-muted);
  margin-left: 0.12em;
}
.if-measure__label {
  font-size: var(--text-sm);
  color: var(--ink-muted);
}
.if-measure--sm .if-measure__value {
  font-size: var(--text-lg);
}
/* What a brand decided on, against what actually happened. No competitor
 * without first-party data can put these two numbers side by side, so they get
 * the largest type on the screen and nothing else competes. */
.if-outcome {
  display: flex;
  align-items: baseline;
  gap: var(--space-3);
  flex-wrap: wrap;
}
.if-outcome__actual {
  font-family: var(--font-data);
  font-size: var(--text-3xl);
  font-weight: var(--weight-medium);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.012em;
  line-height: var(--leading-tight);
}
.if-outcome__estimate {
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
  font-size: var(--text-md);
  color: var(--ink-muted);
  text-decoration: line-through;
}
.if-outcome__delta {
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
  font-size: var(--text-sm);
  padding: 0.1rem var(--space-2);
  border-radius: var(--radius-pill);
  background: var(--brand-wash);
  color: var(--brand-ink);
}
/* The provenance marker, in its two forms. The full highlight goes behind ONE
 * word, once per expressive screen; the dot is the discreet form and the only
 * one allowed in the tool — in front of a reading time, or in a column header
 * to say the whole column was read. Both mean the same thing: this came from
 * the API. A figure iFluenz computes never carries either. */
.if-mark {
  background: var(--brand);
  color: var(--ink);
  padding: 0 0.08em;
  border-radius: 4px;
  box-decoration-break: clone;
  -webkit-box-decoration-break: clone;
}
.if-read {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
  font-size: var(--text-xs);
  color: var(--ink-muted);
}
.if-read::before,
.if-col-read::before {
  content: "";
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--brand);
  flex: none;
}
.if-col-read {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
/* A rate sits on a scale, so it gets one. A raw count does not, so it does
 * not — that would be decoration. */
.if-scale {
  height: 4px;
  border-radius: 2px;
  background: var(--surface-tint);
  overflow: hidden;
}
.if-scale__fill {
  height: 100%;
  border-radius: 2px;
  background: var(--brand);
  transition: width var(--duration-slow) var(--ease);
}
/* ══ CONTROLS ════════════════════════════════════════════════════════════
 * Accept, decline and undo — the three gestures the whole product turns on —
 * were spans with a tooltip and two stacked icons: no label, nothing a
 * keyboard could reach. */
.if-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  height: var(--control-height);
  padding: 0 var(--space-5);
  border: 0;
  border-radius: var(--radius-pill);
  background: var(--surface-tint);
  color: var(--ink);
  font: inherit;
  font-size: var(--text-base);
  font-weight: var(--weight-medium);
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  text-decoration: none;
  transition: background var(--duration-fast) var(--ease), transform var(--duration-fast) var(--ease), opacity var(--duration-fast) var(--ease);
}
.if-btn:hover:not([disabled]) {
  background: var(--surface-hover);
}
.if-btn:active {
  transform: translateY(1px);
}
.if-btn[disabled],
.if-btn.is-disabled {
  opacity: 0.4;
  cursor: not-allowed;
  transform: none;
}
/* Black, not brand-coloured. Colour is not how this interface says "press me" —
   weight and contrast are, which leaves the brand colour free to mean
   something. */
.if-btn--primary {
  background: var(--ink);
  color: var(--ink-inverse);
  font-weight: var(--weight-strong);
}
.if-btn--primary:hover:not([disabled]) {
  background: var(--ink-hover);
}
/* The one action that commits to a figure being paid for and reported on.
   Ink on the green, never white: the brand green is too light to carry white
   text (2.2:1) and the highlight it descends from has always been ink on green. */
.if-btn--brand {
  background: var(--brand);
  color: var(--ink);
  font-weight: var(--weight-strong);
}
.if-btn--brand:hover:not([disabled]) {
  background: #72B037;
  color: var(--ink);
}
.if-btn--quiet {
  background: transparent;
  color: var(--ink-soft);
}
.if-btn--quiet:hover:not([disabled]) {
  background: var(--surface-tint);
  color: var(--ink);
}
.if-btn--danger {
  background: var(--tint-rose);
  color: var(--tint-rose-ink);
}
.if-btn--sm {
  height: 2rem;
  padding: 0 var(--space-4);
  font-size: var(--text-sm);
}
.if-btn--block {
  display: flex;
  width: 100%;
}
/* Instagram's gradient, once, on the one control that goes to Instagram. */
.if-btn--instagram {
  background: var(--instagram);
  color: var(--ink-inverse);
}
.if-btn--instagram:hover:not([disabled]) {
  background: var(--instagram);
  filter: brightness(1.06);
  color: var(--ink-inverse);
}
.if-field {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.if-field > label {
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  color: var(--ink-soft);
  margin: 0;
}
.if-input {
  height: var(--control-height);
  padding: 0 var(--space-4);
  border: 0;
  border-radius: var(--radius-sm);
  background: var(--surface-tint);
  color: var(--ink);
  font: inherit;
  font-size: var(--text-base);
  transition: box-shadow var(--duration-fast) var(--ease), background var(--duration-fast) var(--ease);
}
.if-input::placeholder {
  color: var(--ink-muted);
}
.if-input:hover {
  background: var(--surface-hover);
}
.if-input:focus {
  outline: none;
  background: var(--surface);
  box-shadow: var(--ring);
}
/* An amount is measured too, so it is typed in the face it is read in. */
.if-input--amount {
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
}
textarea.if-input {
  height: auto;
  padding: var(--space-3) var(--space-4);
  line-height: var(--leading-snug);
}
.if-field__error {
  font-size: var(--text-sm);
  color: var(--flag-ink);
}
.if-field.is-invalid .if-input {
  box-shadow: var(--ring-invalid);
}
/* Status always carries a word. It was a coloured square with an inline style
 * and no label, which tells a colour-blind reader nothing. */
.if-pill {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: 0.2rem var(--space-3);
  border-radius: var(--radius-pill);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  line-height: 1.5;
  white-space: nowrap;
}
.if-pill::before {
  content: "";
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: currentColor;
  flex: none;
}
.if-pill--neutral {
  background: var(--surface-tint);
  color: var(--ink-soft);
}
.if-pill--live {
  background: var(--tint-mint);
  color: var(--tint-mint-ink);
}
.if-pill--talking {
  background: var(--tint-sky);
  color: var(--tint-sky-ink);
}
.if-pill--hold {
  background: var(--tint-peach);
  color: var(--tint-peach-ink);
}
.if-pill--flag {
  background: var(--tint-rose);
  color: var(--tint-rose-ink);
}
/* ══ STATES ══════════════════════════════════════════════════════════════
 * Replaces the full-screen veil. There were 169 of those and no skeletons: the
 * shell disappeared on every navigation, which is the one thing the products
 * this is measured against never do. */
.if-skeleton {
  background: linear-gradient(90deg, var(--surface-tint) 25%, var(--surface-hover) 37%, var(--surface-tint) 63%);
  background-size: 400% 100%;
  border-radius: var(--radius-sm);
  animation: if-shimmer 1.6s ease infinite;
}
.if-skeleton--text {
  height: 0.7em;
  margin: 0.3em 0;
}
.if-skeleton--title {
  height: 1.1em;
  width: 45%;
}
.if-skeleton--avatar {
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 50%;
}
.if-skeleton--plate {
  width: 100%;
  aspect-ratio: 1.5;
  border-radius: var(--radius);
}
@keyframes if-shimmer {
  from {
    background-position: 100% 50%;
  }
  to {
    background-position: 0 50%;
  }
}
@media (prefers-reduced-motion: reduce) {
  .if-skeleton {
    animation: none;
  }
}
/* 27 of 85 routes said anything when they had nothing to show. An empty list
 * is a moment to explain what would fill it. */
.if-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-7) var(--space-4);
  text-align: center;
}
.if-empty__title {
  font-size: var(--text-md);
  font-weight: var(--weight-strong);
}
.if-empty__body {
  max-width: 44ch;
  color: var(--ink-muted);
  line-height: var(--leading-normal);
}
/* Replaces 310 blocking confirmations. A confirmation should say what happened
 * and get out of the way. */
.if-toasts {
  position: fixed;
  right: var(--space-5);
  bottom: var(--space-5);
  z-index: var(--z-toast);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  pointer-events: none;
}
.if-toast {
  pointer-events: auto;
  display: flex;
  gap: var(--space-3);
  min-width: 18rem;
  max-width: 26rem;
  padding: var(--space-4);
  border-radius: var(--radius);
  background: var(--ink);
  color: var(--ink-inverse);
  box-shadow: var(--shadow-lg);
  font-size: var(--text-base);
}
.if-toast__title {
  font-weight: var(--weight-medium);
}
.if-toast__detail {
  color: var(--ink-faint);
  font-size: var(--text-sm);
}
.if-toast__dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  margin-top: 0.45rem;
  flex: none;
  background: var(--ink-faint);
}
.if-toast--live .if-toast__dot {
  background: var(--brand);
}
.if-toast--flag .if-toast__dot {
  background: var(--flag);
}
/* Ours, so vue-js-modal can go. */
.if-overlay {
  position: fixed;
  inset: 0;
  z-index: var(--z-modal);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-4);
  background: var(--scrim);
  backdrop-filter: blur(4px);
}
.if-dialog {
  width: 100%;
  max-width: 34rem;
  max-height: calc(100vh - var(--space-7));
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
}
.if-dialog__header {
  padding: var(--space-5) var(--space-5) var(--space-3);
}
.if-dialog__title {
  font-size: var(--text-lg);
  font-weight: var(--weight-strong);
  letter-spacing: var(--tracking-snug);
}
.if-dialog__body {
  padding: 0 var(--space-5) var(--space-5);
  overflow-y: auto;
}
.if-dialog__footer {
  padding: var(--space-4) var(--space-5);
  background: var(--surface-tint);
  display: flex;
  justify-content: flex-end;
  gap: var(--space-2);
}
/* Creators work from their phone. The desktop dialog dropped into a 320px
   viewport is how that half of the product currently feels. */
@media (max-width: 40rem) {
  .if-overlay {
    padding: 0;
    align-items: flex-end;
  }
  .if-dialog {
    max-width: none;
    align-self: flex-end;
    border-radius: var(--radius-xl) var(--radius-xl) 0 0;
  }
}
/* LESS 2.7 tries to resolve the subtraction inside calc() and cannot, because
 * one side is a custom property it has no value for. The ~"…" escape hands the
 * string through untouched. It goes when the build moves to Vite. */
/* ══ DATA ════════════════════════════════════════════════════════════════ */
.if-table-wrap {
  overflow-x: auto;
  background: var(--surface);
  border-radius: var(--radius-lg);
}
.if-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--text-base);
}
.if-table th,
.if-table td {
  padding: 0 var(--space-5);
  height: var(--row-height);
  text-align: left;
}
.if-table tbody td {
  border-top: 1px solid var(--hairline);
}
.if-table thead th {
  position: sticky;
  top: 0;
  z-index: var(--z-sticky);
  height: var(--row-height-tight);
  background: var(--surface);
  color: var(--ink-muted);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  white-space: nowrap;
}
.if-table tbody tr:hover {
  background: var(--surface-tint);
}
/* Measured columns keep the figure face they have everywhere else. A missing
   figure is a dash: a campaign that reached nobody has no cost per thousand,
   and nought would read as free. */
.if-table .if-num {
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
  text-align: right;
  white-space: nowrap;
}
.if-table .if-none {
  color: var(--ink-muted);
}
/* ══ CHIPS ═══════════════════════════════════════════════════════════════
 * How choosing is done here: a pill with an icon and a word, tapped on or off.
 * Targeting a campaign is a set of choices, and a row of pills says so at a
 * glance where a stack of dropdowns hides it. */
.if-chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
}
.if-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  height: 2.75rem;
  padding: 0 var(--space-5);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-pill);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: var(--text-base);
  font-weight: var(--weight-medium);
  cursor: pointer;
  transition: background var(--duration-fast) var(--ease), border-color var(--duration-fast) var(--ease), transform var(--duration-fast) var(--ease);
}
.if-chip:hover {
  background: var(--surface-tint);
}
.if-chip:active {
  transform: translateY(1px);
}
.if-chip.is-selected {
  background: var(--surface-tint);
  border-color: transparent;
  font-weight: var(--weight-strong);
}
/* ══ PROGRESS ════════════════════════════════════════════════════════════
 * A hairline at the very top of the screen. */
.if-progress {
  height: 3px;
  border-radius: 2px;
  background: var(--surface-tint);
  overflow: hidden;
}
.if-progress__fill {
  height: 100%;
  background: var(--brand);
  transition: width var(--duration-slow) var(--ease);
}
/* ══ ASK ═════════════════════════════════════════════════════════════════
 * One question per screen, in the largest type on it, with room around it.
 * Deciding who a campaign should reach deserves this more than a form does. */
.if-ask {
  max-width: 46rem;
  margin: 0 auto;
  padding: var(--space-9) 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
}
.if-ask h2 {
  margin: 0;
  font-size: var(--text-xl);
  font-weight: var(--weight-heavy);
  letter-spacing: var(--tracking-tight);
  line-height: var(--leading-tight);
}
.if-ask__note {
  color: var(--ink-soft);
  font-size: var(--text-md);
  margin: 0;
}
.if-ask__actions {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-top: var(--space-4);
}
/* ══ SPLIT ═══════════════════════════════════════════════════════════════
 * Signing in and connecting an account: one half holding a statement, the form
 * centred in the other. */
.if-split {
  display: grid;
  min-height: 100vh;
  grid-template-columns: 1fr;
  background: var(--surface);
}
@media (min-width: 60rem) {
  .if-split {
    grid-template-columns: 1fr 1fr;
  }
}
/* The half beside the form. It held a marketing photograph; the ones in the
   tree are the 2018 campaign shots, and this is the first screen anyone —
   including a Meta reviewer — sees. The brand's own ground says the same thing
   and cannot embarrass us. */
.if-split__art {
  display: none;
  background: var(--ink);
  color: var(--ink-inverse);
  padding: var(--space-8);
  flex-direction: column;
  justify-content: flex-end;
  gap: var(--space-5);
}
.if-split__art-mark {
  width: 8rem;
  height: auto;
}
.if-split__art-line {
  margin: 0;
  max-width: 18ch;
  font-size: 2.25rem;
  font-weight: var(--weight-heavy);
  letter-spacing: var(--tracking-tight);
  line-height: var(--leading-tight);
  text-wrap: balance;
}
.if-split__art-note {
  margin: 0;
  max-width: 34ch;
  color: var(--ink-faint);
  line-height: var(--leading-normal);
}
@media (min-width: 60rem) {
  .if-split__art {
    display: flex;
  }
}
.if-split__form {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--space-5);
  padding: var(--space-7) var(--space-6);
  max-width: 26rem;
  width: 100%;
  margin: 0 auto;
  text-align: center;
}
.if-split__form h1 {
  margin: 0;
  font-size: var(--text-lg);
  font-weight: var(--weight-heavy);
  letter-spacing: var(--tracking-snug);
}
.if-split__legal {
  font-size: var(--text-sm);
  color: var(--ink-muted);
  line-height: var(--leading-normal);
}
/* ══ TRANSITIONS ═════════════════════════════════════════════════════════
 * Named for Vue's <transition>. Fades and short travels only — the system
 * has no bounce, no spring and no spin. Both collapse to nothing under
 * prefers-reduced-motion, because --duration is 0ms there.
 */
.if-fade-enter-active,
.if-fade-leave-active {
  transition: opacity var(--duration) var(--ease);
}
.if-fade-enter,
.if-fade-leave-to {
  opacity: 0;
}
.if-toast-enter-active,
.if-toast-leave-active {
  transition: opacity var(--duration) var(--ease), transform var(--duration) var(--ease);
}
.if-toast-enter,
.if-toast-leave-to {
  opacity: 0;
  transform: translateY(0.5rem);
}
.if-dialog-enter-active,
.if-dialog-leave-active {
  transition: opacity var(--duration) var(--ease);
}
.if-dialog-enter .if-dialog,
.if-dialog-leave-to .if-dialog {
  transform: translateY(0.75rem);
}
.if-dialog-enter,
.if-dialog-leave-to {
  opacity: 0;
}
.if-dialog .if-dialog {
  transition: transform var(--duration) var(--ease);
}
/* ══ A FEW THINGS THE SCREENS NEED AND THE SYSTEM DOES NOT NAME ══════════
 * Kept deliberately short. Anything that grows past a few lines belongs in
 * the design system as a real primitive, not here.
 */
/* A chip that cannot be chosen — the fifth interest when four is the limit.
 * The system names a disabled state for buttons and fields; a chip is a
 * button, so it takes the same one. */
.if-chip[disabled] {
  opacity: 0.4;
  cursor: not-allowed;
  transform: none;
}
.if-chip[disabled]:hover {
  background: var(--surface);
}
/* A row of things with the space the system uses between them. */
.if-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}
.if-row--between {
  justify-content: space-between;
}
.if-row--wrap {
  flex-wrap: wrap;
}
/* A stack. The gap is the only decision it makes. */
.if-stack {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}
.if-stack--tight {
  gap: var(--space-2);
}
.if-stack--loose {
  gap: var(--space-6);
}
/* A grid of panels. Below the breakpoint it is one column, always. */
.if-grid {
  display: grid;
  gap: var(--space-5);
  grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr));
}
.if-grid--wide {
  grid-template-columns: repeat(auto-fill, minmax(26rem, 1fr));
}
.if-grid--narrow {
  grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
}
/* The heading that opens a screen that is not a Welcome. Sentence case, 32px,
   with the one control it needs on the right. */
.if-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-4);
  margin-bottom: var(--space-6);
  flex-wrap: wrap;
}
.if-head__title {
  margin: 0;
  font-size: var(--text-xl);
  font-weight: var(--weight-heavy);
  letter-spacing: var(--tracking-tight);
  line-height: var(--leading-tight);
}
.if-head__note {
  margin: var(--space-2) 0 0;
  color: var(--ink-muted);
}
.if-head__actions {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}
/* Tabs. A row of pills at control height, the current one filled — the same
   gesture as the rail, so a reader only learns it once. */
.if-tabs {
  display: flex;
  gap: var(--space-2);
  flex-wrap: wrap;
  margin-bottom: var(--space-5);
}
.if-tab {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  height: var(--control-height);
  padding: 0 var(--space-4);
  border: 0;
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--ink-soft);
  font: inherit;
  font-size: var(--text-base);
  font-weight: var(--weight-medium);
  text-decoration: none;
  cursor: pointer;
  transition: background var(--duration-fast) var(--ease), color var(--duration-fast) var(--ease);
}
.if-tab:hover {
  background: var(--surface-tint);
  color: var(--ink);
}
.if-tab.is-current,
.if-tab.active {
  background: var(--surface-tint);
  color: var(--ink);
  font-weight: var(--weight-strong);
}
.if-tab__count {
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
  font-size: var(--text-xs);
  color: var(--ink-muted);
}
/* An avatar. Round, tinted while it loads, and it never stretches. */
.if-avatar {
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 50%;
  object-fit: cover;
  background: var(--surface-tint);
  flex: none;
}
.if-avatar--sm {
  width: 1.75rem;
  height: 1.75rem;
}
.if-avatar--lg {
  width: 4rem;
  height: 4rem;
}
/* Prose written by a person — a brief, a message, a description. */
.if-prose {
  color: var(--ink-soft);
  line-height: var(--leading-normal);
  text-wrap: pretty;
}
.if-prose p {
  margin: 0 0 var(--space-3);
}
.if-prose p:last-child {
  margin-bottom: 0;
}
.if-prose ul {
  margin: 0 0 var(--space-3);
  padding-left: var(--space-5);
}
/* A label above a value, both quiet. Used in the definition rows that carry
   what a brand asked for and what a creator answered. */
.if-def {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.if-def__label {
  font-size: var(--text-sm);
  color: var(--ink-muted);
}
.if-def__value {
  font-size: var(--text-base);
}
/* A hairline between two blocks inside one panel, where the change of tint
   would cost a whole surface. */
.if-rule {
  height: 1px;
  background: var(--hairline);
  border: 0;
  margin: var(--space-5) 0;
}
/* Small quiet text under a control, saying what it will do. */
.if-note {
  font-size: var(--text-sm);
  color: var(--ink-muted);
  line-height: var(--leading-snug);
}
/* Text visible only to a screen reader. A control with an icon and no label
   uses this rather than a title attribute. */
.if-sr {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
