/* OVision Discovery OS — design system.

   A scientific instrument: calm, precise, inspectable. Evidence-native rather
   than dashboard-native. Every scientific state is carried by an icon AND a
   word as well as a colour (GU-10, WCAG 2.2 AA).

   The palette is H&E.

   Haematoxylin and eosin is the stain almost every slide in the launch domain
   arrives under: haematoxylin takes the nuclei violet, eosin takes the cytoplasm
   and stroma pink. It is the first thing a pathologist sees and the last thing
   they describe, so it is the one colour scheme in this product that a user does
   not have to learn. Borrowing it costs nothing and means the chrome around a
   tile is in the same key as the tile.

   It replaces a navy that was chosen for being neutral. Neutral is not the same
   as meaningful, and on a page whose whole subject is stained tissue, navy read
   as generic enterprise software sitting next to the science.

   The discipline that matters: eosin is the BRAND, not a status. Every
   scientific state keeps its own colour (amber caution, green pass, red fail,
   blue evidence, violet nuclear/derived) and every one of them still carries an
   icon and a word, so nothing here is decided by hue alone. */

:root {
  /* ------------------------------------------------------------- the wave
     One gradient, for hero surfaces only: the landing hero, sign-in, the
     first run and the home. Working pages paint none (shell.css), so no page
     of work ever sits on it. Declared here because every shell loads this
     sheet; home.css and landing-extra.css only say how much of it their
     screen gets. A wash cannot ride a token swap, so the dark scheme is
     written out by hand in theme-dark.css, in both the explicit and the
     system-preference form.
     2026-09-26, the user: "change the color back to the lovable.dev theme …
     make sure it's real and beautiful … light and dark powerful both". So it
     is lovable.dev's own hero, measured, not remembered: a cream top where
     the title sits; a saturated royal-blue band that rises at the sides and
     dips into a V under the question box; orchid-pink hills either side of
     the V; rose at the foot. Fitted on a 9 x 12 grid against a capture of
     lovable.dev's hero (mean RGB distance about 14 in light and 18 in dark,
     most of it the reference's own lopsidedness). Lovable paints it with a
     raster image; this is CSS alone. The light scheme keeps its light top,
     never a dark wave on a white app ("it should always stay light, and the
     dark theme dark"); theme-dark.css paints the same colours on charcoal.
     The ground equals the wave's first stop, so where a surface ends there
     is no visible step. Text directly on the wave follows the scheme through
     --on-wave and sits on the top; lower down it sits on a plate. Cards,
     chips, tiles and the composer on the wave keep their own scheme. */
  --ov-wave:
    linear-gradient(180deg, #f7f6f3 0%, rgba(247, 246, 243, .85) 7%, rgba(247, 246, 243, 0) 22%),
    radial-gradient(42% 64% at 50% 0%, #f8f7f4 0%, #f8f7f4 52%, rgba(248, 247, 244, .55) 76%, rgba(248, 247, 244, 0) 100%),
    radial-gradient(32% 28% at 20% 104%, #e7426f 0%, rgba(231, 66, 111, .7) 45%, rgba(231, 66, 111, 0) 100%),
    radial-gradient(32% 28% at 80% 104%, #e7426f 0%, rgba(231, 66, 111, .7) 45%, rgba(231, 66, 111, 0) 100%),
    radial-gradient(38% 48% at 12% 84%, #ed7ad8 0%, #ec78d5 36%, rgba(236, 120, 213, 0) 100%),
    radial-gradient(38% 48% at 88% 84%, #ed7ad8 0%, #ec78d5 36%, rgba(236, 120, 213, 0) 100%),
    radial-gradient(22% 36% at 50% 64%, #6f80f4 0%, rgba(111, 128, 244, .75) 40%, rgba(111, 128, 244, 0) 100%),
    linear-gradient(180deg, #eef0f7 0%, #d4daf6 12%, #97a6f6 26%, #6779f7 38%, #6070f3 50%, #6a72f0 62%, #8a73ea 72%, #c474d9 82%, #e263b8 91%, #e84a86 100%);
  --ov-wave-ground: #f7f6f3;
  /* The wave's foot, flat: what a page painted one screen of the wave on
     (the home) keeps below that screen, under the studies sheet. */
  --ov-wave-foot: #e84a86;
  /* Text that sits directly on the light wave: near-black ink, on the cream
     top (about 17:1). The bands below are vivid, and a mid-luminance band
     defeats both inks, so text is never placed on them bare: chips, pills
     and cards there carry a plate (--on-wave-plate or their own paper). The
     dark scheme sets these white (theme-dark.css). */
  --on-wave: #18181b;
  --on-wave-2: #27272a;
  --on-wave-3: #27272a;
  /* Plates, hover tints and outlines on the wave: faint ink on the light wave,
     faint white on the dark one (theme-dark.css). */
  --on-wave-plate: rgba(255, 255, 255, .55);
  --on-wave-hover: rgba(24, 24, 27, .06);
  --on-wave-line: rgba(24, 24, 27, .22);
  /* The app's two flat surfaces, also after Lovable: the ground the rail sits
     on, and the rounded panel every page lives in (shell.css). Text only ever
     sits on these, on white cards, or on a hero's light top. */
  --ground: #f3f3f2;
  --panel: #fcfcfb;
  /* Eosin. The brand ramp, and still named `ink-*` because ~400 declarations
     read it by that name; the value is the brand, the identifier is plumbing.
     Tuned against paper: ink-600 on white is 5.3:1 and ink-700 is 7.3:1, so
     links and body text both clear AA. ink-500 is a fill and a focus ring and
     is never asked to carry small type. */
  --ink-900: #1e1b4b;
  --ink-800: #3730a3;
  --ink-700: #4338ca;
  --ink-600: #4f46e5;
  --ink-500: #6366f1;
  /* Text, warmed to a plum-black so it sits on blush paper rather than on top
     of it. Same lightness as the navy-grey it replaces, so every contrast
     pairing already measured in this file survives the change. */
  --text: #18181b;
  --text-2: #52525b;
  /* Darkened from #8f7d86 on 2026-09-15: that failed WCAG AA on every light
     ground it is painted on (3.86 on --paper, 3.64 on --canvas, 3.36 on
     --canvas-2, against the 4.5 normal text requires), and every element
     using it renders between 10.5px and 12.8px, so the 3:1 large-text
     allowance never applied. This value clears all three with headroom:
     5.51 / 5.21 / 4.80. Held by tests/integration/test_contrast.py. */
  --text-3: #65656e;

  /* Paper and rules. The canvas is the largest surface in the product and is
     therefore the one that decides whether the whole thing feels warm. */
  --paper: #ffffff;
  --canvas: #fbfbfa;
  --canvas-2: #f4f4f5;
  --line: #ececee;
  --line-2: #dcdce0;

  /* Accents. */
  /* Darkened from #b0722a on 2026-09-25: that scored 3.70 on its own pill
     (--amber-2) and 3.97 on paper, under the 4.5 small text needs, and every
     "Needs review" chip and warning label is small text. This clears 5.28
     on the pill and 5.67 on paper. Held by tests/integration/test_contrast.py. */
  --amber: #94591c;
  --amber-2: #fdf6ea;
  --amber-line: #f0e0c4;
  --green: #0f7050;
  --green-2: #ecf7f2;
  --green-line: #c3e5d6;
  --red: #a52a22;
  --red-2: #fdeeed;
  --red-line: #f2cdca;
  --blue: #1f5b8f;
  --blue-2: #eef4fa;
  --blue-line: #cfe0ee;
  /* Haematoxylin, the nuclear stain. Used for derived/structural objects, and
     the one accent that is a real counterpart to the brand rather than a
     neighbour of it. */
  --violet: #5b3f8c;
  --violet-2: #f1ecf9;
  --violet-line: #dcd0ee;

  --r-lg: 14px;
  --r: 11px;
  --r-sm: 7px;
  --shadow-1: 0 1px 2px rgba(24, 24, 27, .05);
  --shadow-2: 0 1px 3px rgba(24, 24, 27, .06), 0 8px 24px -12px rgba(24, 24, 27, .14);
  --shadow-3: 0 24px 60px -18px rgba(24, 24, 27, .24);

  --serif: "Iowan Old Style", "Palatino Linotype", Palatino, "Book Antiqua", Georgia, serif;
  /* Inter first where it is installed — it is the face the reference uses and
     the one this product is being matched to. Where it is not, the platform
     serves its own UI face, which is the same design problem solved the same
     way: SF Pro on Apple, Segoe UI Variable on Windows, Roboto on Android.
     Deliberately NOT a webfont: the landing page is the public face of a
     product whose claim is that nothing leaves your machine, and a Google
     Fonts link would have every visitor call Google to read it. */
  --sans: Inter, "Inter var", -apple-system, BlinkMacSystemFont, "Segoe UI Variable Text",
          "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
}

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--canvas);
  color: var(--text);
  font-family: var(--sans);
  font-size: 14px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* Let a variable face pick its optical size, and keep figures aligned in
     running text — this product prints a lot of counts and intervals. */
  font-optical-sizing: auto;
  font-variant-numeric: tabular-nums;
}

a { color: var(--ink-600); text-decoration: none; }
a:hover { color: var(--ink-700); text-decoration: underline; text-underline-offset: 2px; }

:focus-visible { outline: 2px solid var(--ink-600); outline-offset: 2px; border-radius: 4px; }

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--ink-900); color: #fff; padding: .65rem 1.1rem; border-radius: 0 0 8px 0;
}
.skip:focus { left: 0; }

.ico { flex: none; vertical-align: -.15em; }
.ico.amber { color: var(--amber); }
.ico.ok-ico { color: var(--green); }
.ico.bad-ico { color: var(--red); }

/* ---------------------------------------------------------------- layout */

/* Brand lockup: the mark, then the name, then the descriptor BELOW it. */
.brand-mark { flex: none; display: flex; color: var(--ink-800); }
.logo { display: block; }
.brand-text { display: block; min-width: 0; }
.brand-name {
  display: block;
  font-family: var(--serif);
  font-size: 1.42rem; line-height: 1.05; color: var(--ink-900);
  letter-spacing: -.01em;
}
.brand-sub {
  display: block;
  font-size: .75rem; line-height: 1.2; margin-top: .22rem;
  color: var(--text-3); letter-spacing: .11em; text-transform: uppercase;
}

.main { display: flex; flex-direction: column; min-width: 0; position: relative; }
.content {
  position: relative; z-index: 1;
  padding: 1.9rem 1.9rem 3.5rem; max-width: 1280px; width: 100%;
}
.dot { width: 7px; height: 7px; border-radius: 50%; background: var(--green); flex: none; }
.avatar {
  width: 30px; height: 30px; border-radius: 50%; background: var(--ink-800);
  color: #fff; display: grid; place-items: center; font-weight: 700; font-size: .7rem;
  letter-spacing: .02em;
}

/* ---------------------------------------------------------------- page head */

.page-head {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 2rem; margin-bottom: 1.5rem; padding-bottom: 1.15rem;
  border-bottom: 1px solid var(--line);
}
.page-head h1 {
  font-family: var(--serif); font-size: 2.25rem; font-weight: 400;
  color: var(--ink-900); margin: 0 0 .3rem; letter-spacing: -.015em; line-height: 1.15;
}
.page-head .sub { color: var(--text-2); margin: 0; max-width: 62ch; }
.page-head .tag {
  text-align: right; color: var(--text-3); font-size: .82rem; line-height: 1.4;
  white-space: nowrap; padding-bottom: .2rem;
}
.page-head .tag .rule { width: 28px; height: 2px; background: var(--amber); margin: .45rem 0 0 auto; }
@media (max-width: 860px) {
  .page-head { flex-direction: column; align-items: flex-start; gap: .8rem; }
  .page-head .tag { text-align: left; } .page-head .tag .rule { margin-left: 0; }
}

/* ---------------------------------------------------------------- cards */

.card {
  background: var(--paper); border: 1px solid var(--line);
  border-radius: var(--r-lg); padding: 1.25rem 1.35rem; margin-bottom: 1.1rem;
  box-shadow: var(--shadow-1);
}
.card > h2:first-child, .card > h3:first-child { margin-top: 0; }
.card h2 {
  font-size: .75rem; letter-spacing: .1em; text-transform: uppercase;
  color: var(--text-3); font-weight: 700; margin: 0 0 .85rem;
  display: flex; align-items: center; gap: .45rem;
}
.card h2 .ico { color: var(--text-3); }
.card h2.plain {
  text-transform: none; letter-spacing: -.01em; font-size: 1.35rem;
  font-family: var(--serif); font-weight: 400; color: var(--ink-900);
}

.grid { display: grid; gap: 1.1rem; align-items: stretch; }
.grid.two { grid-template-columns: 1fr 1fr; }
.grid.three { grid-template-columns: repeat(3, 1fr); }
.grid.four { grid-template-columns: repeat(4, 1fr); }
.grid.sidebar-right { grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr); align-items: start; }
.grid > .card { margin-bottom: 0; display: flex; flex-direction: column; }
.grid > .card > :last-child { margin-bottom: 0; }
.grid > div > .card:last-child { margin-bottom: 0; }
@media (max-width: 1080px) {
  .grid.two, .grid.three, .grid.four, .grid.sidebar-right { grid-template-columns: 1fr; }
  .content { padding: 1.4rem 1.1rem 3rem; }
}

.stat-card .n {
  font-family: var(--serif); font-size: 2.1rem; color: var(--ink-900);
  line-height: 1.05; letter-spacing: -.02em;
}
.stat-card .l { color: var(--text-2); font-size: .85rem; margin-top: .2rem; }
.stat-card .ico-wrap {
  width: 34px; height: 34px; border-radius: 9px; display: grid; place-items: center;
  background: var(--blue-2); color: var(--blue); margin-bottom: .7rem;
}
.stat-card.ok .ico-wrap { background: var(--green-2); color: var(--green); }
.stat-card.warn .ico-wrap { background: var(--amber-2); color: var(--amber); }
.stat-card.neg .ico-wrap { background: var(--red-2); color: var(--red); }

.muted { color: var(--text-3); }
.small { font-size: .83rem; }
.mono { font-family: var(--mono); font-size: .78rem; letter-spacing: -.01em;
        overflow-wrap: anywhere; word-break: break-word; min-width: 0; }
.serif { font-family: var(--serif); }
.right { text-align: right; }
.nowrap { white-space: nowrap; }
.grow { flex: 1; min-width: 0; }

/* ---------------------------------------------------------------- evidence bar */

.evbar {
  display: flex; background: var(--paper); border: 1px solid var(--line);
  border-radius: var(--r-lg); overflow: hidden; margin-bottom: 1.3rem;
  box-shadow: var(--shadow-1);
}
.evbar .seg {
  flex: 1 1 0; padding: .7rem .9rem; border-right: 1px solid var(--line);
  color: var(--text); min-width: 0; display: flex; flex-direction: column;
  justify-content: flex-start;
}
.evbar .seg:last-child { border-right: 0; }
.evbar .seg:hover { background: var(--canvas); text-decoration: none; }
.evbar .k {
  font-size: .75rem; text-transform: uppercase; letter-spacing: .1em;
  color: var(--text-3); font-weight: 700;
}
.evbar .v {
  font-weight: 600; font-size: .84rem; margin-top: .2rem;
  display: flex; align-items: flex-start; gap: .35rem;
  line-height: 1.35; overflow-wrap: anywhere; min-width: 0;
}
.evbar .v .ico { flex: none; margin-top: .16em; }
.evbar .v.ok { color: var(--green); }
.evbar .v.warn { color: var(--amber); }
.evbar .v.blocked { color: var(--red); }
.evbar .v.info { color: var(--blue); }
.evbar .v.neutral { color: var(--text-2); }
@media (max-width: 1240px) { .evbar { flex-wrap: wrap; } .evbar .seg { flex: 1 1 25%; } }
@media (max-width: 820px)  { .evbar .seg { flex: 1 1 50%; } }

/* ---------------------------------------------------------------- status pills */

.pill {
  display: inline-flex; align-items: center; gap: .32rem;
  border-radius: 20px; padding: .16rem .6rem .16rem .5rem;
  font-size: .75rem; font-weight: 650; letter-spacing: .005em;
  border: 1px solid transparent; white-space: nowrap; line-height: 1.5;
}
.pill .ico { width: 13px; height: 13px; }
.pill.ok      { background: var(--green-2);  color: var(--green);  border-color: var(--green-line); }
.pill.note    { background: var(--amber-2);  color: var(--amber);  border-color: var(--amber-line); }
.pill.warn    { background: var(--amber-2);  color: var(--amber);  border-color: var(--amber-line); }
.pill.blocked { background: var(--red-2);    color: var(--red);    border-color: var(--red-line); }
.pill.info    { background: var(--blue-2);   color: var(--blue);   border-color: var(--blue-line); }
.pill.neutral { background: var(--canvas-2); color: var(--text-2); border-color: var(--line-2); }
.pill.exp     { background: var(--violet-2); color: var(--violet); border-color: var(--violet-line); }

/* ---------------------------------------------------------------- evidence chips */

.chip {
  display: inline-flex; align-items: center; gap: .3rem;
  background: var(--amber-2); border: 1px solid var(--amber-line); color: #7d5215;
  border-radius: 20px; padding: .12rem .58rem; font-size: .75rem;
  margin: .14rem .22rem .14rem 0; font-family: var(--mono);
}
.chip:hover { background: #fbeed6; text-decoration: none; color: #6a4512; }
.chip.ev { background: var(--blue-2); border-color: var(--blue-line); color: var(--ink-700); }
.chip.ev:hover { background: #e3eef8; color: var(--ink-800); }

/* ---------------------------------------------------------------- tables */

table.data { width: 100%; border-collapse: collapse; font-size: .88rem; }
table.data caption { text-align: left; color: var(--text-3); font-size: .8rem; padding-bottom: .6rem; }
table.data th {
  text-align: left; font-size: .75rem; text-transform: uppercase; letter-spacing: .09em;
  color: var(--text-3); font-weight: 700; padding: .45rem .55rem;
  border-bottom: 1px solid var(--line);
}
table.data td { padding: .6rem .55rem; border-bottom: 1px solid var(--line); vertical-align: top; }
table.data tr:last-child td { border-bottom: 0; }
/* An identifier in a cell (a skill id, a hash, a path) has no spaces, so it
   set the column's narrowest width and pushed the table past its card: the
   row's own button was cut off. It may break anywhere instead. */
table.data td .mono, table.data td.mono, table.data td code { overflow-wrap: anywhere; }
table.data.plan td:first-child {
  width: 156px; color: var(--text-2); font-weight: 650; font-size: .82rem;
  text-transform: uppercase; letter-spacing: .05em; padding-top: .75rem;
}
table.data.plan td { padding-top: .75rem; padding-bottom: .75rem; }

/* ---------------------------------------------------------------- forms */

label {
  display: block; font-weight: 650; font-size: .78rem; margin: .85rem 0 .3rem;
  color: var(--text-2); letter-spacing: .01em;
}
input[type=text], input[type=search], input[type=number],
input[type=email], input[type=password], select, textarea {
  width: 100%; padding: .6rem .75rem; border: 1px solid var(--line-2);
  border-radius: var(--r-sm); font: inherit; background: var(--paper); color: var(--text);
  transition: border-color .12s ease, box-shadow .12s ease;
}
input:focus, select:focus, textarea:focus {
  border-color: var(--ink-500); box-shadow: 0 0 0 3px rgba(222, 74, 123, .16); outline: none;
}
textarea { resize: vertical; min-height: 78px; line-height: 1.55; }

button, .btn {
  display: inline-flex; align-items: center; gap: .48rem; justify-content: center;
  background: var(--ink-800); color: #fff; border: 1px solid var(--ink-800);
  border-radius: var(--r-sm); padding: .58rem 1.1rem; font: inherit; font-weight: 600;
  cursor: pointer; min-height: 40px; transition: background .12s ease, border-color .12s ease;
}
button:hover, .btn:hover { background: var(--ink-700); border-color: var(--ink-700); text-decoration: none; color: #fff; }
/* Disabled is said by a flat, quiet look and the not-allowed cursor, never by
   fading the words: a label at 45% opacity measured under 2:1, so the one
   thing a person needed to read ("Unavailable") was the thing they could not. */
button:disabled, .btn[aria-disabled="true"],
button:disabled:hover, .btn[aria-disabled="true"]:hover {
  opacity: 1; cursor: not-allowed; box-shadow: none;
  background: var(--canvas-2); border-color: var(--line-2); color: var(--text-2);
}
button.secondary, .btn.secondary {
  background: var(--paper); color: var(--ink-800); border-color: var(--line-2);
}
button.secondary:hover, .btn.secondary:hover {
  background: var(--canvas); color: var(--ink-800); border-color: var(--line-2);
}
button.danger, .btn.danger { background: var(--red); border-color: var(--red); }
button.danger:hover, .btn.danger:hover { background: #8f231c; border-color: #8f231c; }
button.tiny, .btn.tiny { padding: .28rem .68rem; min-height: 30px; font-size: .79rem; }
.btn-row { display: flex; gap: .65rem; flex-wrap: wrap; align-items: center; margin-top: 1rem; }

/* ------------------------------------------------------------------- launch chrome
   Wordmark, composer and the headline mark. The old full-bleed launch shell
   (no rail, launch-bar, launch-wash) is gone: home uses the app rail. */

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

.launch-brand { color: inherit; flex: none; }
.launch-brand:hover { text-decoration: none; }

.wordmark { display: inline-flex; align-items: center; gap: .5rem; }
/* One lockup everywhere: the landing's. A bold sans name in the page's ink
   beside the ring, which carries the brand colour. */
.wordmark-name {
  font-family: var(--sans);
  font-size: 1.125rem;
  font-weight: 700;
  letter-spacing: -.022em;
  color: var(--heading, var(--ink-900));
  line-height: 1;
}

/* The mark set inline in the headline, the way these products sign their own
   first sentence. Nudged off the baseline because a circle optically sits high. */
.stage-mark { display: inline-block; vertical-align: -.12em; margin: 0 .04em; }
.stage-mark .logo { display: block; }

/* ------------------------------------------------------------- the composer */
.composer {
  text-align: left;
  background: rgba(255, 255, 255, .86);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  border: 1px solid rgba(98, 16, 44, .1);
  border-radius: 16px;
  box-shadow: 0 1px 2px rgba(98, 16, 44, .04), 0 18px 44px -22px rgba(98, 16, 44, .3);
  overflow: hidden;
  transition: border-color .14s ease, box-shadow .14s ease;
}
.composer:focus-within {
  border-color: rgba(196, 50, 99, .42);
  box-shadow: 0 1px 2px rgba(98, 16, 44, .04), 0 18px 44px -22px rgba(98, 16, 44, .34),
              0 0 0 3px rgba(222, 74, 123, .14);
}

.composer-input {
  display: block;
  width: 100%;
  border: 0;
  background: none;
  padding: 1.1rem 1.15rem .3rem;
  font: inherit;
  font-size: 1rem;
  line-height: 1.55;
  color: var(--text);
  resize: none;
  min-height: 5.4rem;
}
/* Every field's hint reads in both themes. Left to the browser, the hint
   was its own #757575, which stands at 3:1 on a dark field. */
::placeholder { color: var(--text-3); opacity: 1; }
.composer-input::placeholder { color: var(--text-3); }
.composer-input:focus { outline: none; box-shadow: none; }

.composer-bar {
  display: flex;
  align-items: center;
  gap: .5rem;
  flex-wrap: wrap;
  padding: .5rem .6rem .6rem;
}

/* A select that reads as a quiet action until you touch it — the "Attach" and
   "Import" slot in the reference, except these do something scientific. */
.composer-select {
  display: inline-flex;
  align-items: center;
  gap: .38rem;
  padding: .36rem .55rem;
  border-radius: 9px;
  color: var(--text-2);
  max-width: 100%;
  transition: background .12s ease, color .12s ease;
}
.composer-select:hover { background: rgba(98, 16, 44, .05); color: var(--ink-800); }
.composer-select .ico { color: var(--text-3); flex: none; }
.composer-select select {
  border: 0;
  background: none;
  padding: 0;
  font-size: .845rem;
  font-weight: 500;
  color: inherit;
  max-width: 22ch;
  min-width: 0;
  text-overflow: ellipsis;
  cursor: pointer;
}
.composer-select select:focus { outline: none; box-shadow: none; }
.composer-select:focus-within { background: rgba(98, 16, 44, .06); }

.composer-actions { display: flex; align-items: center; gap: .45rem; margin-left: auto; }

/* `hidden` must beat the display rules below it. Author styles win over the
   browser's `[hidden] { display: none }` whatever their specificity, so every
   `display:` in this block would otherwise un-hide a control the script has
   not enabled yet — or, for the microphone, one the browser cannot honour at
   all. home.css learned this once for the signed-in composer; it belongs to
   the component, so it lives here and covers both. */
.composer [hidden] { display: none !important; }

/* The send button: a filled circle, the one saturated thing on the page. */
.composer-send {
  width: 34px;
  height: 34px;
  padding: 0;
  border-radius: 50%;
  border: 0;
  background: var(--ink-900);
  color: #fff;
  display: grid;
  place-items: center;
  flex: none;
  cursor: pointer;
  transition: background .12s ease, transform .12s ease;
}
.composer-send:hover { background: var(--ink-700); transform: translateY(-1px); }
.composer-send:active { transform: none; }
.composer-send .ico { color: #fff; }

/* Dictation, beside it. A glyph rather than a second filled circle: there is
   one loud control in this box and the send key is it. The button is only
   ever shown where the browser has speech recognition, so this is never the
   styling of something that does nothing.

   `is-live` is the brand, not the red a recorder would use: red means failed
   everywhere else in this product and a microphone that is working is not a
   failure. The state is carried by the word in `.composer-note` as well as
   by the colour and the ring (GU-10), so nothing here is decided by hue. */
.composer-mic {
  width: 32px;
  height: 32px;
  min-height: 0;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: none;
  color: var(--text-3);
  display: grid;
  place-items: center;
  flex: none;
  cursor: pointer;
  transition: background .12s ease, color .12s ease;
}
.composer-mic:hover { background: var(--glass-hover, rgba(98, 16, 44, .05)); color: var(--text); }
.composer-mic .ico { color: currentColor; }
.composer-mic.is-live {
  color: var(--ink-600);
  background: var(--glass-hover-2, rgba(98, 16, 44, .06));
  box-shadow: 0 0 0 3px rgba(222, 74, 123, .18);
}
@media (prefers-reduced-motion: no-preference) {
  .composer-mic.is-live { animation: mic-live 1.6s ease-in-out infinite; }
}
@keyframes mic-live {
  50% { box-shadow: 0 0 0 6px rgba(222, 74, 123, .08); }
}

/* What dictation has to say. Hidden until there is something true to put in
   it: that the browser is listening and where the audio goes, or why it
   stopped. A control that fails silently is the thing this page is against. */
.composer-note {
  margin: 0;
  padding: 0 .85rem .6rem;
  font-size: .78rem;
  line-height: 1.45;
  color: var(--text-3);
}

@media (max-width: 620px) {
  .composer-actions { margin-left: 0; width: 100%; justify-content: flex-end; }
  .composer-select select { max-width: 13ch; }
}

/* ---------------------------------------------------------------- notices */

.notice {
  border-left: 3px solid var(--blue); background: var(--blue-2);
  padding: .8rem 1rem; border-radius: 0 var(--r-sm) var(--r-sm) 0;
  margin: 1rem 0; font-size: .89rem;
}
.notice > * { min-width: 0; }
.notice { overflow-wrap: anywhere; }
.notice.warn { border-color: var(--amber); background: var(--amber-2); }
.notice.blocked { border-color: var(--red); background: var(--red-2); }
.notice.ok { border-color: var(--green); background: var(--green-2); }
.notice h4 {
  margin: 0 0 .3rem; font-size: .75rem; text-transform: uppercase; letter-spacing: .09em;
  font-weight: 700; color: var(--text-2);
}
.notice.warn h4 { color: var(--amber); }
.notice.ok h4 { color: var(--green); }
.notice.blocked h4 { color: var(--red); }

.guard {
  border: 1px solid var(--amber-line); background: var(--amber-2);
  border-radius: var(--r); padding: 1rem 1.15rem; margin: .85rem 0;
}
.guard .part { margin-bottom: .65rem; }
.guard .part:last-of-type { margin-bottom: 0; }
.guard .part .k {
  display: block; font-size: .75rem; text-transform: uppercase; letter-spacing: .09em;
  color: var(--amber); font-weight: 700; margin-bottom: .1rem;
}
/* The code and the rule, for whoever has to look them up: one click in. */
.guard-tech { margin-top: .5rem; font-size: .78rem; color: var(--text-2); }
.guard-tech > summary { cursor: pointer; width: fit-content; font-weight: 600; color: var(--text-2); }
.guard-tech > summary:hover { color: var(--text); }
.guard-tech[open] > summary { margin-bottom: .25rem; }

/* ---------------------------------------------------------------- chat */

.msg { display: flex; gap: .85rem; margin-bottom: 1.35rem; }
.msg:last-child { margin-bottom: 0; }
.msg .who {
  width: 30px; height: 30px; border-radius: 50%; flex: none;
  display: grid; place-items: center; font-size: .75rem; font-weight: 700;
}
.msg.user .who { background: var(--canvas-2); color: var(--text-2); }
.msg.assistant .who { background: var(--ink-800); color: #fff; }
.msg .body { flex: 1; min-width: 0; }
.msg .name {
  font-weight: 700; font-size: .78rem; color: var(--ink-900); margin-bottom: .25rem;
  display: flex; gap: .45rem; align-items: baseline;
}
.msg.user .bubble {
  background: var(--blue-2); border: 1px solid var(--blue-line);
  border-radius: var(--r); padding: .7rem .9rem;
}
.msg .bubble { line-height: 1.6; }

/* ---------------------------------------------------------------- montage */

.montage { display: grid; grid-template-columns: repeat(6, 1fr); gap: .4rem; }
.montage .tile {
  aspect-ratio: 1; border-radius: 6px; border: 1px solid var(--line);
  position: relative; overflow: hidden;
  /* A low-power H&E field: eosinophilic stroma with haematoxylin nuclei
     scattered through it.

     The nuclei are placed, not tiled. A repeating lattice was the obvious way
     to get many of them and it is the wrong one: at this size a 13px pitch is
     only five dots across, and five across reads unmistakably as a grid. These
     twenty four are irregular in position, radius and density, which is what
     scatter actually looks like.

     Placeholder art for a tile with no thumbnail yet. The provenance strip
     underneath still names the real region, so nothing here stands in for data
     that does not exist. */
  background-image:
    radial-gradient(circle at 12% 18%, rgba(74, 48, 120, 0.60) 0 2.7%, transparent 4.3%),
    radial-gradient(circle at 29% 8%, rgba(74, 48, 120, 0.50) 0 2.2%, transparent 3.5%),
    radial-gradient(circle at 41% 31%, rgba(74, 48, 120, 0.64) 0 3.0%, transparent 4.8%),
    radial-gradient(circle at 19% 45%, rgba(74, 48, 120, 0.54) 0 2.4%, transparent 3.8%),
    radial-gradient(circle at 55% 15%, rgba(74, 48, 120, 0.58) 0 2.6%, transparent 4.2%),
    radial-gradient(circle at 67% 38%, rgba(74, 48, 120, 0.62) 0 3.1%, transparent 5.0%),
    radial-gradient(circle at 34% 58%, rgba(74, 48, 120, 0.52) 0 2.3%, transparent 3.7%),
    radial-gradient(circle at 8% 63%, rgba(74, 48, 120, 0.56) 0 2.8%, transparent 4.5%),
    radial-gradient(circle at 48% 72%, rgba(74, 48, 120, 0.60) 0 2.5%, transparent 4.0%),
    radial-gradient(circle at 73% 61%, rgba(74, 48, 120, 0.58) 0 2.9%, transparent 4.6%),
    radial-gradient(circle at 61% 85%, rgba(74, 48, 120, 0.50) 0 2.2%, transparent 3.5%),
    radial-gradient(circle at 23% 79%, rgba(74, 48, 120, 0.55) 0 2.7%, transparent 4.3%),
    radial-gradient(circle at 86% 26%, rgba(74, 48, 120, 0.53) 0 2.4%, transparent 3.8%),
    radial-gradient(circle at 91% 53%, rgba(74, 48, 120, 0.57) 0 2.8%, transparent 4.5%),
    radial-gradient(circle at 78% 11%, rgba(74, 48, 120, 0.48) 0 2.1%, transparent 3.4%),
    radial-gradient(circle at 45% 44%, rgba(74, 48, 120, 0.61) 0 2.6%, transparent 4.2%),
    radial-gradient(circle at 15% 33%, rgba(74, 48, 120, 0.49) 0 2.2%, transparent 3.5%),
    radial-gradient(circle at 57% 51%, rgba(74, 48, 120, 0.59) 0 2.9%, transparent 4.6%),
    radial-gradient(circle at 88% 80%, rgba(74, 48, 120, 0.54) 0 2.5%, transparent 4.0%),
    radial-gradient(circle at 31% 90%, rgba(74, 48, 120, 0.51) 0 2.3%, transparent 3.7%),
    radial-gradient(circle at 70% 90%, rgba(74, 48, 120, 0.47) 0 2.0%, transparent 3.2%),
    radial-gradient(circle at 5% 88%, rgba(74, 48, 120, 0.52) 0 2.4%, transparent 3.8%),
    radial-gradient(circle at 96% 38%, rgba(74, 48, 120, 0.46) 0 2.1%, transparent 3.4%),
    radial-gradient(circle at 38% 17%, rgba(74, 48, 120, 0.45) 0 2.0%, transparent 3.2%),
    radial-gradient(30% 34% at 34% 30%, rgba(222, 74, 123, .20), transparent 72%),
    radial-gradient(26% 30% at 74% 68%, rgba(222, 74, 123, .16), transparent 70%),
    linear-gradient(150deg, #fce5ee, #f2ccdc);
}
.montage .tile .prov {
  position: absolute; bottom: 0; left: 0; right: 0; font-size: .75rem; line-height: 1.35;
  background: rgba(255, 255, 255, .88); color: var(--text-3); padding: 0 3px;
  font-family: var(--mono); overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
@media (max-width: 760px) { .montage { grid-template-columns: repeat(4, 1fr); } }

/* ---------------------------------------------------------------- graph */

.graph { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: .8rem; align-items: start; }
@media (max-width: 900px) { .graph { grid-template-columns: 1fr 1fr; } }
.gnode {
  border: 1.5px solid var(--line-2); border-radius: var(--r); padding: .7rem .8rem;
  background: var(--paper);
}
.gnode .t {
  font-size: .75rem; text-transform: uppercase; letter-spacing: .1em;
  color: var(--text-3); font-weight: 700;
}
.gnode .n { font-weight: 650; color: var(--ink-900); font-size: .89rem; word-break: break-word; margin-top: .15rem; }
.gnode .d { font-size: .78rem; color: var(--text-2); margin-top: .1rem; }
.gnode.claim { border-color: var(--green); background: linear-gradient(var(--green-2), var(--paper) 60%); }
.gnode.claim.constrained { border-color: var(--amber); background: linear-gradient(var(--amber-2), var(--paper) 60%); }
.gnode.negative { border-color: var(--red-line); background: linear-gradient(var(--red-2), var(--paper) 60%); }
.gnode.review { border-color: var(--blue-line); background: linear-gradient(var(--blue-2), var(--paper) 60%); }
.edge {
  text-align: center; color: var(--text-3); font-size: .75rem; padding: .35rem 0;
  display: flex; align-items: center; gap: .4rem; justify-content: center;
}

/* ---------------------------------------------------------------- uncertainty axes */

.axis {
  display: grid; grid-template-columns: 152px minmax(0, 1fr) 40px;
  gap: .6rem; align-items: center; margin-bottom: .42rem;
}
.axis .name { font-size: .82rem; color: var(--text-2); }
.axis .track { height: 7px; background: var(--canvas-2); border-radius: 4px; overflow: hidden; }
.axis .fill { height: 100%; border-radius: 4px; }
.axis .fill.hi { background: var(--green); }
.axis .fill.mid { background: var(--amber); }
.axis .fill.lo { background: var(--red); }
.axis .val { text-align: right; font-weight: 700; font-size: .8rem; font-family: var(--mono); }
.axis .val.hi { color: var(--green); } .axis .val.mid { color: var(--amber); } .axis .val.lo { color: var(--red); }

/* ---------------------------------------------------------------- pipeline steps */

.steps { display: flex; gap: .45rem; align-items: stretch; flex-wrap: wrap; }
.step {
  flex: 1 1 0; min-width: 96px; border: 1px solid var(--line); border-radius: var(--r-sm);
  padding: .5rem .55rem; text-align: center; background: var(--paper);
}
.step .k { font-weight: 700; font-size: .78rem; color: var(--ink-900); }
.step .s { font-size: .75rem; color: var(--text-3); margin-top: .1rem; }
.step.done { background: var(--green-2); border-color: var(--green-line); }
.step.done .k { color: var(--green); }
.step.running { background: var(--blue-2); border-color: var(--blue-line); }
.step.running .k { color: var(--blue); }
.step.queued { background: var(--canvas); }
.step.negative { background: var(--red-2); border-color: var(--red-line); }
.step.negative .k { color: var(--red); }

/* ---------------------------------------------------------------- lists + kv */

.kv { display: grid; grid-template-columns: 190px minmax(0, 1fr); gap: .35rem .9rem; font-size: .87rem; margin: 0; }
.kv dt { color: var(--text-3); }
.kv dd { margin: 0; word-break: break-word; }
@media (max-width: 700px) { .kv { grid-template-columns: 1fr; } .kv dd { margin-bottom: .4rem; } }

details.drawer {
  border: 1px solid var(--line); border-radius: var(--r-sm);
  padding: .55rem .75rem; margin: .55rem 0; background: var(--paper);
}
details.drawer summary {
  cursor: pointer; font-weight: 600; font-size: .84rem; color: var(--ink-600);
  list-style: none; display: flex; align-items: center; gap: .4rem;
}
details.drawer summary::-webkit-details-marker { display: none; }
details.drawer summary::before { content: "▸"; color: var(--text-3); font-size: .8rem; }
details.drawer[open] summary::before { content: "▾"; }
details.drawer[open] { background: var(--canvas); }
details.drawer pre {
  overflow-x: auto; font-size: .75rem; background: var(--paper); padding: .7rem;
  border-radius: 6px; border: 1px solid var(--line); margin: .6rem 0 0;
}

.list-rows { display: flex; flex-direction: column; }
.list-rows > .row {
  display: flex; gap: .9rem; align-items: center; padding: .78rem .1rem;
  border-top: 1px solid var(--line); min-width: 0;
}
.list-rows > .row > .pill { flex: none; }
.list-rows > .row:first-child { border-top: 0; padding-top: .25rem; }
.list-rows > .row:last-child { padding-bottom: .25rem; }
.list-rows + .btn-row { margin-top: 1rem; }
.rel-key {
  flex: none; width: 8.5rem; font-size: .78rem; color: var(--text-3);
  text-transform: uppercase; letter-spacing: .06em; font-weight: 700;
  overflow-wrap: anywhere;
}

/* ---------------------------------------------------------------- scoreboard */

.board { display: flex; flex-direction: column; }
.board-row { padding: 1rem .1rem; border-top: 1px solid var(--line); min-width: 0; }
.board-row:first-child { border-top: 0; padding-top: .4rem; }
.board-row:last-child { padding-bottom: .2rem; }
.board-head {
  display: flex; align-items: baseline; gap: .6rem .7rem; flex-wrap: wrap;
}
.board-head h3 {
  margin: 0; font-size: .95rem; font-weight: 650; color: var(--ink-900);
  letter-spacing: -.005em; min-width: 0;
}
.board-head .pill { flex: none; align-self: center; }
.board-num {
  margin-left: auto; display: flex; align-items: baseline; gap: .55rem;
  white-space: nowrap; font-family: var(--mono); font-size: .78rem;
}
.board-num .n { color: var(--ink-700); font-weight: 600; }
.board-num .c { color: var(--text-3); }
.board-headline {
  margin: .4rem 0 0; color: var(--text-2); font-size: .875rem;
  line-height: 1.55; max-width: 92ch;
}
.board-constraint {
  margin: .4rem 0 0; color: var(--amber); font-size: .83rem; line-height: 1.5;
  display: flex; align-items: flex-start; gap: .35rem;
}
.board-constraint .ico { flex: none; margin-top: .18em; }
.board-chips { margin-top: .55rem; display: flex; flex-wrap: wrap; gap: .35rem; }

/* ---------------------------------------------------------------- footer strip */

.ruo-strip {
  position: relative; z-index: 1;
  margin-top: auto; background: var(--ink-900); color: #f0c9d8; font-size: .76rem;
  padding: .7rem 1.9rem; letter-spacing: .01em;
  display: flex; align-items: center; gap: .5rem;
}
.ruo-strip strong { color: #fff; }
.ruo-strip .ico { color: var(--amber); }

/* ---------------------------------------------------------------- palette */

.palette {
  position: fixed; inset: 0; background: rgba(35, 21, 29, .38);
  display: none; place-items: start center; padding-top: 12vh; z-index: 50;
  backdrop-filter: blur(2px);
}
.palette.show { display: grid; }
.palette .box {
  background: var(--paper); border-radius: var(--r-lg); width: min(580px, 92vw);
  box-shadow: var(--shadow-3); overflow: hidden;
  /* The list is longer than a short window (or a zoomed one): the box keeps
     its search field in place and scrolls the destinations under it. */
  display: flex; flex-direction: column; max-height: min(74vh, 40rem);
}
.palette input { flex: none; }
.palette .box a:first-of-type { margin-top: 0; }
.palette .box > a { flex: none; }
.palette .box { scrollbar-gutter: stable; }
.palette .box > *:not(input) { overflow-anchor: none; }
.palette .box { overflow-y: auto; }
.palette input {
  border: 0; border-bottom: 1px solid var(--line); border-radius: 0;
  padding: 1rem 1.15rem; font-size: 1rem;
}
.palette input:focus { box-shadow: none; }
.palette a {
  display: flex; align-items: center; gap: .7rem; padding: .65rem 1.15rem;
  color: var(--text); border-bottom: 1px solid var(--line);
}
.palette a:last-child { border-bottom: 0; }
.palette a:hover { background: var(--canvas); text-decoration: none; }
.palette a .ico { color: var(--text-3); }
.palette a .h { font-weight: 600; display: block; }
.palette a .d { font-size: .78rem; color: var(--text-3); display: block; }

/* ---------------------------------------------------------------- verify page */

.verify-shell { max-width: 920px; margin: 0 auto; padding: 2.4rem 1.5rem 4rem; }
.verify-head {
  border-bottom: 1px solid var(--line); padding-bottom: 1.1rem; margin-bottom: 1.6rem;
  display: flex; align-items: center; gap: .8rem;
}
.verify-title {
  font-family: var(--serif); font-size: 2.15rem; color: var(--ink-900);
  line-height: 1.2; margin: .35rem 0 .2rem; font-weight: 400; letter-spacing: -.015em;
}
.verify-rule { width: 46px; height: 2px; background: var(--amber); margin: 1rem 0; }
.ev-grid { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: .75rem; }
.ev-grid .cell {
  border: 1px solid var(--line); border-radius: var(--r); padding: .8rem .85rem;
  background: var(--paper); box-shadow: var(--shadow-1);
}
.ev-grid .cell .k {
  font-size: .75rem; text-transform: uppercase; letter-spacing: .1em;
  color: var(--text-3); font-weight: 700;
  display: flex; align-items: center; gap: .3rem;
}
.ev-grid .cell .v {
  font-family: var(--serif); font-size: 1.15rem; color: var(--ink-900); margin-top: .25rem;
}
@media (max-width: 900px) { .ev-grid { grid-template-columns: repeat(2, 1fr); } }

@media print {
  .btn-row, .palette, .ruo-strip { display: none !important; }
  .card { box-shadow: none; break-inside: avoid; }
}

@media (prefers-reduced-motion: reduce) { * { animation: none !important; transition: none !important; } }

/* ------------------------------------------------------- how it actually works

   A dark full-bleed band: the steps on the left, and the artefact each one
   produces on the right. Selecting a step swaps the panel.

   The panels are the reason the section exists. Five sentences about rigour
   persuade nobody; a guard refusing a headline AUROC in four parts, with the
   permutation it would take to earn it, is the product. So the copy is short
   and the artefacts are specific — real reason codes, real vocabulary, marked
   as examples because this page has no workspace behind it.

   Dark because it is the one band on the page that is not the product's own
   chrome: it is a demonstration, and the change in ground says so without a
   heading having to. */

.how {
  background: #17131a;
  color: #f4ecf0;
  padding: clamp(3.5rem, 8vw, 6rem) 1.5rem;
}
.how-inner {
  max-width: 1180px;
  margin: 0 auto;
  display: grid;
  gap: clamp(2rem, 5vw, 3.5rem);
  align-items: start;
}
@media (min-width: 940px) {
  .how-inner { grid-template-columns: minmax(0, 0.85fr) minmax(0, 1fr); }
}

.how-copy h2 {
  font-family: var(--sans);
  font-size: clamp(1.6rem, 3.2vw, 2.2rem);
  font-weight: 700;
  letter-spacing: -.028em;
  line-height: 1.1;
  margin: 0 0 .7rem;
  color: #fff;
  text-wrap: balance;
}
.how-copy > p {
  color: #b8a9b2;
  margin: 0 0 1.9rem;
  max-width: 46ch;
  line-height: 1.6;
}

.how-steps {
  list-style: none; margin: 0; padding: 0;
  /* One clock for the whole section. The rail's fill is the timer: script
     advances on its `animationend` rather than on an interval of its own
     (landing.html), so the line under the open step cannot finish early or
     late relative to the move it is predicting. Change this number and both
     halves change together. */
  --how-dwell: 6000ms;
  --how-open: 420ms;
  /* Out-quint: most of the distance covered immediately, then a long settle.
     The step should look like it has already opened by the time the eye
     arrives, rather than like something being unfolded. */
  --how-ease: cubic-bezier(.22, .61, .36, 1);
}

.how-step { position: relative; border-top: 1px solid rgba(255, 255, 255, .1); }
.how-step:last-child { border-bottom: 1px solid rgba(255, 255, 255, .1); }

.how-step button {
  all: unset;
  display: block;
  width: 100%;
  box-sizing: border-box;
  padding: 1rem 0;
  font-size: 1.02rem;
  font-weight: 500;
  color: #cdbfc7;
  cursor: pointer;
  transition: color .14s ease;
}
.how-step button:hover { color: #fff; }
.how-step button:focus-visible {
  outline: 2px solid var(--ink-500);
  outline-offset: 3px;
  border-radius: 4px;
}
.how-step.is-open button { color: #fff; }

/* Without JavaScript every detail stays open, so the section is a plain list
   rather than five headings with their content hidden behind a script. */
.how-detail { padding-bottom: 1.05rem; }
.how-detail p { margin: 0; color: #a2939c; font-size: .93rem; line-height: 1.6; max-width: 46ch; }

/* With script, a closed step collapses instead of disappearing.

   This was `display: none`, which is a cut: the list jumped by the height of
   a paragraph every six seconds, and the three steps below the open one moved
   before the eye had finished reading the one that opened. The height is
   animated as a grid row — 0fr to 1fr — because that interpolates to the
   content's own height, so no one has to measure the paragraph or cap it with
   a max-height guess that clips the longest step and pads the shortest.

   `min-height: 0` and `overflow: hidden` on the child are what make the row
   able to be shorter than its content; without them the grid refuses to
   shrink and nothing moves. A browser that cannot interpolate grid rows snaps
   between the two states, which is exactly the cut this replaced — so the
   enhancement degrades to the previous behaviour rather than to a broken one.

   The text fades slightly behind the opening and slightly ahead of the close,
   so the paragraph is never briefly readable at a height that cannot hold
   it. */
body.how-enhanced .how-detail {
  display: grid;
  grid-template-rows: 0fr;
  padding-bottom: 0;
  opacity: 0;
  transition: grid-template-rows var(--how-open) var(--how-ease),
              padding-bottom var(--how-open) var(--how-ease),
              opacity .16s linear;
}
body.how-enhanced .how-detail > p { min-height: 0; overflow: hidden; }
body.how-enhanced .how-step.is-open .how-detail {
  grid-template-rows: 1fr;
  padding-bottom: 1.05rem;
  opacity: 1;
  transition: grid-template-rows var(--how-open) var(--how-ease),
              padding-bottom var(--how-open) var(--how-ease),
              opacity .26s linear .1s;
}

/* The rail under the open step. It fills over the dwell time, so the section
   says how long it will sit there instead of moving without warning. */
.how-rail {
  position: absolute;
  left: 0; right: 0; bottom: -1px;
  height: 2px;
  display: none;
  overflow: hidden;
}
body.how-enhanced .how-step.is-open .how-rail { display: block; }
.how-rail i {
  display: block;
  height: 100%;
  width: 100%;
  background: linear-gradient(90deg, var(--ink-500), #c9a8f2);
  transform-origin: left center;
  animation: how-fill var(--how-dwell) linear both;
}
.how-steps.is-manual .how-rail i { animation: none; transform: scaleX(1); }
/* Held while the pointer is over the list or the keyboard is inside it. The
   rail is the timer, so pausing the animation pauses the advance itself —
   there is no second clock to keep in step, and the line resumes from where
   it stopped rather than restarting or jumping to the end. Reading a step
   should not be a race against it. */
.how-steps.is-held .how-rail i { animation-play-state: paused; }
@keyframes how-fill { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@media (prefers-reduced-motion: reduce) {
  /* No animation is also no `animationend`, so the section stops advancing on
     its own: with reduced motion the list is yours to click through, which is
     what it already did and is now expressed in one place instead of two. */
  .how-rail i { animation: none; transform: scaleX(1); }
  body.how-enhanced .how-detail,
  body.how-enhanced .how-step.is-open .how-detail { transition: none; }
}




/* ==================================================================== landing

   The public page, section by section. It borrows the launch composer so the
   thing on the landing page is the thing you get after signing in; everything
   else here is its own, kept as plain as the reference: one bold headline,
   one line under it, one box. */

body.land { background: #fbf8f9; color: var(--text); }

/* ---------------------------------------------------------------- the bar */
.land-bar {
  position: sticky; top: 0; z-index: 20;
  display: flex; align-items: center; gap: 1.6rem;
  padding: .8rem 1.6rem;
  background: rgba(251, 248, 249, .82);
  -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px);
}
.land-nav { display: flex; gap: .2rem; }
.land-nav a {
  padding: .38rem .7rem; border-radius: 8px;
  color: var(--text); font-size: .9rem; font-weight: 500;
}
.land-nav a:hover { background: rgba(35, 21, 29, .06); text-decoration: none; }
.land-meta { margin-left: auto; display: flex; align-items: center; gap: .5rem; }
.land-login {
  padding: .5rem .9rem; border-radius: 10px;
  border: 1px solid var(--line-2); background: var(--paper);
  color: var(--text); font-size: .88rem; font-weight: 500;
}
.land-login:hover { background: var(--canvas); text-decoration: none; }
.land-cta {
  padding: .5rem .95rem; border-radius: 10px;
  background: #17131a; color: #fff; font-size: .88rem; font-weight: 600;
}
.land-cta:hover { background: #2b2229; color: #fff; text-decoration: none; }
@media (max-width: 720px) { .land-nav { display: none; } }

/* ---------------------------------------------------------------- the hero

   Nearly the whole viewport, and the wash is the point of it: white at the
   top so the bar sits on paper, haematoxylin through the middle, eosin at the
   foot. The white bloom behind the type is what keeps it legible over the
   stain; take it out and the headline sinks. */
.hero {
  position: relative; isolation: isolate;
  min-height: 86vh;
  display: grid; place-items: center;
  padding: 3rem 1.25rem 4rem;
  overflow: hidden;
}
.hero-wash {
  position: absolute; inset: 0; z-index: -1;
  /* The product's one wave (--ov-wave above: light in the light scheme, dark in the dark). */
  background: var(--ov-wave);
}
.hero-inner { width: 100%; max-width: 880px; text-align: center; }
.hero-title {
  font-family: var(--sans);
  font-size: clamp(2.2rem, 5.2vw, 3.45rem);
  font-weight: 700;
  letter-spacing: -.04em;
  line-height: 1.04;
  color: #17131a;
  margin: 0 auto .55rem;
  max-width: 20ch;
  text-wrap: balance;
}
.hero-sub {
  font-size: 1.05rem; color: #4a3d44;
  margin: 0 auto 1.6rem; max-width: 46ch;
}

.hero-composer {
  display: block; color: inherit; text-align: left;
  max-width: 720px; margin: 0 auto;
  border-radius: 20px;
  background: rgba(255, 255, 255, .92);
  box-shadow: 0 1px 2px rgba(98, 16, 44, .05), 0 24px 60px -24px rgba(98, 16, 44, .35);
}
.hero-composer:hover { text-decoration: none; }
.hero-composer .composer-bar { padding: .35rem .6rem .6rem; }
.hero-plus {
  width: 30px; height: 30px; border-radius: 50%;
  display: grid; place-items: center;
  border: 1px solid var(--line-2); color: var(--text-2); background: var(--paper);
}

/* ------------------------------------------------------------- the bands */
.band { padding: clamp(3.5rem, 8vw, 6rem) 1.5rem; }
.band-inner { max-width: 1180px; margin: 0 auto; }
.band h2 {
  font-family: var(--sans);
  font-size: clamp(1.7rem, 3.4vw, 2.4rem);
  font-weight: 700; letter-spacing: -.03em; line-height: 1.1;
  color: #17131a; margin: 0 0 .5rem; text-wrap: balance;
}
.band-lede { color: var(--text-2); font-size: 1.02rem; margin: 0 0 2rem; max-width: 52ch; }

/* The three cards. Same edges, same art height, same inner padding.

   `minmax(0, 1fr)` rather than `1fr`: the typing composer inside card one
   holds a `white-space: nowrap` sentence, and a plain `1fr` track floors at
   its min-content width — at 390px that pushed the card to the sentence's
   width and hung it 23px off the right edge of the page. The card clips the
   sentence at its own edge (`.mini-composer { overflow: hidden }`), which is
   only allowed to happen if the track may be narrower than its content. */
.trio { display: grid; gap: 1rem; grid-template-columns: minmax(0, 1fr); }
.trio-card, .trio-art { min-width: 0; }
@media (min-width: 860px) { .trio { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.trio-card {
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 16px;
  padding: .9rem .9rem 1.3rem;
  display: flex; flex-direction: column;
}
.trio-card h3 { font-size: 1rem; font-weight: 600; color: #17131a; margin: 1.15rem .3rem .35rem; }
.trio-card p { font-size: .9rem; line-height: 1.55; color: var(--text-2); margin: 0 .3rem; }
.trio-art {
  height: 240px; border-radius: 10px; overflow: hidden;
  display: grid; place-items: center; padding: 1.25rem;
  background:
    radial-gradient(60% 60% at 20% 20%, rgba(107, 70, 168, .18), transparent 70%),
    radial-gradient(60% 60% at 90% 90%, rgba(244, 144, 94, .18), transparent 70%),
    linear-gradient(160deg, #fdf5f8, #f7eef3);
}
.mini-composer {
  width: 100%; background: #fff; border-radius: 14px;
  padding: 1rem 1.1rem 2.4rem; color: var(--text-3); font-size: .92rem;
  box-shadow: 0 10px 30px -14px rgba(98, 16, 44, .35);
}
.mini-guard {
  width: 100%; background: #fff; border-radius: 12px; padding: .95rem 1.05rem;
  display: flex; flex-direction: column; gap: .35rem; font-size: .84rem;
  color: var(--text-2); box-shadow: 0 10px 30px -14px rgba(98, 16, 44, .35);
}
.mini-guard b { color: #17131a; font-size: .95rem; }
.mini-tag {
  align-self: flex-start; font-family: var(--mono); font-size: .75rem; font-weight: 600;
  color: var(--ink-600); background: var(--canvas-2); padding: .15rem .45rem; border-radius: 999px;
}
.mini-list {
  width: 100%; background: #fff; border-radius: 12px; padding: .7rem .5rem;
  display: flex; flex-direction: column; gap: .15rem;
  box-shadow: 0 10px 30px -14px rgba(98, 16, 44, .35);
}
.mini-list span {
  display: flex; align-items: center; gap: .55rem;
  padding: .45rem .7rem; border-radius: 8px; font-size: .86rem; color: var(--text-2);
}
.mini-list span.on { background: var(--canvas-2); color: #17131a; font-weight: 600; }
.mini-list .ico { color: var(--text-3); }
.mini-list span.on .ico { color: var(--ink-600); }

/* --------------------------------------------------------- the tile grid

   Providers the build has code for. Bright is built and tested; dim is
   declared and fails closed. Names rather than other companies' marks, which
   are theirs to use and not ours to paste. */
.tiles {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: .5rem;
  align-self: center;
}
.tile {
  aspect-ratio: 1;
  display: grid; place-items: center; text-align: center;
  padding: .4rem;
  border-radius: 12px;
  background: #221b25;
  border: 1px solid rgba(255, 255, 255, .07);
  color: #d9ccd3;
  font-size: .78rem; font-weight: 600; letter-spacing: -.01em;
  line-height: 1.2;
}
.tile-dim { color: #5c4f57; background: #1c1620; }
.tile-ov {
  background: linear-gradient(160deg, #6b46a8, #d63c74 55%, #f4905e);
  border-color: transparent;
  box-shadow: 0 0 0 1px rgba(255, 255, 255, .12), 0 18px 44px -12px rgba(214, 60, 116, .7);
}
@media (max-width: 560px) { .tiles { grid-template-columns: repeat(4, 1fr); } .tile { font-size: .75rem; } }

/* -------------------------------------------------------------- reviews

   The reference centres this band's heading over one wide card, and that is
   the shape kept here: head, then a rail whose middle is the card. Every
   colour comes from a token pair, so the card inverts with the rest of the
   page and needs no second declaration in theme-dark.css. */
.reviews-head { text-align: center; margin-bottom: 2.2rem; }
.reviews-head .band-lede { margin-inline: auto; max-width: 58ch; }

.reviews-rail {
  display: grid; gap: .75rem;
  grid-template-columns: minmax(0, 1fr);
  align-items: stretch;
  max-width: 900px; margin: 0 auto;
}
/* The flanking name cards only exist when there are other reviews to flank
   with, so the rail is one column until a second quote arrives. */
@media (min-width: 1040px) {
  .reviews-rail:has(.review-side) {
    max-width: none;
    grid-template-columns: minmax(0, .42fr) minmax(0, 1.6fr) minmax(0, .42fr);
  }
  .reviews-rail:has(.review-side) .review-card { grid-row: 1; }
  .reviews-rail:has(.review-side) > .review-side:nth-of-type(1) { grid-column: 1; grid-row: 1; }
  .reviews-rail:has(.review-side) > .review-side:nth-of-type(2) { grid-column: 3; grid-row: 1; }
  .reviews-rail:has(.review-side) .review-ledger { grid-column: 2; }
}
.review-side {
  display: grid; place-items: center; text-align: center;
  padding: 2rem 1rem; border-radius: 16px;
  background: var(--canvas-2); color: var(--text-2);
  font-weight: 600; letter-spacing: -.01em;
  /* Inset from the featured card's top and bottom, as the reference's
     flanking cards are: same ground, so height is what says which one the
     page is asking you to read. */
  margin-block: clamp(1rem, 2.5vw, 2.5rem);
}

.review-card {
  background: var(--canvas-2);
  border-radius: 16px;
  padding: clamp(1.4rem, 3vw, 2.2rem);
  display: grid; gap: 1.6rem;
  grid-template-columns: minmax(0, 1fr);
  align-content: start;
}
@media (min-width: 760px) {
  .review-card:has(.review-stats) {
    grid-template-columns: minmax(0, 1.45fr) minmax(0, 1fr); column-gap: 2.4rem;
  }
  .review-card .review-mark, .review-card .review-foot { grid-column: 1 / -1; }
}
.review-mark { margin: 0; display: flex; flex-wrap: wrap; align-items: center; gap: .6rem; }
.review-not { font-size: .8rem; color: var(--text-3); }
.review-note { margin: 0 0 1.1rem; font-size: .9rem; line-height: 1.55; color: var(--text-2); }
.review-title {
  margin: 0 0 .5rem; font-size: .82rem; font-weight: 600; letter-spacing: .02em;
  text-transform: uppercase; color: var(--ink-700);
}
.review-quote {
  margin: 0; border-left: 2px solid var(--line-2); padding-left: 1.1rem;
  font-family: var(--sans); font-weight: 600; letter-spacing: -.02em;
  font-size: clamp(1.15rem, 2.2vw, 1.55rem); line-height: 1.28; color: #17131a;
  text-wrap: pretty;
}
.review-ask {
  margin: 1rem 0 0; display: flex; gap: .45rem; align-items: baseline;
  font-size: .86rem; line-height: 1.5; color: var(--text-2);
}
.review-ask .ico { color: var(--ink-600); flex: none; }

/* The three figures, counted from the council run, in the reference's
   figure-over-caption order. */
.review-stats { margin: 0; display: grid; gap: 1.1rem; align-content: start; }
.review-stats div { display: grid; gap: .15rem; }
.review-stats dd {
  margin: 0; font-family: var(--sans); font-size: clamp(1.7rem, 3vw, 2.3rem);
  font-weight: 700; letter-spacing: -.04em; line-height: 1; color: #17131a;
  font-variant-numeric: tabular-nums;
}
.review-stats dt { font-size: .84rem; line-height: 1.4; color: var(--text-2); }

.review-foot {
  display: flex; flex-wrap: wrap; gap: 1rem; align-items: center;
  justify-content: space-between;
  border-top: 1px solid var(--line-2); padding-top: 1.2rem;
}
.review-who { display: flex; align-items: center; gap: .7rem; }
.review-mono {
  width: 38px; height: 38px; border-radius: 50%; flex: none;
  display: grid; place-items: center;
  background: var(--avatar-bg); color: var(--avatar-fg);
  font-size: .9rem; font-weight: 600;
}
.review-who b { display: block; font-size: .92rem; color: #17131a; }
.review-who i { display: block; font-style: normal; font-size: .82rem; color: var(--text-3); }
.review-perm { display: flex; align-items: center; gap: .35rem; font-size: .78rem; color: var(--text-3); }
.review-go {
  display: inline-flex; align-items: center; gap: .4rem;
  background: var(--paper); color: var(--text);
  border-radius: 999px; padding: .55rem .95rem;
  font-size: .86rem; font-weight: 600;
  box-shadow: var(--shadow-1);
}
.review-go:hover { background: var(--canvas); color: var(--ink-700); }

/* Every objection the council filed, not the one the card chose. Closed by
   default because the card is the point; open because the claim that the
   featured line was not cherry-picked is only checkable if the rest is here. */
.review-ledger { margin-top: .75rem; font-size: .86rem; }
.review-ledger summary {
  cursor: pointer; padding: .7rem .2rem; color: var(--text-2); font-weight: 600;
  list-style-position: inside;
}
.review-ledger summary:hover { color: var(--ink-700); }
.review-ledger ul { list-style: none; margin: .3rem 0 0; padding: 0; display: grid; gap: .1rem; }
.review-ledger li {
  display: grid; gap: .6rem; align-items: baseline;
  grid-template-columns: 5.4rem 4.6rem minmax(0, 1fr);
  padding: .5rem .2rem; border-top: 1px solid var(--line);
}
.review-sev {
  font-family: var(--mono); font-size: .75rem; font-weight: 600; text-transform: uppercase;
  letter-spacing: .04em; padding: .12rem .4rem; border-radius: 999px; text-align: center;
}
.sev-critical { background: var(--red-2); color: var(--red); }
.sev-major { background: var(--amber-2); color: var(--amber); }
.sev-minor { background: var(--canvas-2); color: var(--text-2); }
.review-state { font-family: var(--mono); font-size: .75rem; color: var(--text-3); }
.review-obj { color: var(--text-2); line-height: 1.45; }
.review-obj b { color: var(--text); font-weight: 600; }
.review-synthetic { margin: .9rem 0 0; font-size: .78rem; line-height: 1.5; color: var(--text-3); }
@media (max-width: 560px) {
  .review-ledger li { grid-template-columns: 5.4rem minmax(0, 1fr); }
  .review-ledger .review-state { grid-column: 1; }
  .review-ledger .review-obj { grid-column: 1 / -1; }
}

/* -------------------------------------------------------------- numbers */
.numbers { display: grid; gap: 2.5rem; align-items: center; }
@media (min-width: 900px) { .numbers { grid-template-columns: minmax(0, .9fr) minmax(0, 1.1fr); } }
.stats { margin: 0; display: grid; gap: 1.1rem; }
.stats div { display: grid; gap: .1rem; }
.stats dt { font-size: .8rem; color: var(--text-3); }
.stats dd {
  margin: 0; font-family: var(--sans); font-size: clamp(2rem, 4vw, 2.8rem);
  font-weight: 700; letter-spacing: -.04em; line-height: 1; color: #17131a;
  font-variant-numeric: tabular-nums;
}
.ramp { width: 100%; height: auto; display: block; }
.ramp-caption { font-size: .8rem; color: var(--text-3); margin: .6rem 0 0; }

/* -------------------------------------------------------------- closing

   The close and the footer are one region with one wash under both of them,
   because a gradient that stops at the footer's top edge is a gradient the
   reader never sees the end of. `.page-end` owns the wash; the band and the
   footer sit on it. The band keeps `position: relative` for its own stacking
   and nothing else — it no longer clips anything. */
/* The padding, not a margin on the footer, is what holds the gap under the
   card. A bottom margin there collapses straight out of this box — the wash
   ends above it and the page finishes on a strip of bare canvas, which is the
   ruled line again in a different colour. */
.page-end { position: relative; isolation: isolate; padding-bottom: 1.5rem; }
.closing {
  position: relative;
  padding: clamp(4rem, 9vw, 7rem) 1.25rem 2rem;
  text-align: center;
}
/* The full ramp, and the same one the hero runs: paper at the top so the band
   above it ends on its own ground, periwinkle and violet through the middle,
   eosin at the very foot of the page. The white bloom sits behind the heading
   and the composer — the same device the hero uses — so the type stays on
   paper while the wash behind it goes to full strength.

   theme-dark.css restates this through `--wash-closing` for both schemes and
   wins by order; this declaration is what a build with no theme sheet gets. */
.closing-wash {
  position: absolute; inset: 0; z-index: -1;
  background:
    radial-gradient(52% 30% at 50% 22%, rgba(255, 255, 255, .94) 0%, rgba(255, 255, 255, 0) 70%),
    radial-gradient(40% 26% at 2% 54%,  #8fa0ff 0%, transparent 62%),
    radial-gradient(40% 26% at 98% 52%, #a996ff 0%, transparent 62%),
    radial-gradient(64% 30% at 50% 96%, #ff5fae 0%, transparent 66%),
    radial-gradient(44% 24% at 8% 106%, #ff8a6f 0%, transparent 60%),
    radial-gradient(44% 24% at 92% 106%, #ff4e8f 0%, transparent 60%),
    linear-gradient(180deg, #fbf8f9 0%, #f0eefb 16%, #dcdcff 40%, #c9b6ff 58%, #ffa9d5 82%, #ff6f9e 100%);
}
.closing-inner { max-width: 640px; margin: 0 auto; }
.closing-eyebrow {
  font-size: .85rem; color: var(--text-2); margin: 0 0 .3rem;
}
.closing h2 {
  font-family: var(--sans);
  font-size: clamp(1.7rem, 3.6vw, 2.4rem);
  font-weight: 700; letter-spacing: -.035em; line-height: 1.08;
  color: #17131a; margin: 0 0 1.4rem;
}

/* --------------------------------------------------------------- footer

   A card on the wash, not a slab under it: the gradient shows down both sides
   and under the bottom edge, so the page ends on colour rather than on the
   footer's own cream. Opaque, because the links and the research-use line
   have to hold their contrast wherever on the ramp the card happens to land. */
.foot {
  width: min(1180px, calc(100% - 2.5rem)); margin: 0 auto;
  background: #f5eff2; border-radius: 22px;
  padding: 2.4rem 2rem 1.6rem;
}
.foot-inner { display: grid; gap: 2rem; }
@media (min-width: 760px) { .foot-inner { grid-template-columns: 120px 1fr; } }
.foot-cols { display: grid; gap: 1.6rem; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); }
.foot-cols h4 { margin: 0 0 .6rem; font-size: .88rem; color: #17131a; }
.foot-cols a, .foot-cols span { display: block; font-size: .86rem; color: var(--text-2); margin: .3rem 0; }
.foot-cols a:hover { color: var(--ink-700); }
.foot-ruo {
  margin: 2rem 0 0; padding-top: 1.2rem;
  border-top: 1px solid var(--line); font-size: .8rem; color: var(--text-3);
  display: flex; gap: .45rem; align-items: flex-start;
}


/* ------------------------------------------------------------ the mark, live

   In a headline the mark is the O of OVision, and the dot — the finding —
   drops into the ring when the page opens. Once, on load, in under a second,
   and only in the headline: the bar, the footer and the favicon stay still,
   because a logo that moves every time you glance at it is a logo you stop
   trusting. Honours the OS reduced-motion setting by not moving at all. */
.stage-mark .logo { overflow: visible; }
.stage-mark .logo-dot {
  animation: ov-drop .85s cubic-bezier(.22, .9, .3, 1.15) .2s both;
}
@keyframes ov-drop {
  0%   { transform: translateY(-22px); opacity: 0; }
  40%  { opacity: 1; }
  100% { transform: translateY(0); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .stage-mark .logo-dot { animation: none; }
}


/* ================================================================ the app shell

   The signed-in home: a slim rail and a composer on a full wash. */

body.app { background: var(--ground); }
.app-shell { display: grid; grid-template-columns: 250px minmax(0, 1fr); min-height: 100vh; }
@media (max-width: 820px) { .app-shell { grid-template-columns: 56px minmax(0, 1fr); } }

.rail {
  background: var(--paper);
  border-right: 1px solid var(--line);
  padding: .9rem .7rem 1rem;
  display: flex; flex-direction: column; gap: .35rem;
  position: sticky; top: 0; height: 100vh; overflow-y: auto;
}
.rail-brand { display: inline-flex; padding: .2rem .5rem .55rem; }
.rail-ws {
  display: flex; align-items: center; gap: .55rem;
  margin: 0 0 .5rem; padding: .45rem .6rem;
  border: 1px solid var(--line-2); border-radius: 10px; background: var(--paper);
  font-size: .86rem; font-weight: 600; color: var(--text);
}
.rail-ws select { border: 0; background: none; font: inherit; font-weight: 600; width: 100%; padding: 0; }
.rail-ws select:focus { outline: none; box-shadow: none; }
.rail-ws-mark {
  width: 20px; height: 20px; border-radius: 5px; flex: none;
  background: linear-gradient(160deg, #6b46a8, #d63c74); color: #fff;
  font-size: .68rem; font-weight: 700; display: grid; place-items: center;
}
.rail-ws-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.rail-nav { display: flex; flex-direction: column; gap: 1px; }
.rail-nav a {
  display: flex; align-items: center; gap: .6rem;
  padding: .48rem .6rem; border-radius: 9px;
  color: var(--text); font-size: .9rem; font-weight: 500;
}
.rail-nav a .ico { color: var(--text-3); }
.rail-nav a:hover { background: var(--canvas-2); text-decoration: none; }
.rail-nav a[aria-current="page"] { background: var(--canvas-2); font-weight: 600; }
.rail-nav a[aria-current="page"] .ico { color: var(--ink-700); }
.rail-nav kbd {
  margin-left: auto; font-family: var(--mono); font-size: .75rem; color: var(--text-3);
  border: 1px solid var(--line-2); border-radius: 5px; padding: .05rem .3rem;
}
.rail-label {
  display: block; font-size: .75rem; font-weight: 600; letter-spacing: .06em;
  text-transform: uppercase; color: var(--text-3); padding: .9rem .6rem .3rem;
}
.rail-recents { display: flex; flex-direction: column; }
.rail-recents a {
  padding: .34rem .6rem; border-radius: 8px; font-size: .86rem; color: var(--text-2);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.rail-recents a:hover { background: var(--canvas-2); text-decoration: none; color: var(--text); }
.rail-recents .rail-more { color: var(--text-3); font-size: .8rem; }

.rail-foot { margin-top: auto; display: flex; flex-direction: column; gap: .6rem; padding-top: .8rem; }
.rail-upgrade {
  display: flex; align-items: center; justify-content: space-between; gap: .6rem;
  padding: .7rem .8rem; border-radius: 12px;
  border: 1px solid var(--line-2); background: var(--paper);
  color: var(--text); box-shadow: var(--shadow-1);
}
.rail-upgrade:hover { border-color: var(--ink-500); text-decoration: none; }
.rail-upgrade span { display: flex; flex-direction: column; gap: .1rem; }
.rail-upgrade b { font-size: .86rem; }
.rail-upgrade small { font-size: .75rem; color: var(--text-3); }
.rail-upgrade .ico {
  width: 30px; height: 30px; padding: 7px; border-radius: 8px; flex: none;
  background: var(--haem-soft, #f1ecf9); color: var(--violet);
}
.avatar.sm { width: 22px; height: 22px; font-size: .6rem; }

/* ---------------------------------------------------------------- the main */
.app-main { position: relative; isolation: isolate; display: flex; flex-direction: column; min-width: 0; }
.app-wash { position: absolute; inset: 0 0 auto; height: 78vh; z-index: -1; }

.dash {
  width: 100%; max-width: 760px; margin: 0 auto;
  padding: clamp(3.5rem, 12vh, 8rem) 1.25rem 2.5rem;
  text-align: center;
  display: flex; flex-direction: column; align-items: center; gap: 1rem;
}
.dash-pill {
  display: inline-flex; align-items: center; gap: .45rem;
  padding: .42rem .9rem .42rem .7rem; border-radius: 999px;
  background: rgba(255, 255, 255, .8); border: 1px solid rgba(98, 16, 44, .1);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  font-size: .84rem; font-weight: 600; color: var(--text);
}
.dash-pill:hover { background: #fff; text-decoration: none; }
.dash-title {
  font-family: var(--sans);
  font-size: clamp(1.7rem, 3.6vw, 2.3rem);
  font-weight: 700; letter-spacing: -.035em; line-height: 1.1;
  color: #17131a; margin: .2rem 0 .3rem;
}
.dash-sub { color: var(--text-2); margin: 0 0 .4rem; }
.dash-composer { width: 100%; text-align: left; }
.dash-composer .composer-input { min-height: 3.6rem; padding-bottom: .1rem; }

.jump { width: 100%; max-width: 680px; text-align: left; display: flex; flex-direction: column; gap: .5rem; margin-top: 1.4rem; }
.jump-label { display: inline-flex; align-items: center; gap: .35rem; font-size: .82rem; font-weight: 600; color: var(--text); }
.jump-card {
  display: flex; align-items: center; gap: 1rem;
  padding: .6rem; border-radius: 16px;
  background: rgba(255, 255, 255, .78); border: 1px solid rgba(98, 16, 44, .1);
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
  color: var(--text);
}
.jump-card:hover { background: rgba(255, 255, 255, .95); text-decoration: none; }
.jump-art {
  width: 120px; height: 72px; border-radius: 10px; flex: none;
  display: grid; place-items: center;
  background: linear-gradient(160deg, var(--canvas-2), #fff);
}
.jump-body { display: flex; flex-direction: column; gap: .15rem; min-width: 0; flex: 1; }
.jump-body b { font-size: .95rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.jump-body span { font-size: .82rem; color: var(--text-2); }

.dash-panel {
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 20px 20px 0 0;
  margin: 1rem 1.25rem 0;
  padding: 1.1rem 1.25rem 1.6rem;
  box-shadow: 0 -2px 40px -18px rgba(98, 16, 44, .25);
}
.dash-tabs { display: flex; align-items: center; gap: .25rem; margin-bottom: 1rem; }
.dash-tab {
  padding: .38rem .8rem; border-radius: 999px; font-size: .86rem; font-weight: 500;
  color: var(--text-2); border: 1px solid transparent;
}
.dash-tab:hover { text-decoration: none; color: var(--text); }
.dash-tab.is-on { border-color: var(--line-2); background: var(--paper); color: var(--text); font-weight: 600; }
.dash-browse { margin-left: auto; font-size: .86rem; font-weight: 600; color: var(--text); display: inline-flex; gap: .3rem; align-items: center; }

.study-grid { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); }
.study-card { display: flex; flex-direction: column; gap: .6rem; color: var(--text); }
.study-card:hover { text-decoration: none; }
.study-art {
  aspect-ratio: 16 / 10; border-radius: 12px;
  border: 1px solid var(--line); background: var(--canvas-2);
  display: grid; place-items: center;
}
.study-card:hover .study-art { border-color: var(--line-2); background: var(--canvas); }
.study-meta { display: flex; align-items: center; gap: .55rem; min-width: 0; }
.study-meta > span:last-child { display: flex; flex-direction: column; min-width: 0; }
.study-meta b { font-size: .9rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.study-meta small { font-size: .78rem; color: var(--text-3); }

/* ============================================================ the catalogue */
.cx { display: grid; gap: 1.25rem; align-items: start; }
@media (min-width: 900px) { .cx { grid-template-columns: 220px minmax(0, 1fr); } }
.cx-side { display: flex; flex-direction: column; gap: 2px; position: sticky; top: 1rem; }
.cx-search {
  display: flex; align-items: center; gap: .45rem;
  border: 1px solid var(--line-2); border-radius: 10px; padding: .45rem .65rem;
  background: var(--paper); margin-bottom: .5rem; color: var(--text-3);
}
.cx-search input { border: 0; background: none; padding: 0; font: inherit; width: 100%; }
.cx-search input:focus { outline: none; box-shadow: none; }
.cx-cat {
  display: flex; justify-content: space-between; gap: .5rem;
  padding: .42rem .6rem; border-radius: 8px; font-size: .88rem; color: var(--text);
}
.cx-cat span { color: var(--text-3); font-size: .8rem; font-variant-numeric: tabular-nums; }
.cx-cat:hover { background: var(--canvas-2); text-decoration: none; }
.cx-cat.is-on { background: var(--canvas-2); font-weight: 600; }
.cx-request {
  margin-top: 1rem; padding: .9rem; border-radius: 12px;
  border: 1px solid var(--line); background: var(--paper);
  display: flex; flex-direction: column; gap: .5rem; align-items: flex-start;
  font-size: .86rem;
}
.cx-request .ico { color: var(--text-3); }
.cx-request .btn { align-self: stretch; justify-content: center; }

.cx-h2 {
  display: flex; align-items: center; gap: .4rem;
  font-size: .78rem; letter-spacing: .07em; text-transform: uppercase; font-weight: 700;
  color: var(--text-3); margin: 1.4rem 0 .6rem;
}
.cx-grid { display: grid; gap: .6rem; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); }
.cx-card {
  display: flex; align-items: center; gap: .8rem;
  padding: .6rem .75rem; border-radius: 12px;
  border: 1px solid var(--line); background: var(--paper);
}
.cx-card[hidden] { display: none; }
.cx-off { opacity: .6; }
.cx-body { display: flex; flex-direction: column; min-width: 0; }
.cx-body b { font-size: .9rem; display: flex; align-items: center; gap: .4rem; }
.cx-body small { font-size: .78rem; color: var(--text-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cx-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--line-2); flex: none; }
.cx-dot.on { background: var(--green); }
.cx-dot.mid { background: var(--amber); }

/* ============================================================== onboarding */
.ob {
  width: 100%; max-width: 760px; margin: 0 auto;
  padding: clamp(4rem, 14vh, 9rem) 1.25rem 3rem;
  text-align: center; display: flex; flex-direction: column; align-items: center; gap: 1.2rem;
}
.ob-title {
  font-family: var(--sans); font-size: clamp(1.7rem, 3.6vw, 2.2rem);
  font-weight: 700; letter-spacing: -.035em; color: #17131a; margin: 0;
}
.ob-tiles { display: grid; gap: .8rem; grid-template-columns: repeat(2, minmax(0, 1fr)); width: 100%; max-width: 640px; }
@media (min-width: 640px) { .ob-tiles { grid-template-columns: repeat(4, 1fr); } }
.ob-tile-form { display: contents; }
.ob-tile {
  all: unset; box-sizing: border-box; cursor: pointer;
  display: flex; flex-direction: column; align-items: center; gap: .4rem;
  padding: 1.3rem .8rem 1.1rem; border-radius: 14px;
  border: 1px solid var(--line-2); background: rgba(255, 255, 255, .8);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  color: var(--text); text-align: center;
  transition: border-color .12s ease, transform .12s ease;
}
.ob-tile:hover { border-color: var(--ink-500); transform: translateY(-1px); }
.ob-tile:focus-visible { outline: 2px solid var(--ink-500); outline-offset: 3px; }
.ob-tile .ico { color: var(--ink-700); }
.ob-tile span { font-size: .9rem; font-weight: 600; }
.ob-tile small { font-size: .75rem; color: var(--text-3); }
.ob-note { font-size: .82rem; color: var(--text-3); margin: 0; }

/* ==================================================================== auth */
body.auth { background: var(--canvas); position: relative; isolation: isolate; min-height: 100vh; }
.auth-wash { position: fixed; inset: 0; z-index: -1; }
.auth-shell { min-height: 100vh; display: grid; place-items: center; padding: 2rem 1rem; }
.auth-card {
  width: 100%; max-width: 380px;
  background: var(--paper); border-radius: 22px;
  padding: 1.6rem 1.6rem 1.3rem;
  box-shadow: 0 30px 80px -30px rgba(98, 16, 44, .45), 0 1px 2px rgba(98, 16, 44, .06);
}
.auth-mark { display: inline-flex; margin-bottom: 1rem; }
.auth-eyebrow { margin: 0; font-size: 1.15rem; font-weight: 600; color: var(--text-3); }
.auth-title {
  font-family: var(--sans); font-size: 1.45rem; font-weight: 700; letter-spacing: -.025em;
  color: #17131a; margin: 0 0 1.1rem;
}
.auth-form { display: flex; flex-direction: column; gap: .55rem; }
.auth-form input { width: 100%; padding: .7rem .85rem; border-radius: 10px; font-size: .95rem; }
.auth-go {
  margin-top: .3rem; width: 100%; justify-content: center;
  padding: .75rem 1rem; border-radius: 10px;
  background: #17131a; border-color: #17131a; color: #fff; font-weight: 600;
}
.auth-go:hover { background: #2b2229; border-color: #2b2229; }
.auth-alt { margin: .9rem 0 0; font-size: .86rem; color: var(--text-2); }
.auth-fine { margin: .6rem 0 0; font-size: .78rem; color: var(--text-3); line-height: 1.5; }
.auth-ruo {
  margin: 1.1rem 0 0; padding-top: .9rem; border-top: 1px solid var(--line);
  font-size: .76rem; color: var(--text-3); display: flex; gap: .35rem; align-items: center;
}

.rail-edition { align-self: flex-start; margin: 0 0 .4rem .3rem; font-size: .75rem; }

/* Narrow: the rail narrows to its icons rather than going away.

   It used to hide entirely below 820px and hand over to the account strip,
   and that produced the same report three times — "where is the sidebar?" —
   because a browser at 125% zoom is a narrow browser, and a strip in the
   normal flow scrolls off the top. A 56px rail costs a phone almost nothing
   and is never missing. This block lives at the END of the file on purpose:
   it used to sit above the base `.rail` rule, which won at equal specificity,
   so the rule did nothing at all. Last in the cascade means it cannot be
   silently undone by a rule that merely comes later.

   The strip itself, and the phone drawer that replaced it at 640px and
   below, now live at the end of shell.css ("the rail, narrow"), which every
   signed-in page loads after this sheet — the same guarantee, one step
   later. The account menu's narrow rules are in account-menu.css. */

/* ------------------------------------------------------------- scrollbars

   Appended block: a global concern, and this is the only sheet every surface
   links (the landing takes ovision + landing-extra + theme-dark; the app
   takes ovision + shell + page + system + theme-dark). Nothing above is
   modified.

   The problem this fixes. macOS defaults to overlay scrollbars, which are
   invisible until the moment you scroll and then fade. On a 4,300px landing
   page in a 900px viewport that leaves no indication there is anything below
   the fold — measured: `window.innerWidth - documentElement.clientWidth` was
   0, so nothing was reserved or drawn. Styling ::-webkit-scrollbar opts the
   document out of overlay behaviour, so the bar is always there.

   Every colour is a token, so dark needs nothing added: --line-2 and
   --text-3 both invert with the scheme, which is the rule the token-pair
   guard exists to keep (tests/discovery/test_theme_token_pairs.py). */
/* Firefox only. The standard properties and ::-webkit-scrollbar are not
   additive: from Chrome 121 a specified `scrollbar-width` switches the
   element to the standard path and the pseudo-elements below are ignored —
   which on macOS means overlay behaviour and an invisible bar, i.e. setting
   this unguarded cancels the very fix underneath it. @supports keeps each
   engine on the one it actually honours. */
@supports not selector(::-webkit-scrollbar) {
  * { scrollbar-width: thin; scrollbar-color: var(--line-2) transparent; }
}

::-webkit-scrollbar { width: 11px; height: 11px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background-color: var(--line-2);
  border-radius: 8px;
  /* The border is the inset: a transparent ring clipped to the padding box
     leaves the thumb looking 7px wide with 2px of air either side, which is
     what makes it read as quiet rather than as a browser default. */
  border: 2px solid transparent;
  background-clip: padding-box;
}
::-webkit-scrollbar-thumb:hover { background-color: var(--text-3); }
::-webkit-scrollbar-corner { background: transparent; }

/* Reserve the gutter so a page that grows past the fold after load does not
   shift sideways when the bar appears. `stable` keeps the space on the side
   the bar will use, and costs nothing on a page that never scrolls. */
html { scrollbar-gutter: stable; }

/* The headline mark draws itself.

   Beside the dot that already drops into it (ov-drop above), the ring now
   draws round once as the page opens, so the O is written rather than simply
   present. Same rule as the dot and for the same reason: once, on load,
   headline only — the bar, the footer and the favicon stay still, because a
   logo that moves every time you glance at it is a logo you stop trusting.

   The dasharray is the ring's circumference, 2*pi*11.4 = 71.6, rounded up so
   no hairline of the last degree is left undrawn. It starts at twelve
   o'clock: the circle's own zero is at three, so the element is rotated a
   quarter turn about the mark's centre, which moves where the stroke begins
   and nothing else. The dot's delay (.2s) already lands it after the ring is
   most of the way round, so the two read as one gesture. */
.stage-mark .logo-ring {
  stroke-dasharray: 72;
  stroke-dashoffset: 72;
  transform: rotate(-90deg);
  transform-origin: 16px 16px;
  animation: ov-draw .9s cubic-bezier(.22, .61, .36, 1) both;
}
@keyframes ov-draw { to { stroke-dashoffset: 0; } }
@media (prefers-reduced-motion: reduce) {
  .stage-mark .logo-ring { animation: none; stroke-dashoffset: 0; }
}

/* ============================================================== validation
   OVision's own bubble for a field the browser will not send (validate.js).
   The browser still decides what is invalid; this only says so in the
   product's words and colours, here because every shell loads this sheet.
   Paper, a hairline and a shadow, an amber "!" beside the words (never the
   colour alone), and an arrow pointing at the field. */
.ov-invalid {
  position: fixed; z-index: 1000; top: 0; left: 0;
  display: flex; align-items: flex-start; gap: .55rem;
  max-width: min(340px, calc(100vw - 16px));
  padding: .6rem .85rem .6rem .6rem; border-radius: 12px;
  background: var(--paper); color: var(--text); border: 1px solid var(--line-2);
  box-shadow: var(--shadow-3);
  font-family: var(--sans); font-size: .86rem; font-weight: 500; line-height: 1.4; text-align: left;
  animation: ov-invalid-in .14s ease-out;
}
.ov-invalid::before {
  content: ""; position: absolute; top: -6px; left: calc(var(--ov-arrow, 20px) - 5px);
  width: 10px; height: 10px; background: var(--paper);
  border-left: 1px solid var(--line-2); border-top: 1px solid var(--line-2);
  transform: rotate(45deg);
}
.ov-invalid.is-above::before { top: auto; bottom: -6px; transform: rotate(225deg); }
.ov-invalid-mark {
  flex: none; display: grid; place-items: center; width: 20px; height: 20px; border-radius: 6px;
  background: var(--amber-2); color: var(--amber); border: 1px solid var(--amber-line);
  font-size: .8rem; font-weight: 800; line-height: 1;
}
.ov-invalid-msg { padding-top: 1px; }
@keyframes ov-invalid-in { from { opacity: 0; transform: translateY(-3px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) {
  .ov-invalid { animation: none; }
}

/* ============================================================== dropdowns
   OVision's own menu for a <select> (select.js), here because every shell
   loads this sheet. The select stays in the page as the real form control,
   out of sight but focusable, which the browser needs to validate a required
   one; beside it a button shows the choice, and a listbox under it gives the
   whole text of every option, wrapped, with a quieter second line where the
   option carries one (data-description). Colours are tokens only, so both
   schemes follow. The button is written as `button.ov-select-trigger
   [aria-haspopup]`, one step more specific than the page column's
   `.content button` (shell.css, which paints every button as a primary and
   loads after this sheet), and its hover restates the colours for the same
   reason. Where a select has its own shape — the rail's profile switcher,
   the first-run workspace switcher, the Reports switcher, the research
   focus row, the composer's no-script chips, the usage filters — the button
   is given that shape at the end of this block. */
select.ov-select-native {
  position: absolute !important; width: 1px !important; height: 1px !important;
  min-width: 0 !important; max-width: none !important; min-height: 0 !important;
  margin: -1px !important; padding: 0 !important; border: 0 !important;
  overflow: hidden !important; clip: rect(0 0 0 0) !important; clip-path: inset(50%) !important;
  white-space: nowrap !important; pointer-events: none !important;
}
button.ov-select-trigger[aria-haspopup="listbox"] {
  display: inline-flex; align-items: center; justify-content: space-between; gap: .5rem;
  width: 100%; max-width: 100%; min-width: 0; min-height: 0; margin: 0;
  padding: .55rem .75rem; border: 1px solid var(--line-2); border-radius: 10px;
  font: inherit; font-weight: 400; letter-spacing: normal; text-align: left; text-transform: none;
  vertical-align: middle; cursor: pointer; box-shadow: none; text-decoration: none;
  transition: border-color .12s ease, box-shadow .12s ease;
}
button.ov-select-trigger[aria-haspopup="listbox"],
button.ov-select-trigger[aria-haspopup="listbox"]:hover {
  background: var(--paper); color: var(--text); border-color: var(--line-2); text-decoration: none;
}
button.ov-select-trigger[aria-haspopup="listbox"]:hover { border-color: color-mix(in srgb, var(--line-2), var(--text-3) 45%); }
button.ov-select-trigger[aria-haspopup="listbox"][aria-expanded="true"] { border-color: var(--ink-500); }
button.ov-select-trigger[aria-haspopup="listbox"]:focus-visible {
  border-color: var(--ink-500); outline: 2px solid var(--ink-600); outline-offset: 2px;
}
/* Disabled, the way every control here says it: flat and quiet, the words
   still readable, the cursor refusing. */
button.ov-select-trigger[aria-haspopup="listbox"]:disabled,
button.ov-select-trigger[aria-haspopup="listbox"]:disabled:hover {
  background: var(--canvas-2); color: var(--text-2); border-color: var(--line-2); cursor: not-allowed;
}
button.ov-select-trigger[aria-haspopup="listbox"][hidden] { display: none; }
.ov-select-value { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ov-select-value.is-placeholder { color: var(--text-3); }
.ov-select-chev { flex: none; color: var(--text-3); transition: transform .15s ease; }
button.ov-select-trigger[aria-expanded="true"] .ov-select-chev { transform: rotate(180deg); }

/* The list. In the top layer where the browser has one (a popover), so no
   scroll container or dialog clips it; select.js places it under the button
   at the button's width, or above it when there is more room there. It takes
   none of its parent's type: a list opened from a small label is still read
   at the size of the page. */
.ov-select-list {
  position: fixed; inset: auto; z-index: 1001; margin: 0;
  box-sizing: border-box; height: auto; min-width: 0; max-width: calc(100vw - 16px);
  overflow-x: hidden; overflow-y: auto; overscroll-behavior: contain;
  padding: .3rem; border: 1px solid var(--line-2); border-radius: 12px;
  background: var(--paper); color: var(--text); box-shadow: var(--shadow-3);
  font-family: var(--sans); font-size: .875rem; font-style: normal; font-weight: 400; line-height: 1.4;
  letter-spacing: normal; text-align: left; text-transform: none; white-space: normal;
  cursor: default; -webkit-user-select: none; user-select: none; -webkit-tap-highlight-color: transparent;
  animation: ov-select-in .12s ease-out;
}
.ov-select-list.is-above { animation-name: ov-select-in-above; }
.ov-select-option {
  display: flex; align-items: flex-start; gap: .6rem;
  padding: .5rem .6rem; border-radius: 8px; color: var(--text); cursor: pointer;
}
.ov-select-option.is-active { background: var(--canvas-2); }
.ov-select-option[aria-disabled="true"] { color: var(--text-3); cursor: not-allowed; }
.ov-select-text { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: .15rem; }
.ov-select-label { overflow-wrap: anywhere; }
.ov-select-option[aria-selected="true"] .ov-select-label { font-weight: 600; }
.ov-select-desc { font-size: .8rem; line-height: 1.45; color: var(--text-2); overflow-wrap: anywhere; }
.ov-select-option[aria-disabled="true"] .ov-select-desc { color: var(--text-3); }
.ov-select-check { flex: none; margin-top: .1rem; color: var(--ink-600); visibility: hidden; }
.ov-select-option[aria-selected="true"] .ov-select-check { visibility: visible; }
.ov-select-group + .ov-select-group, .ov-select-option + .ov-select-group {
  margin-top: .3rem; padding-top: .3rem; border-top: 1px solid var(--line);
}
/* An option after a group is not in it: the same rule separates it, drawn
   clear of the row so its highlight keeps its rounded shape. */
.ov-select-group + .ov-select-option { position: relative; margin-top: .6rem; }
.ov-select-group + .ov-select-option::before {
  content: ""; position: absolute; left: 0; right: 0; top: -.3rem; border-top: 1px solid var(--line);
}
.ov-select-group-label {
  padding: .4rem .6rem .2rem; font-size: .75rem; font-weight: 650; letter-spacing: .06em;
  text-transform: uppercase; color: var(--text-3);
}
@keyframes ov-select-in { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }
@keyframes ov-select-in-above { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) {
  .ov-select-list, .ov-select-list.is-above { animation: none; }
  .ov-select-chev { transition: none; }
}
/* A finger needs a row it can hit. */
@media (max-width: 640px) {
  .ov-select-option { min-height: 44px; align-items: center; }
  .ov-select-check { margin-top: 0; }
}

/* Selects with a shape of their own; each mirrors the select's rule it names. */
.rail-profile button.ov-select-trigger[aria-haspopup="listbox"] {                /* account-menu.css */
  padding: .28rem .5rem; font-size: .76rem; border-radius: 8px;
}
.rail-profile button.ov-select-trigger[aria-haspopup="listbox"],
.rail-profile button.ov-select-trigger[aria-haspopup="listbox"]:hover { color: var(--text-2); }
.fr-ws-form button.ov-select-trigger[aria-haspopup="listbox"] {                  /* shell.css */
  width: auto; max-width: 20ch; padding: .25rem .5rem; font-size: .82rem; border-radius: 8px; border-color: var(--line);
}
.fr-ws-form button.ov-select-trigger[aria-haspopup="listbox"],
.fr-ws-form button.ov-select-trigger[aria-haspopup="listbox"]:hover { color: var(--text-2); }
.ov-switch button.ov-select-trigger[aria-haspopup="listbox"] { width: auto; max-width: 28ch; }   /* product.css */
.pe-focus-form button.ov-select-trigger[aria-haspopup="listbox"] {               /* grounding.css */
  width: auto; min-height: 32px; padding: .3rem .65rem; font-size: .84rem;
}
.composer-select button.ov-select-trigger[aria-haspopup="listbox"] {             /* above, and home.css */
  width: auto; max-width: 22ch; padding: 0; border: 0; font-size: .845rem; font-weight: 500;
}
.composer-select button.ov-select-trigger[aria-haspopup="listbox"],
.composer-select button.ov-select-trigger[aria-haspopup="listbox"]:hover { background: none; color: inherit; }
.composer-fallback .composer-select button.ov-select-trigger[aria-haspopup="listbox"] { max-width: 18ch; }
.usage .use-filters button.ov-select-trigger[aria-haspopup="listbox"] {          /* usage.css */
  width: auto; min-width: 120px; max-width: 220px; font-size: .82rem;
}
@media (max-width: 720px) {
  .usage .use-filters button.ov-select-trigger[aria-haspopup="listbox"] { width: 100%; max-width: none; }
}
@media (max-width: 620px) {
  .composer-select button.ov-select-trigger[aria-haspopup="listbox"] { max-width: 13ch; }
}
