/* oddly web dashboard v2. Design-handoff-2026-07-02 (Kyle + Claude Design,
 * final intent). The five-view logged-in product: Today / Plays / Benchmarks /
 * Connections / Log. One shell (sticky top bar + route tabs), no sidebar.
 *
 * Consumes the design-spine-v2 token layer (/_shared/oddly-tokens.css):
 * Newsreader display serif, Hanken Grotesk body sans, the cream/ink/teal/gold
 * palette, v2 radii + tints. Everything here is scoped under .odv2 so it never
 * touches the legacy sidebar dashboard, and so the .oddly-cockpit titan cascade
 * (injected by chrome.js) cannot bleed into the new shell.
 *
 * Served at /_shared/oddly-dashboard-v2.css; the ?v= is a content hash rewritten
 * by scripts/sync-asset-versions.ts (never hand-edited).
 *
 * Colour discipline mirrors the handoff: teal is the only action colour, gold is
 * the money / premium signal only. No em-dashes, middot (·) as the separator.
 */

.odv2,
.odv2 * {
  box-sizing: border-box;
}
.odv2 {
  min-height: 100vh;
  background: var(--oddly-canvas, #FAFAF7);
  color: var(--oddly-ink, #1A1A2E);
  font-family: var(--oddly-font-sans, "Hanken Grotesk", system-ui, sans-serif);
  -webkit-font-smoothing: antialiased;
}
.odv2 ::selection {
  background: var(--oddly-teal, #2C7873);
  color: var(--oddly-canvas, #FAFAF7);
}

/* ---- shell / top bar ---- */
.odv2-topbar {
  position: sticky;
  top: 0;
  z-index: 20;
  background: var(--oddly-canvas, #FAFAF7);
  border-bottom: 1px solid rgba(26, 26, 46, 0.09);
}
.odv2-topbar-inner {
  max-width: 1280px;
  margin: 0 auto;
  padding: 0 32px;
  height: 64px;
  display: flex;
  align-items: center;
  gap: 28px;
}
.odv2-brand {
  display: flex;
  align-items: center;
  gap: 12px;
}
.odv2-wordmark {
  font-family: var(--oddly-font-serif, "Newsreader", Georgia, serif);
  font-size: 22px;
  font-weight: 500;
  letter-spacing: -0.02em;
  text-decoration: none;
}
/* The full stop is the mark's accent glyph, painted by
 * /_shared/oddly-mark.css. */
.odv2-slash {
  font-size: 13px;
  color: rgba(26, 26, 46, 0.35);
}
.odv2-store {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 14px;
  font-weight: 600;
  /* The bar scrolls horizontally on a phone, so the store name rides along
     rather than wrapping onto a second line and pushing the bar taller. */
  white-space: nowrap;
}
.odv2-livedot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--oddly-teal, #2C7873);
}
.odv2-tabs {
  display: flex;
  align-items: center;
  gap: 4px;
}
.odv2-tab {
  padding: 8px 14px;
  border-radius: 8px;
  font-size: 14px;
  font-weight: 600;
  font-family: inherit;
  color: rgba(26, 26, 46, 0.5);
  background: transparent;
  border: none;
  cursor: pointer;
  text-decoration: none;
}
.odv2-tab:hover {
  color: rgba(26, 26, 46, 0.8);
}
.odv2-tab.is-active {
  color: var(--oddly-ink, #1A1A2E);
  background: rgba(26, 26, 46, 0.07);
}
.odv2-topbar-right {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 18px;
}
.odv2-plan {
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  font-weight: 700;
  color: var(--oddly-gold, #B08D57);
  border: 1px solid rgba(176, 141, 87, 0.4);
  padding: 5px 12px;
  border-radius: 20px;
  white-space: nowrap;
  text-decoration: none;
}
.odv2-readago {
  font-size: 13px;
  color: rgba(26, 26, 46, 0.5);
}
.odv2-avatar {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: var(--oddly-ink, #1A1A2E);
  color: var(--oddly-canvas, #FAFAF7);
  font-size: 13px;
  font-weight: 700;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  text-decoration: none;
  font-family: inherit;
  border: none;
  padding: 0;
  cursor: pointer;
}
.odv2-avatar:focus-visible,
.odv2-storeswitch-select:focus-visible {
  outline: 2px solid var(--oddly-teal, #2C7873);
  outline-offset: 2px;
}

/* ---- account menu (handoff account panel: identity, destinations, sign out) ---- */
.odv2-acct {
  position: relative;
}
.odv2-acct-panel {
  position: absolute;
  top: 44px;
  right: 0;
  z-index: 40;
  width: 230px;
  background: var(--oddly-canvas, #FAFAF7);
  border: 1px solid rgba(26, 26, 46, 0.12);
  border-radius: 14px;
  box-shadow: 0 24px 60px -20px rgba(26, 26, 46, 0.35);
  padding: 8px;
  display: flex;
  flex-direction: column;
}
.odv2-acct-panel[hidden] {
  display: none;
}
.odv2-acct-id {
  padding: 10px 12px 12px;
  border-bottom: 1px solid rgba(26, 26, 46, 0.08);
  margin-bottom: 6px;
}
.odv2-acct-name {
  font-size: 14px;
  font-weight: 700;
}
.odv2-acct-email {
  font-size: 12px;
  color: rgba(26, 26, 46, 0.5);
  overflow-wrap: anywhere;
}
.odv2-acct-item {
  padding: 9px 12px;
  border-radius: 8px;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--oddly-ink, #1A1A2E);
  text-decoration: none;
}
.odv2-acct-item:hover {
  background: rgba(26, 26, 46, 0.05);
}
.odv2-acct-signout {
  color: rgba(26, 26, 46, 0.55);
  border-top: 1px solid rgba(26, 26, 46, 0.08);
  margin-top: 6px;
}

/* ---- store switcher (multi-store accounts only; empty for a lone store) ---- */
.odv2-storeswitch {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
/* When the switcher renders it IS the store identity, so the static name beside
   it would be the same store printed twice. Progressive: a browser without
   :has() keeps both, which is redundant but never broken. */
.odv2-brand:has(.odv2-storeswitch select) .odv2-store {
  display: none;
}
.odv2-storeswitch-select {
  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
  color: var(--oddly-ink, #1A1A2E);
  background: rgba(26, 26, 46, 0.05);
  border: 1px solid rgba(26, 26, 46, 0.12);
  padding: 5px 26px 5px 10px;
  border-radius: 8px;
  cursor: pointer;
  appearance: none;
  max-width: 190px;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%231A1A2E' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>");
  background-repeat: no-repeat;
  background-position: right 8px center;
}

/* ---- chrome-only mount (the account surfaces wear the v2 header, keep their
   own page body). The full-height canvas belongs to a v2 VIEW, not to a header
   strip, so it is dropped here. ---- */
.odv2-chrome-only {
  min-height: 0;
  background: transparent;
}

/* ---- account sub-nav: the surfaces the retired sidebar used to hold, as one
   row under the v2 header so an account page is never a dead end ---- */
.odv2-subnav {
  max-width: 1280px;
  margin: 0 auto;
  padding: 14px 32px 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px;
}
.odv2-subnav a {
  padding: 6px 12px;
  border-radius: 8px;
  font-family: var(--oddly-font-sans, "Hanken Grotesk", system-ui, sans-serif);
  font-size: 13.5px;
  font-weight: 600;
  color: rgba(26, 26, 46, 0.5);
  text-decoration: none;
}
.odv2-subnav a:hover {
  color: rgba(26, 26, 46, 0.8);
}
.odv2-subnav a.is-active {
  color: var(--oddly-ink, #1A1A2E);
  background: rgba(26, 26, 46, 0.07);
}

/* ---- main column ---- */
.odv2-main {
  max-width: 1280px;
  margin: 0 auto;
  padding: 40px 32px 72px;
}
.odv2-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 24px;
  margin-bottom: 32px;
  flex-wrap: wrap;
}
.odv2-h1 {
  font-family: var(--oddly-font-serif, "Newsreader", Georgia, serif);
  font-weight: 400;
  font-size: 38px;
  line-height: 1.05;
  letter-spacing: -0.02em;
  margin: 0 0 8px;
}
.odv2-h1 em {
  font-style: italic;
  color: var(--oddly-teal, #2C7873);
}
.odv2-sub {
  font-size: 15px;
  color: rgba(26, 26, 46, 0.55);
  margin: 0;
}
.odv2-head-note {
  font-size: 13px;
  color: rgba(26, 26, 46, 0.5);
  display: inline-flex;
  align-items: center;
  gap: 8px;
  white-space: nowrap;
}
.odv2-head-note .glyph {
  color: var(--oddly-teal, #2C7873);
}

/* ---- cards ---- */
.odv2-card {
  background: #FFFFFF;
  border: 1px solid rgba(26, 26, 46, 0.08);
  border-radius: 16px;
  padding: 24px;
}
.odv2-card.is-highlight {
  border-color: rgba(44, 120, 115, 0.3);
  box-shadow: 0 20px 44px -30px rgba(44, 120, 115, 0.45);
}
.odv2-eyebrow {
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  font-weight: 700;
  color: rgba(26, 26, 46, 0.45);
}
.odv2-eyebrow.is-teal {
  color: var(--oddly-teal, #2C7873);
}

/* Today: 3-card grid */
.odv2-grid-3 {
  display: grid;
  grid-template-columns: 0.85fr 1.35fr 1fr;
  gap: 16px;
  align-items: stretch;
  margin-bottom: 16px;
}
.odv2-grid-bm {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
}
.odv2-grid-conn {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 16px;
}

/* health score */
.odv2-score {
  display: flex;
  align-items: baseline;
  gap: 6px;
}
.odv2-score-num {
  font-family: var(--oddly-font-serif, "Newsreader", Georgia, serif);
  font-size: 58px;
  line-height: 0.9;
  letter-spacing: -0.02em;
}
.odv2-score-den {
  font-size: 17px;
  color: rgba(26, 26, 46, 0.4);
}
.odv2-score-status {
  font-size: 13px;
  color: var(--oddly-teal, #2C7873);
  font-weight: 600;
  margin: 6px 0 12px;
}
.odv2-score-status.is-gold {
  color: var(--oddly-gold, #B08D57);
}
.odv2-note-p {
  font-size: 12px;
  line-height: 1.5;
  color: rgba(26, 26, 46, 0.5);
  margin: 0 0 18px;
}

/* mini bars (subscores) */
.odv2-bars {
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.odv2-bar-row .odv2-bar-label {
  display: flex;
  justify-content: space-between;
  font-size: 13px;
  margin-bottom: 6px;
}
.odv2-bar-row .odv2-bar-label .k {
  color: rgba(26, 26, 46, 0.6);
}
.odv2-bar-row .odv2-bar-label .v {
  font-weight: 600;
}
.odv2-bar-track {
  height: 5px;
  border-radius: 4px;
  background: rgba(26, 26, 46, 0.08);
}
.odv2-bar-fill {
  height: 5px;
  border-radius: 4px;
  background: var(--oddly-teal, #2C7873);
}
.odv2-bar-fill.is-gold {
  background: var(--oddly-gold, #B08D57);
}
.odv2-weak {
  font-size: 12px;
  color: var(--oddly-gold, #B08D57);
  margin-top: 6px;
}
.odv2-link {
  font-size: 13px;
  font-weight: 600;
  color: var(--oddly-teal, #2C7873);
  cursor: pointer;
  text-decoration: none;
}
.odv2-card-foot {
  margin-top: 18px;
  padding-top: 14px;
  border-top: 1px solid rgba(26, 26, 46, 0.07);
}

/* top play card */
.odv2-topplay {
  display: flex;
  flex-direction: column;
}
.odv2-topplay-head {
  display: flex;
  justify-content: space-between;
  margin-bottom: 14px;
}
.odv2-tag {
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  font-weight: 700;
}
.odv2-tag.is-teal { color: var(--oddly-teal, #2C7873); }
.odv2-tag.is-gold { color: var(--oddly-gold, #B08D57); }
.odv2-tag.is-muted { color: rgba(26, 26, 46, 0.5); }
.odv2-play-title {
  font-family: var(--oddly-font-serif, "Newsreader", Georgia, serif);
  font-size: 27px;
  letter-spacing: -0.01em;
  margin: 0 0 6px;
}
.odv2-money-row {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin-bottom: 12px;
}
.odv2-money {
  font-size: 34px;
  font-weight: 700;
  color: var(--oddly-gold, #B08D57);
  letter-spacing: -0.01em;
}
.odv2-money.is-teal { color: var(--oddly-teal, #2C7873); }
.odv2-money-unit {
  font-size: 14px;
  color: rgba(26, 26, 46, 0.5);
}
.odv2-body-p {
  font-size: 14px;
  line-height: 1.55;
  color: rgba(26, 26, 46, 0.62);
  margin: 0 0 18px;
}
/* Benchmark evidence line on a play (Kyle ruling 2026-07-14): the quiet WHY. */
.odv2-evidence {
  font-size: 12px;
  line-height: 1.5;
  color: rgba(26, 26, 46, 0.62);
  margin: 6px 0 14px;
  padding-left: 10px;
  border-left: 2px solid var(--oddly-border-strong, #D8D5CC);
}
.odv2-actions {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: auto;
}

/* buttons */
.odv2-btn {
  font-size: 14px;
  font-weight: 600;
  font-family: inherit;
  padding: 11px 20px;
  border-radius: 10px;
  cursor: pointer;
}
.odv2-btn-primary {
  background: var(--oddly-teal, #2C7873);
  color: var(--oddly-canvas, #FAFAF7);
  border: 1px solid var(--oddly-teal, #2C7873);
}
.odv2-btn-approved {
  background: rgba(44, 120, 115, 0.12);
  color: var(--oddly-teal, #2C7873);
  border: 1px solid rgba(44, 120, 115, 0.4);
}
.odv2-btn-locked {
  background: transparent;
  color: var(--oddly-gold, #B08D57);
  border: 1px solid rgba(176, 141, 87, 0.5);
}
.odv2-btn-ghost {
  background: transparent;
  border: none;
  font-size: 14px;
  font-weight: 600;
  color: rgba(26, 26, 46, 0.55);
  padding: 11px 14px;
  cursor: pointer;
  font-family: inherit;
}
.odv2-note-trailing {
  margin-left: auto;
  font-size: 12px;
  color: rgba(26, 26, 46, 0.45);
}

/* dot-bars (percentile) */
.odv2-dots {
  display: flex;
  flex-direction: column;
  gap: 18px;
}
.odv2-dot-label {
  display: flex;
  justify-content: space-between;
  font-size: 13px;
  margin-bottom: 7px;
}
.odv2-dot-label .k { color: rgba(26, 26, 46, 0.6); }
.odv2-dot-label .v { font-weight: 700; }
.odv2-dot-label .v.is-teal { color: var(--oddly-teal, #2C7873); }
.odv2-dot-label .v.is-gold { color: var(--oddly-gold, #B08D57); }
.odv2-dot-track {
  position: relative;
  height: 6px;
  border-radius: 4px;
  background: rgba(26, 26, 46, 0.08);
}
.odv2-dot {
  position: absolute;
  top: -3px;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  border: 2px solid #FFFFFF;
  background: var(--oddly-teal, #2C7873);
}
.odv2-dot.is-gold { background: var(--oddly-gold, #B08D57); }

/* ranked / next-plays rows */
.odv2-rows {
  padding: 8px 24px;
}
.odv2-next-row {
  display: grid;
  grid-template-columns: 30px 1fr auto auto;
  gap: 16px;
  align-items: center;
  padding: 16px 0;
}
.odv2-next-row + .odv2-next-row {
  border-top: 1px solid rgba(26, 26, 46, 0.07);
}
.odv2-badge {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--oddly-ink, #1A1A2E);
  color: var(--oddly-canvas, #FAFAF7);
  font-size: 13px;
  font-weight: 700;
  text-align: center;
  line-height: 26px;
}
.odv2-badge.is-teal { background: var(--oddly-teal, #2C7873); }
.odv2-badge.is-dim { background: rgba(26, 26, 46, 0.8); }
.odv2-row-title {
  font-size: 15px;
  font-weight: 600;
}
.odv2-row-desc {
  font-size: 13px;
  color: rgba(26, 26, 46, 0.55);
}
.odv2-row-metric {
  font-size: 13px;
  font-weight: 700;
  color: var(--oddly-gold, #B08D57);
}
.odv2-row-metric.is-teal { color: var(--oddly-teal, #2C7873); }

/* plays list */
.odv2-plays {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.odv2-play-row {
  display: grid;
  grid-template-columns: 30px 1fr auto auto auto;
  gap: 18px;
  align-items: center;
  padding: 20px 24px;
  border-radius: 14px;
  background: #FFFFFF;
  border: 1px solid rgba(26, 26, 46, 0.09);
}
.odv2-play-row.is-top {
  border-color: rgba(44, 120, 115, 0.3);
}
.odv2-play-row.is-done {
  background: rgba(26, 26, 46, 0.02);
  border-color: rgba(26, 26, 46, 0.07);
  opacity: 0.75;
}
.odv2-play-badge {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  color: var(--oddly-canvas, #FAFAF7);
  font-size: 14px;
  font-weight: 700;
  text-align: center;
  line-height: 28px;
  background: rgba(26, 26, 46, 0.8);
}
.odv2-play-badge.is-teal { background: var(--oddly-teal, #2C7873); }
.odv2-play-badge.is-ink { background: var(--oddly-ink, #1A1A2E); }
.odv2-play-badge.is-done {
  background: transparent;
  border: 1.5px solid rgba(26, 26, 46, 0.3);
  color: rgba(26, 26, 46, 0.5);
  line-height: 26px;
}
.odv2-play-name {
  font-size: 16px;
  font-weight: 600;
  margin-bottom: 3px;
}
.odv2-play-row.is-done .odv2-play-name {
  text-decoration: line-through;
  color: rgba(26, 26, 46, 0.55);
}
.odv2-play-metric {
  font-size: 15px;
  font-weight: 700;
  color: var(--oddly-gold, #B08D57);
}
.odv2-play-metric.is-teal { color: var(--oddly-teal, #2C7873); }
.odv2-play-metric.is-done {
  font-size: 13px;
  font-weight: 600;
  color: rgba(26, 26, 46, 0.45);
}
.odv2-mini-approve {
  font-size: 13px;
  font-weight: 600;
  color: var(--oddly-canvas, #FAFAF7);
  background: var(--oddly-teal, #2C7873);
  padding: 9px 16px;
  border-radius: 9px;
  border: 1px solid var(--oddly-teal, #2C7873);
  cursor: pointer;
  font-family: inherit;
}
.odv2-mini-review {
  font-size: 13px;
  font-weight: 600;
  color: var(--oddly-ink, #1A1A2E);
  background: transparent;
  border: 1px solid rgba(26, 26, 46, 0.16);
  padding: 9px 16px;
  border-radius: 9px;
  cursor: pointer;
  font-family: inherit;
  text-decoration: none;
}
.odv2-mini-locked {
  font-size: 13px;
  font-weight: 600;
  color: var(--oddly-gold, #B08D57);
  background: transparent;
  border: 1px solid rgba(176, 141, 87, 0.5);
  padding: 9px 16px;
  border-radius: 9px;
  cursor: pointer;
  font-family: inherit;
  text-decoration: none;
}

/* play drill-in: the summary row plus the working and the actions it opens.
   The item wraps the row so the grid row keeps its five columns and the detail
   panel sits beneath it as a sibling. */
.odv2-play-item {
  display: flex;
  flex-direction: column;
}
.odv2-play-item .odv2-play-row {
  cursor: pointer;
}
.odv2-play-item.is-open .odv2-play-row {
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
  border-bottom-color: transparent;
}
.odv2-play-detail {
  padding: 0 24px 20px;
  border: 1px solid rgba(26, 26, 46, 0.09);
  border-top: 0;
  border-radius: 0 0 14px 14px;
  background: #FFFFFF;
}
.odv2-play-item.is-done .odv2-play-detail {
  background: rgba(26, 26, 46, 0.02);
  border-color: rgba(26, 26, 46, 0.07);
}
.odv2-play-why {
  font-size: 14px;
  line-height: 1.65;
  color: rgba(26, 26, 46, 0.68);
  margin: 0 0 16px;
}
.odv2-play-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
}
/* In the drill-in the caveat belongs BESIDE the button it qualifies, not
   pushed to the far edge on a line of its own (the topplay card's right-edge
   placement is a different layout). */
.odv2-play-actions .odv2-note-trailing {
  margin-left: 0;
  flex: 1 1 240px;
}

/* the receipt an approve leaves behind: what happened, in place */
.odv2-approved {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  flex: 1 1 100%;
  font-size: 13px;
  line-height: 1.6;
  padding: 12px 14px;
  border-radius: 10px;
  border: 1px solid rgba(44, 120, 115, 0.28);
  background: rgba(44, 120, 115, 0.06);
  color: rgba(26, 26, 46, 0.75);
}
.odv2-approved.is-partial,
.odv2-approved.is-failed {
  border-color: rgba(176, 141, 87, 0.42);
  background: rgba(176, 141, 87, 0.08);
}
.odv2-approved-glyph {
  font-size: 14px;
  line-height: 1.5;
  color: var(--oddly-teal, #2C7873);
}
.odv2-approved.is-partial .odv2-approved-glyph,
.odv2-approved.is-failed .odv2-approved-glyph {
  color: var(--oddly-gold, #B08D57);
}
.odv2-approved-text strong {
  color: var(--oddly-ink, #1A1A2E);
}

/* Today: the store-facts strip (Revenue / Orders / AOV / Inventory health).
   Deliberately chrome-less. Every other block on Today is a card, so the one
   element without a card body reads as reference under the decision instead of
   competing with it. A hairline above separates it from the grid; nothing else
   frames it. The figures use the serif at roughly a third of the health score's
   size: same voice as the number above, plainly subordinate to it. */
.odv2-facts {
  border-top: 1px solid rgba(26, 26, 46, 0.08);
  padding-top: 18px;
  margin-bottom: 28px;
}
.odv2-facts-row {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 16px 24px;
}
.odv2-fact {
  display: flex;
  flex-direction: column;
  gap: 5px;
  min-width: 0;
}
.odv2-fact-l {
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  font-weight: 700;
  color: rgba(26, 26, 46, 0.45);
}
.odv2-fact-v {
  font-family: var(--oddly-font-serif, "Newsreader", Georgia, serif);
  font-size: 22px;
  line-height: 1.15;
  letter-spacing: -0.01em;
  color: var(--oddly-ink, #1A1A2E);
  /* Four figures read across as a comparison, so the digits must align. */
  font-variant-numeric: tabular-nums;
  /* A long-form currency (IDR, VND, COP) runs far wider than USD. Let it wrap
     inside its own column rather than push the row into a sideways scroll. */
  overflow-wrap: anywhere;
}
/* Inventory health keeps the canonical 80 / 50 banding. The percentage states
   the fact on its own; the tint only reinforces it, so nothing is carried by
   colour alone. */
.odv2-fact-v.is-watch,
.odv2-fact-v.is-attention {
  color: var(--oddly-gold, #B08D57);
}
/* An absent figure says so in words, at body size: it is a sentence, not a
   number, and must not read as one. */
.odv2-fact.is-empty .odv2-fact-v {
  font-family: inherit;
  font-size: 13px;
  line-height: 1.4;
  color: rgba(26, 26, 46, 0.45);
}
.odv2-facts-caption {
  font-size: 12px;
  color: rgba(26, 26, 46, 0.5);
  margin-top: 14px;
}
.odv2-facts-cold {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px 14px;
  font-size: 13px;
  color: rgba(26, 26, 46, 0.6);
}

/* what oddly is watching, in counts, beneath the health score */
.odv2-w-counts {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  margin: 14px 0 0;
}
.odv2-w-count {
  font-size: 12px;
  font-weight: 600;
  color: rgba(26, 26, 46, 0.55);
  display: inline-flex;
  align-items: baseline;
  gap: 5px;
}
.odv2-w-count strong {
  font-size: 17px;
  font-weight: 700;
  color: var(--oddly-ink, #1A1A2E);
}

/* filter chips */
.odv2-chips {
  display: flex;
  gap: 8px;
}
.odv2-chip {
  font-size: 13px;
  font-weight: 600;
  padding: 8px 16px;
  border-radius: 20px;
  border: 1px solid rgba(26, 26, 46, 0.14);
  color: rgba(26, 26, 46, 0.6);
  background: transparent;
  cursor: pointer;
  font-family: inherit;
  text-decoration: none;
}
.odv2-chip.is-active {
  background: var(--oddly-ink, #1A1A2E);
  color: var(--oddly-canvas, #FAFAF7);
  border-color: var(--oddly-ink, #1A1A2E);
}

/* guard-rail strip */
.odv2-guard {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 20px;
  padding: 14px 20px;
  border: 1px solid rgba(176, 141, 87, 0.35);
  background: rgba(176, 141, 87, 0.05);
  border-radius: 12px;
  font-size: 13px;
  color: rgba(26, 26, 46, 0.65);
}
.odv2-guard strong { color: var(--oddly-ink, #1A1A2E); }
.odv2-guard .glyph { font-size: 15px; }
.odv2-guard .odv2-link { margin-left: auto; white-space: nowrap; }
.odv2-guard.is-banner { margin-top: 0; margin-bottom: 16px; padding: 13px 20px; }

/* Benchmarks: two layers, visually separated on purpose.
   Layer 1 is market position read from public storefronts; layer 2 is the
   opted-in peer cohort. They must never read as one grid, or public context
   passes for contributed truth, so each gets its own heading, its own tag, and
   a rule between them. */
.odv2-layer {
  margin-bottom: 28px;
}
.odv2-layer + .odv2-layer {
  padding-top: 28px;
  border-top: 1px solid rgba(26, 26, 46, 0.1);
}
.odv2-layer-head {
  display: flex;
  align-items: baseline;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 6px;
}
.odv2-h2 {
  font-family: var(--oddly-font-serif, "Newsreader", Georgia, serif);
  font-weight: 400;
  font-size: 24px;
  line-height: 1.15;
  letter-spacing: -0.01em;
  margin: 0;
  text-wrap: balance;
}
.odv2-layer-tag {
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  font-weight: 700;
  padding: 4px 10px;
  border-radius: 20px;
  border: 1px solid rgba(26, 26, 46, 0.14);
  color: rgba(26, 26, 46, 0.5);
}
.odv2-layer-tag.is-cohort {
  border-color: rgba(44, 120, 115, 0.3);
  color: var(--oddly-teal, #2C7873);
}
.odv2-layer-sub {
  font-size: 14px;
  line-height: 1.6;
  color: rgba(26, 26, 46, 0.55);
  max-width: 640px;
  margin: 0 0 18px;
}

/* Market-position card: verdict-first, not percentile-first.
   The colour split is the honest half of the distinction, not decoration. Teal
   and gold are the VERDICT colours: they say a number is good or bad for you.
   A market observation makes no such claim (a price above the category median
   is not a failing), so layer 1 is drawn in ink throughout: the edge marker,
   the position dot, the label. Ink reads "observed"; teal and gold stay
   reserved for "judged", which is layer 2's job. */
.odv2-mp-card {
  border-left: 3px solid rgba(26, 26, 46, 0.25);
}
.odv2-mp-name {
  font-size: 12px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  font-weight: 700;
  color: rgba(26, 26, 46, 0.4);
  margin-bottom: 10px;
  overflow-wrap: break-word;
}
.odv2-mp-verdict {
  font-family: var(--oddly-font-serif, "Newsreader", Georgia, serif);
  font-size: 19px;
  line-height: 1.35;
  color: var(--oddly-ink, #1A1A2E);
  /* the verdict is server-authored prose of unbounded length, and the measure
     labels are open-ended (price.<item> cells), so long content wraps rather
     than pushing the card wider. */
  text-wrap: pretty;
  overflow-wrap: break-word;
}
.odv2-mp-meaning {
  font-size: 13px;
  line-height: 1.55;
  color: rgba(26, 26, 46, 0.55);
  margin-top: 8px;
}
.odv2-mp-card .odv2-dot-track {
  margin: 16px 0 12px;
}
.odv2-dot.is-ink {
  background: var(--oddly-ink, #1A1A2E);
}
.odv2-mp-stat {
  font-size: 13px;
  color: rgba(26, 26, 46, 0.55);
  margin-top: 12px;
  /* two figures compared side by side on one line: align the digits. */
  font-variant-numeric: tabular-nums;
}
.odv2-mp-source {
  font-size: 12px;
  color: rgba(26, 26, 46, 0.4);
  margin-top: 8px;
  font-variant-numeric: tabular-nums;
}

/* benchmarks metric cards */
.odv2-bm-card .odv2-bm-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: 6px;
}
.odv2-bm-name { font-size: 14px; font-weight: 600; }
.odv2-bm-pct {
  font-family: var(--oddly-font-serif, "Newsreader", Georgia, serif);
  font-size: 30px;
}
.odv2-bm-pct.is-teal { color: var(--oddly-teal, #2C7873); }
.odv2-bm-pct.is-gold { color: var(--oddly-gold, #B08D57); }
.odv2-bm-card.is-below { border-color: rgba(176, 141, 87, 0.4); }
.odv2-bm-card .odv2-dot-track { margin: 14px 0 12px; }
.odv2-bm-stat { font-size: 13px; color: rgba(26, 26, 46, 0.55); }
.odv2-bm-foot { font-size: 13px; font-weight: 600; margin-top: 12px; color: rgba(26, 26, 46, 0.45); }
.odv2-bm-foot.is-teal { color: var(--oddly-teal, #2C7873); cursor: pointer; }

/* the read strip */
.odv2-read {
  margin-top: 24px;
  padding: 18px 24px;
  background: #FFFFFF;
  border: 1px solid rgba(26, 26, 46, 0.08);
  border-radius: 14px;
  display: flex;
  align-items: center;
  gap: 14px;
}
.odv2-read-label {
  font-family: var(--oddly-font-serif, "Newsreader", Georgia, serif);
  font-style: italic;
  font-size: 17px;
  color: var(--oddly-ink, #1A1A2E);
  white-space: nowrap;
}
.odv2-read-body { font-size: 14px; color: rgba(26, 26, 46, 0.65); }

/* connections */
.odv2-conn-body {
  font-size: 13px;
  line-height: 1.5;
  color: rgba(26, 26, 46, 0.55);
  margin: 6px 0 16px;
}
.odv2-conn-rows {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.odv2-conn-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  border-radius: 10px;
  border: 1px solid rgba(26, 26, 46, 0.08);
}
.odv2-conn-row.is-off {
  border: 1px dashed rgba(26, 26, 46, 0.18);
}
.odv2-conn-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--oddly-teal, #2C7873);
}
.odv2-conn-dot.is-off { background: rgba(26, 26, 46, 0.2); }
/* Attention, not failure: the connection is live but the data behind it is not
   current (stale watermark, or an entity failing against a live token). Gold is
   the system's attention colour; teal stays the only action colour. */
.odv2-conn-dot.is-gold { background: var(--oddly-gold, #B08D57); }
.odv2-conn-name { font-size: 14px; font-weight: 600; }
.odv2-conn-row.is-off .odv2-conn-name { color: rgba(26, 26, 46, 0.55); }
.odv2-conn-status { font-size: 12px; color: rgba(26, 26, 46, 0.45); }
.odv2-conn-status.is-gold { color: var(--oddly-gold, #B08D57); }
.odv2-conn-cta {
  margin-left: auto;
  font-size: 13px;
  cursor: pointer;
  text-decoration: none;
}
.odv2-conn-cta.is-manage { color: rgba(26, 26, 46, 0.5); }
.odv2-conn-cta.is-connect { color: var(--oddly-teal, #2C7873); font-weight: 600; }

/* log */
.odv2-log-row {
  display: grid;
  grid-template-columns: 90px 1fr auto auto auto;
  gap: 18px;
  align-items: center;
  padding: 18px 0;
}
.odv2-log-row + .odv2-log-row {
  border-top: 1px solid rgba(26, 26, 46, 0.07);
}
.odv2-log-date { font-size: 13px; color: rgba(26, 26, 46, 0.5); }
.odv2-log-title { font-size: 15px; font-weight: 600; }
.odv2-log-sub { font-size: 13px; color: rgba(26, 26, 46, 0.55); }
.odv2-log-src {
  font-size: 12px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  font-weight: 700;
}
.odv2-log-src.is-teal { color: var(--oddly-teal, #2C7873); }
.odv2-log-src.is-gold { color: var(--oddly-gold, #B08D57); }
.odv2-log-result { font-size: 13px; font-weight: 700; }
.odv2-log-result.is-teal { color: var(--oddly-teal, #2C7873); }
.odv2-log-result.is-gold { color: var(--oddly-gold, #B08D57); }
.odv2-log-action { font-size: 13px; font-weight: 600; color: rgba(26, 26, 46, 0.55); cursor: pointer; }
.odv2-log-action.is-done { color: rgba(26, 26, 46, 0.45); cursor: default; }

/* footnotes + empty states */
.odv2-footnote {
  text-align: center;
  margin-top: 24px;
  font-size: 13px;
  color: rgba(26, 26, 46, 0.5);
}
.odv2-empty {
  text-align: center;
  padding: 56px 24px;
  color: rgba(26, 26, 46, 0.55);
}
.odv2-empty .odv2-empty-title {
  font-family: var(--oddly-font-serif, "Newsreader", Georgia, serif);
  font-size: 24px;
  color: var(--oddly-ink, #1A1A2E);
  margin-bottom: 10px;
}
.odv2-empty .odv2-empty-body {
  font-size: 14px;
  max-width: 460px;
  margin: 0 auto;
  line-height: 1.6;
}
.odv2-skel {
  color: rgba(26, 26, 46, 0.4);
  font-size: 14px;
  padding: 24px 0;
}

/* Value statement (VL-2): the realized-dollar proof above the change log. */
.odv2-value {
  margin-bottom: 16px;
  border-color: rgba(44, 120, 115, 0.28);
  box-shadow: 0 20px 44px -32px rgba(44, 120, 115, 0.4);
}
.odv2-value .odv2-eyebrow { margin-bottom: 12px; }
.odv2-value-head {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 8px 20px;
  margin-bottom: 20px;
}
.odv2-value-hero {
  font-family: var(--oddly-font-serif, "Newsreader", Georgia, serif);
  font-size: 44px;
  line-height: 1;
  font-weight: 600;
  color: var(--oddly-ink, #1A1A2E);
  display: flex;
  align-items: baseline;
  gap: 12px;
}
.odv2-value-hero-cap {
  font-family: var(--oddly-font-sans, system-ui, sans-serif);
  font-size: 14px;
  font-weight: 500;
  color: rgba(26, 26, 46, 0.55);
}
.odv2-value-meta {
  font-size: 14px;
  color: rgba(26, 26, 46, 0.6);
  display: flex;
  align-items: center;
  gap: 12px;
}
.odv2-value-roi {
  font-weight: 700;
  color: var(--oddly-teal, #2C7873);
  background: rgba(44, 120, 115, 0.08);
  border-radius: 999px;
  padding: 3px 12px;
}
.odv2-value-note {
  font-size: 14px;
  color: rgba(26, 26, 46, 0.6);
  line-height: 1.6;
  margin: 0;
}
.odv2-value-levers { margin-top: 4px; }
.odv2-value-levers-h,
.odv2-value-lines-h {
  font-size: 12px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  font-weight: 700;
  color: rgba(26, 26, 46, 0.45);
  margin-bottom: 12px;
}
.odv2-value-lever {
  display: grid;
  grid-template-columns: 160px 1fr 88px;
  align-items: center;
  gap: 14px;
  padding: 7px 0;
}
.odv2-value-lever-label { font-size: 14px; color: rgba(26, 26, 46, 0.7); }
.odv2-value-lever.is-on .odv2-value-lever-label { color: var(--oddly-ink, #1A1A2E); font-weight: 600; }
.odv2-value-lever-track {
  height: 8px;
  border-radius: 999px;
  background: rgba(26, 26, 46, 0.06);
  overflow: hidden;
}
.odv2-value-lever-fill {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: var(--oddly-teal, #2C7873);
  transition: width 0.4s ease;
}
.odv2-value-lever-amt {
  text-align: right;
  font-variant-numeric: tabular-nums;
  font-size: 14px;
  font-weight: 700;
  color: var(--oddly-ink, #1A1A2E);
}
.odv2-value-lever:not(.is-on) .odv2-value-lever-amt { color: rgba(26, 26, 46, 0.4); }
.odv2-value-lines {
  margin-top: 22px;
  border-top: 1px solid rgba(26, 26, 46, 0.08);
  padding-top: 18px;
}
.odv2-value-line {
  display: grid;
  grid-template-columns: 1fr 88px auto;
  align-items: center;
  gap: 14px;
  padding: 8px 0;
}
.odv2-value-line + .odv2-value-line { border-top: 1px solid rgba(26, 26, 46, 0.05); }
.odv2-value-line-play { font-size: 14px; font-weight: 600; color: var(--oddly-ink, #1A1A2E); }
.odv2-value-line-amt {
  text-align: right;
  font-variant-numeric: tabular-nums;
  font-size: 14px;
  font-weight: 700;
  color: var(--oddly-teal, #2C7873);
}
.odv2-value-line-link { font-size: 13px; font-weight: 600; color: rgba(26, 26, 46, 0.55); white-space: nowrap; }
.odv2-value-line-more { font-size: 13px; color: rgba(26, 26, 46, 0.5); padding-top: 10px; }
/* Outcome receipts: "we said X -> you got Y" + honest variance. */
.odv2-receipt { grid-template-columns: 1fr auto auto; }
.odv2-receipt-pair {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.odv2-receipt-said { color: rgba(26, 26, 46, 0.55); }
.odv2-receipt-arrow { color: rgba(26, 26, 46, 0.35); }
.odv2-receipt-got { font-weight: 700; }
.odv2-receipt-got.is-teal { color: var(--oddly-teal, #2C7873); }
.odv2-receipt-got.is-muted { color: rgba(26, 26, 46, 0.5); font-weight: 600; }
.odv2-receipt-var {
  text-align: right;
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.odv2-receipt-var.is-beat { color: var(--oddly-teal, #2C7873); }
.odv2-receipt-var.is-short { color: var(--oddly-gold, #B08D57); }
.odv2-receipt-var.is-even { color: rgba(26, 26, 46, 0.5); }
.odv2-value-empty-h {
  font-family: var(--oddly-font-serif, "Newsreader", Georgia, serif);
  font-size: 22px;
  font-weight: 600;
  color: var(--oddly-ink, #1A1A2E);
  margin: 4px 0 8px;
}
.odv2-value-empty-b {
  font-size: 14px;
  line-height: 1.6;
  color: rgba(26, 26, 46, 0.6);
  max-width: 520px;
  margin: 0 0 14px;
}

/* responsive: cards collapse 3->1 at ~900px, per handoff */
@media (max-width: 900px) {
  .odv2-grid-3,
  .odv2-grid-bm,
  .odv2-grid-conn {
    grid-template-columns: 1fr;
  }
  .odv2-topbar-inner {
    gap: 16px;
    overflow-x: auto;
  }
  .odv2-main {
    padding: 28px 20px 56px;
  }
  .odv2-subnav {
    padding: 12px 20px 0;
  }
  /* The panel is anchored to a control inside a horizontally scrolling bar, so
     on narrow widths it is pinned to the viewport instead of the avatar. */
  .odv2-acct-panel {
    position: fixed;
    top: 60px;
    right: 12px;
    left: auto;
    width: min(260px, calc(100vw - 24px));
  }
}
@media (max-width: 560px) {
  .odv2-readago { display: none; }
  /* Both of these strips are a one-line flex row with a nowrap element pinned to
     each end (the italic label, the trailing link). At 390px that leaves the
     prose roughly a dozen characters wide, which the Benchmarks give-to-get line
     made obvious: a long sentence rendered as a narrow ribbon. Below this width
     they stack instead, so the sentence gets the full column and the link sits
     under it. */
  .odv2-guard,
  .odv2-read {
    flex-wrap: wrap;
  }
  .odv2-guard .odv2-link {
    margin-left: 0;
    white-space: normal;
  }
  .odv2-read-label { white-space: normal; }
  /* Four figures across is unreadable at 390px, so the strip folds to 2x2 and
     keeps its row shape rather than becoming a four-item list. */
  .odv2-facts-row { grid-template-columns: repeat(2, 1fr); }
  .odv2-fact-v { font-size: 20px; }
  .odv2-storeswitch-select { max-width: 132px; }
  .odv2-play-row {
    grid-template-columns: 28px 1fr;
    row-gap: 10px;
  }
  .odv2-log-row {
    grid-template-columns: 1fr;
    row-gap: 6px;
  }
  .odv2-value-hero { font-size: 36px; }
  .odv2-value-lever {
    grid-template-columns: 1fr auto;
    column-gap: 10px;
    row-gap: 4px;
  }
  .odv2-value-lever-track { grid-column: 1 / -1; order: 3; }
  .odv2-value-line {
    grid-template-columns: 1fr auto;
    row-gap: 2px;
  }
  .odv2-value-line-link { grid-column: 1 / -1; }
  .odv2-receipt { grid-template-columns: 1fr auto; row-gap: 4px; }
  .odv2-receipt-pair { grid-column: 1 / -1; white-space: normal; }
  .odv2-play-detail { padding: 0 18px 16px; }
  .odv2-play-actions { align-items: stretch; flex-direction: column; }
  /* Stacked, the flex-basis on these two reads as a HEIGHT, which opened a
     240px hole between the caveat and the receipt below it. */
  .odv2-play-actions .odv2-note-trailing,
  .odv2-play-actions .odv2-approved { flex: 0 0 auto; }
  /* Two auto-placed columns dropped the tag and the money figure into the same
     cell, so "GROWTH" and "SGD 2,500" overprinted each other. Place the five
     children explicitly instead of letting auto-placement decide. */
  .odv2-play-row {
    grid-template-columns: 28px 1fr auto;
    column-gap: 12px;
  }
  .odv2-play-row > .odv2-play-badge { grid-column: 1; grid-row: 1; }
  .odv2-play-row > div { grid-column: 2 / -1; grid-row: 1; }
  .odv2-play-row > .odv2-tag { grid-column: 2; grid-row: 2; justify-self: start; }
  .odv2-play-row > .odv2-play-metric { grid-column: 3; grid-row: 2; justify-self: end; }
  .odv2-play-row > .odv2-mini-review,
  .odv2-play-row > .odv2-mini-approve,
  .odv2-play-row > .odv2-mini-locked { grid-column: 2 / -1; grid-row: 3; justify-self: start; }
}
