/* edge-cards.css — the Edge Lab evidence card, extracted for public pages.
 *
 * GENERATED from static/css/neo-os.css. Kept: every rule whose selector mentions
 * one of the class prefixes the evidence-card component emits, plus the blocks
 * that declare the --edge-* tokens those rules read. Regenerate with the same
 * filter when neo-os.css changes.
 *
 * Prefixes: .edge-chip .edge-compare .edge-details .edge-evidence .edge-finding
 *           .edge-hold .edge-pips .edge-shortfall .edge-stat .edge-sublink
 *
 * Why an extract rather than neo-os.css itself: that file styles bare `main` and
 * `body` for the signed-in app shell, so loading it here pushed this page's <main>
 * 320px right (the sidebar offset) and repainted the background. This keeps the
 * component rules and their tokens and drops every global.
 *
 * The tokens are declared on #edge-overview-root, so a wrapper carrying that id
 * gets the real skin without body.edge-lab-app.
 */


/* ------------------------------------------------------- scorecard row ---- */
.edge-stat-row {
    background: var(--edge-surface);
    border: 1px solid var(--edge-border);
    border-left-style: solid;
    border-radius: var(--edge-radius);
    padding: 1.35rem 1.5rem;
    box-shadow: var(--edge-elevation);
    transition: border-color var(--neo-transition), background-color var(--neo-transition),
        box-shadow var(--edge-hover-transition), transform var(--edge-hover-transition),
        opacity var(--edge-enter-transition);
}

.edge-stat-row + .edge-stat-row { margin-top: 0.75rem; }

.edge-stat-row:hover {
    border-color: var(--edge-border-strong);
    box-shadow: var(--edge-elevation-hover);
    transform: translateY(-1px);
}

/* Four strengths, one hue. Only the weight and the accent's opacity move. */
.edge-stat-row--strong {
    border-left-width: var(--edge-rule-strong);
    border-left-color: var(--edge-accent);
}

.edge-stat-row--moderate {
    border-left-width: var(--edge-rule-moderate);
    border-left-color: var(--edge-accent-soft);
}

.edge-stat-row--weak {
    border-left-width: var(--edge-rule-weak);
    border-left-color: var(--edge-accent-faint);
}

/* Declined by the correction. No accent at all, and a dashed edge, so the row
   reads as withheld rather than as a bad result. */
.edge-stat-row--suppressed {
    border-left-width: var(--edge-rule-suppressed);
    border-left-style: dashed;
    border-left-color: var(--edge-border-strong);
    background: transparent;
}

/* The head now carries a family chip on the left and the strength pips plus the
   evidence badge on the right, so it centres rather than top-aligning, and wraps
   instead of crushing the pips at a narrow width. */
.edge-stat-row__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 0.5rem 0.75rem;
    margin-bottom: 0.85rem;
}

/* Strength and evidence level are one judgement, so they read as one control.
   Two separately-bordered pills side by side made the reader compare them. */
.edge-stat-rating {
    display: inline-flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.25rem 0.65rem;
    border: 1px solid var(--edge-border);
    border-radius: 999px;
    background: var(--edge-track);
}

.edge-stat-rating .edge-stat-badge {
    border: 0;
    border-left: 1px solid var(--edge-border-strong);
    border-radius: 0;
    padding: 0 0 0 0.6rem;
    color: var(--edge-text);
    font-weight: 600;
}

/* The title is what a reader scans a list of findings by, so it outranks the
   family chip above it and reads at body size rather than caption size. */
.edge-stat-row__title {
    margin: 0 0 1.15rem;
    font-size: 1rem;
    font-weight: 600;
    line-height: 1.3;
    color: var(--edge-text);
}

/* Some of these badges carry a whole clause ("Forward · trades that had not
   happened yet"). Held at nowrap and unshrinkable they ran out of their card in
   any narrowed column, so they wrap onto a second line instead. */
.edge-stat-badge {
    min-width: 0;
    font-size: 0.75rem;
    line-height: 1.4;
    padding: 0.125rem 0.5rem;
    border: 1px solid var(--edge-border-strong);
    border-radius: 999px;
    color: var(--edge-text-muted);
}

/* Effect leads and is widest; q closes the row at the same typographic weight,
   because the correction is the claim, not a footnote to it. */
.edge-stat-row__grid {
    display: grid;
    grid-template-columns: minmax(0, 1.7fr) minmax(0, 1.1fr) minmax(0, 0.8fr) minmax(0, 1.3fr);
    gap: 1rem 1.25rem;
    margin-top: 0.9rem;
    align-items: start;
}

@media (max-width: 900px) {
    .edge-stat-row__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }}

@media (max-width: 480px) {
    .edge-stat-row__grid { grid-template-columns: minmax(0, 1fr); }}

.edge-stat-cell { min-width: 0; }

.edge-stat-label {
    display: block;
    font-size: 0.6875rem;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--edge-text-muted);
    text-decoration: none;
    border-bottom: 1px dotted transparent;
}

a.edge-stat-label:hover,
a.edge-stat-label:focus-visible {
    color: var(--edge-accent);
    border-bottom-color: var(--edge-accent-faint);
}

.edge-stat-value {
    margin: 0.2rem 0 0;
    font-size: 0.9375rem;
    font-weight: 500;
    color: var(--edge-text);
    font-variant-numeric: tabular-nums;
    overflow-wrap: anywhere;
}

/* The two leads. Identical size and weight, deliberately. */
.edge-stat-value--lead {
    font-size: 1.5rem;
    font-weight: 650;
    line-height: 1.15;
    letter-spacing: -0.01em;
    color: #f8fafc;
}

.edge-stat-row--suppressed .edge-stat-value--lead { color: var(--edge-text); }

.edge-stat-sub {
    margin: 0.25rem 0 0;
    font-size: 0.6875rem;
    line-height: 1.45;
    color: var(--edge-text-muted);
    font-variant-numeric: tabular-nums;
}

.edge-stat-sublink {
    color: var(--edge-text-muted);
    text-decoration: underline;
    text-decoration-style: dotted;
    text-underline-offset: 2px;
}

.edge-stat-sublink:hover,
.edge-stat-sublink:focus-visible { color: var(--edge-accent); }

.edge-stat-row__caption {
    margin: 0.75rem 0 0;
    font-size: 0.75rem;
    color: var(--edge-text-muted);
}

.edge-stat-row__gates {
    margin-top: 0.9rem;
    padding-top: 0.8rem;
    border-top: 1px solid var(--edge-border);
}

.edge-stat-row__gates-title {
    margin: 0 0 0.55rem;
    font-size: 0.6875rem;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--edge-text-muted);
}

/* ------------------------------------------------- quantified shortfall --- */
.edge-shortfall-group {
    display: flex;
    flex-direction: column;
    gap: 0.7rem;
    margin: 1rem auto 0;
    max-width: 26rem;
    text-align: left;
}

/* Inside a full-width finding row a single column would stretch each bar across
   the whole card and push its figure a screen away from its label. */
.edge-stat-row__gates .edge-shortfall-group {
    margin: 0;
    max-width: none;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
    gap: 0.7rem 1.5rem;
}

.edge-shortfall__head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.75rem;
}

.edge-shortfall__label {
    font-size: 0.75rem;
    color: var(--edge-text-muted);
    min-width: 0;
}

.edge-shortfall__figures {
    flex-shrink: 0;
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--edge-text);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.edge-shortfall__track {
    position: relative;
    margin-top: 0.35rem;
    height: 6px;
    border-radius: 999px;
    background: var(--edge-track);
    overflow: hidden;
}

.edge-shortfall__fill {
    display: block;
    height: 100%;
    border-radius: 999px;
    background: var(--edge-accent-soft);
    transition: width 320ms cubic-bezier(0.2, 0, 0, 1);
}

/* The engine gates on a figure the card payload does not carry (cohort day
   counts). Hatching says "requirement known, current value not reported"
   instead of drawing a bar at a number nobody computed. */
.edge-shortfall__track--unknown {
    background-image: repeating-linear-gradient(135deg,
        rgba(148, 163, 184, 0.28) 0, rgba(148, 163, 184, 0.28) 4px,
        transparent 4px, transparent 8px);
}

.edge-shortfall__constant {
    margin: 0.3rem 0 0;
    font-size: 0.625rem;
    letter-spacing: 0.05em;
    color: var(--edge-text-faint);
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}

/* The method link is a footnote, not a heading; without this it inherits the
   document's 16px and outweighs the panel title next to it. */
.edge-gauge__head .edge-stat-sublink {
    font-size: 0.8125rem;
    /* Absorbs the head's slack, so the score badge stays beside the title it
       qualifies instead of drifting to the middle of a wide column, and the link
       still sits right when it wraps to its own line in a narrow one. */
    margin-left: auto;
}

@media (prefers-reduced-motion: reduce) {
    .edge-stat-row,
    .edge-gauge,
    .edge-gauge__arc,
    .edge-gauge__breakdown,
    .edge-radar__shape,
    .edge-stat-ring__fill,
    .edge-shortfall__fill {
        transition: none;
    }}

/* ==========================================================================
   EDGE LAB — VISUAL LAYER
   --------------------------------------------------------------------------
   Everything above states a finding in words and numbers. This block states it
   in shapes first: a family icon instead of a family sentence, two bars instead
   of "affected mean vs control mean", four pips instead of a level name, and a
   native <details> that hides every statistic a lay reader will not act on.

   The hue rule from the block above still holds. Comparison bars borrow the P&L
   hue ONLY for metrics that really are P&L (expectancy_r, daily_net_r); every
   other metric uses the accent for the affected cohort and neutral grey for the
   comparison, so "bigger" never reads as "better".
   ========================================================================== */

/* --------------------------------------------------------- family chip ---- */
.edge-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.2rem 0.6rem 0.2rem 0.45rem;
    border-radius: 999px;
    border: 1px solid var(--edge-border);
    background: var(--edge-surface-raised);
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.01em;
    color: var(--edge-text-muted);
    white-space: nowrap;
}

.edge-chip__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.15rem;
    height: 1.15rem;
    border-radius: 999px;
    background: var(--edge-accent-bg);
    color: var(--edge-accent);
    font-size: 0.625rem;
}

@keyframes edge-step-in {
    from { opacity: 0; transform: translateY(10px); }
    to   { opacity: 1; transform: translateY(0); }
}

/* ------------------------------------------------------- strength pips ---- */
/* Four pips, one hue. A weak finding is not a different colour from a strong
   one; it simply lights fewer pips. Same channel discipline as the border
   weight it sits beside. */
.edge-pips {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    white-space: nowrap;
}

.edge-pips__dots { display: inline-flex; gap: 3px; }

.edge-pips__dot {
    width: 6px;
    height: 6px;
    border-radius: 999px;
    background: var(--edge-track);
}

.edge-pips__dot--on { background: var(--edge-accent); }

.edge-pips__label {
    font-size: 0.6875rem;
    font-weight: 600;
    color: var(--edge-text-muted);
}

/* ----------------------------------------------------- comparison bars ---- */
/* Two rows sharing one zero-anchored scale, so a sign flip between the affected
   and the comparison cohort is visible before a single figure is read. */
.edge-compare {
    display: flex;
    flex-direction: column;
    gap: 0.55rem;
    min-width: 0;
}

.edge-compare__row {
    display: grid;
    grid-template-columns: minmax(5.5rem, auto) minmax(0, 1fr) minmax(3.5rem, auto);
    align-items: center;
    gap: 0.7rem;
}

.edge-compare__label {
    font-size: 0.75rem;
    text-align: right;
    color: var(--edge-text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.edge-compare__track {
    position: relative;
    height: 12px;
    border-radius: 4px;
    background: var(--edge-track);
    overflow: hidden;
}

/* The zero line. Only drawn when the scale actually spans zero. */
.edge-compare__zero {
    position: absolute;
    top: 0;
    bottom: 0;
    width: 1px;
    background: var(--edge-border-strong);
}

.edge-compare__fill {
    position: absolute;
    top: 0;
    bottom: 0;
    border-radius: 3px;
    background: var(--edge-accent-faint);
    transition: width 360ms cubic-bezier(0.2, 0, 0, 1), left 360ms cubic-bezier(0.2, 0, 0, 1);
}

.edge-compare__row--focus .edge-compare__fill { background: var(--edge-accent); }
.edge-compare__row--focus .edge-compare__label { color: var(--edge-text); font-weight: 600; }

/* Only for metrics that are literally money or R.
   These must beat the --focus background above, which is why they carry the
   same two-class weight. Without it the affected cohort — the row the whole
   finding is about — was painted accent blue whatever its sign, while the
   control row next to it was correctly red or green: two rows on one scale
   using two different colour encodings. A reader comparing "when it happens
   -0.91R" (blue) against another card's "when it happens +0.05R" (also blue)
   could not see the sign flip at all, which is the single thing the shared
   scale exists to show. Focus stays legible through the bold label. */
.edge-compare__fill--pos,
.edge-compare__row--focus .edge-compare__fill--pos { background: var(--edge-pnl-positive); }
.edge-compare__fill--neg,
.edge-compare__row--focus .edge-compare__fill--neg { background: var(--edge-pnl-negative); }

.edge-compare__value {
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--edge-text);
    font-variant-numeric: tabular-nums;
    text-align: right;
    white-space: nowrap;
}

/* --------------------------------------------------------- finding hero --- */
.edge-finding__hero {
    display: grid;
    grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr);
    gap: 1.1rem 2rem;
    align-items: start;
    margin: 0;
}

/* The first bar lines up with the cap-height of the effect figure, not with the
   top of its box — which is what "aligned" looks like to an eye. */
.edge-finding__hero > .edge-compare { padding-top: 0.45rem; }

/* A card whose payload carries no cohort means loses the chart, not the layout. */
.edge-finding__hero--solo { grid-template-columns: minmax(0, 1fr); }

.edge-finding__effect {
    display: block;
    font-size: 2rem;
    font-weight: 650;
    line-height: 1.05;
    letter-spacing: -0.02em;
    color: #f8fafc;
    font-variant-numeric: tabular-nums;
}

.edge-finding__effect-cap {
    display: block;
    margin-top: 0.25rem;
    font-size: 0.8125rem;
    line-height: 1.35;
    color: var(--edge-text-muted);
}

/* ------------------------------------------------------ evidence footnote -- */
/* One muted line under the chart carrying the two qualifiers a reader needs
   before acting on a finding: whether it held over time, and how wide the
   estimate is. Muted on purpose — it qualifies the headline, it is not a
   second headline. */
.edge-evidence {
    /* Shrink-wrapped: a full-width bar with a short sentence in it reads as an
       empty container, not as a footnote. */
    display: inline-flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.55rem;
    margin: 1.25rem 0 0;
    padding: 0.55rem 0.8rem;
    border-radius: 10px;
    background: var(--edge-track);
    font-size: 0.75rem;
    color: var(--edge-text-muted);
}

/* A rule rather than a middot: when the line wraps on a phone, a separator
   character is left dangling at the end of the first line. A border is not. */
.edge-evidence > * + * {
    padding-left: 0.6rem;
    border-left: 1px solid var(--edge-border-strong);
}

.edge-evidence__range { font-variant-numeric: tabular-nums; }

/* The across-period check as a meter: one segment per period that had enough
   trades in both cohorts to vote, filled when that period pointed the same way
   as the overall result. The words next to it say what it counts — three bare
   arrows did not. */
.edge-hold {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    cursor: help;
}

.edge-hold__meter { display: inline-flex; gap: 2px; }

.edge-hold__seg {
    width: 16px;
    height: 6px;
    border-radius: 999px;
    background: var(--edge-track);
}

.edge-hold__seg--on { background: var(--edge-accent); }

/* Everything the reader can act on — the cost of the habit, the link into the
   trades behind it, the experiment button — sits in one zone under the finding. */
.edge-stat-row__actions { margin-top: 1.25rem; }
.edge-stat-row__actions > :first-child { margin-top: 0; }

/* --------------------------------------------------- <details> disclosure - */
/* Every statistic a lay reader will not act on lives behind one of these. It is
   a native element: no JS, keyboard-operable and findable by in-page search
   only when open, which is the correct trade for a figure nobody asked for. */
.edge-details {
    margin-top: 1.25rem;
    border-top: 1px solid var(--edge-border);
    padding-top: 0.85rem;
}

/* Consecutive disclosures are one block, not two zones each with its own rule. */
.edge-details + .edge-details {
    margin-top: 0;
    border-top: 0;
    padding-top: 0.35rem;
}

.edge-details > summary {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    cursor: pointer;
    list-style: none;
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--edge-text-muted);
    transition: color var(--neo-transition);
}

.edge-details > summary::-webkit-details-marker { display: none; }

.edge-details > summary:hover,
.edge-details > summary:focus-visible { color: var(--edge-accent); }

.edge-details > summary::before {
    content: "";
    width: 0;
    height: 0;
    border-left: 5px solid currentColor;
    border-top: 4px solid transparent;
    border-bottom: 4px solid transparent;
    transition: transform 180ms ease;
}

.edge-details[open] > summary::before { transform: rotate(90deg); }

.edge-details__body { margin-top: 0.85rem; }

/* A whole panel behind one disclosure. The base rule is built to sit at the foot
   of a block (top border, top margin); as a panel wrapper it carries neither, and
   the summary stops being a small muted label because it IS the panel head. */
.edge-details--panel { margin-top: 0; border-top: 0; padding-top: 0; }

.edge-details--panel > summary {
    display: flex;
    align-items: flex-start;
    gap: 0.6rem;
    font-size: inherit;
    font-weight: inherit;
    color: inherit;
}

/* The marker is baseline-aligned to the eyebrow, not centred on a two-line head. */
.edge-details--panel > summary::before { flex: none; margin-top: 0.42rem; }

.edge-details--panel > summary:hover,
.edge-details--panel > summary:focus-visible { color: inherit; }

.edge-details--panel > summary:hover .edge-panel__title,
.edge-details--panel > summary:focus-visible .edge-panel__title { color: var(--edge-accent); }

@keyframes edge-explain-scan {
    0%, 18% { transform: translateX(-100%); }
    72%, 100% { transform: translateX(100%); }
}

@keyframes edge-explain-node {
    0%, 100% { background: var(--edge-surface); box-shadow: 0 0 0 rgba(56, 189, 248, 0); transform: scale(0.82); }
    50% { background: var(--edge-accent); box-shadow: 0 0 0.8rem rgba(56, 189, 248, 0.7); transform: scale(1); }
}

@keyframes edge-explain-dot {
    0%, 70%, 100% { opacity: 0.22; transform: translateY(0); }
    35% { opacity: 1; transform: translateY(-0.15rem); }
}

@keyframes edge-explain-trace {
    from { background-position: 100% 0; }
    to { background-position: -120% 0; }
}

@keyframes edge-explain-section-in {
    from { opacity: 0; transform: translateY(0.25rem); }
    to { opacity: 1; transform: translateY(0); }
}

@keyframes edge-explain-cursor {
    0%, 48% { opacity: 1; }
    49%, 100% { opacity: 0.16; }
}

@keyframes edge-coach-loading-sheen {
    from { background-position: 100% 0; }
    to { background-position: -100% 0; }
}

@keyframes edge-coach-avatar-feed {
    0%, 100% { opacity: var(--grain-lit); }
    40% { opacity: 1; }
}

@keyframes edge-coach-avatar-apex {
    0%, 38% { transform: scale(0.55); opacity: 0.4; }
    56% { transform: scale(1.3); opacity: 1; }
    72%, 100% { transform: scale(1); opacity: 0.85; }
}

@keyframes edge-coach-avatar-ray-fast {
    0% { stroke-dashoffset: 17; opacity: calc(var(--ray-lit) * 0.2); }
    22%, 32% { stroke-dashoffset: 0; opacity: var(--ray-lit); }
    50% { stroke-dashoffset: -17; opacity: calc(var(--ray-lit) * 0.2); }
    50.01% { stroke-dashoffset: 17; opacity: calc(var(--ray-lit) * 0.2); }
    72%, 82% { stroke-dashoffset: 0; opacity: var(--ray-lit); }
    100% { stroke-dashoffset: -17; opacity: calc(var(--ray-lit) * 0.2); }
}

@keyframes edge-coach-avatar-apex-fast {
    0%, 20% { transform: scale(0.7); opacity: 0.5; }
    32% { transform: scale(1.25); opacity: 1; }
    50%, 70% { transform: scale(0.7); opacity: 0.5; }
    82% { transform: scale(1.25); opacity: 1; }
    100% { transform: scale(0.7); opacity: 0.5; }
}

@keyframes edge-coach-avatar-gather {
    0% { transform: none; opacity: var(--grain-lit); }
    45% { transform: translateX(2px); opacity: 1; }
    100% { transform: none; opacity: var(--grain-lit); }
}

@keyframes edge-coach-avatar-land {
    0%, 45% { transform: scale(1); }
    62% { transform: scale(1.4); }
    100% { transform: scale(1); }
}

@keyframes edge-coach-pulse {
    0%, 100% { opacity: 1; transform: scale(1); }
    50% { opacity: 0.35; transform: scale(0.7); }
}

@keyframes edge-coach-thinking-sheen {
    0% { background-position: 200% 0; }
    100% { background-position: 0% 0; }
}

@keyframes edge-coach-spin { to { transform: rotate(360deg); } }

/* A row whose metric the tool could not compute. The track stays, so the row
   still occupies its place on the scale and the gap is visibly a gap. */
.edge-compare__row--empty .edge-compare__value { color: var(--edge-text-faint); }
.edge-coach-findings .edge-stat-row + .edge-stat-row { margin-top: 0; }

/* Open: the stat row is the body, so it drops the frame the face already draws
   and keeps everything else it normally renders. The face becomes the card's
   header rather than a summary of it — whatever the two would print twice is
   printed by whichever of them says it better. The title stays on the face
   (it is what the reader clicked), the figure moves to the hero (bigger, and
   with the cohort bars beside it), the strength to the card's own pips. */
.edge-coach-finding > .edge-stat-row {
    border: 0;
    border-radius: 0;
    background: transparent;
    box-shadow: none;
    padding: 0.75rem 0.75rem 0.75rem;
}

.edge-coach-finding[open] > .edge-stat-row { border-top: 1px solid var(--edge-border); }

.edge-coach-finding[open] .edge-coach-finding__effect,
.edge-coach-finding[open] .edge-coach-finding__meta,
.edge-coach-finding[open] .edge-stat-row__title { display: none; }

@keyframes edge-coach-caret-blink {
    to { opacity: 0; }
}

@keyframes edge-coach-reveal-in {
    from { opacity: 0; filter: blur(4px); }
    to { opacity: 1; filter: blur(0); }
}
.edge-context-audit__help .edge-details__body {
    max-width: 46rem;
    margin: 0.55rem 0 0;
    color: var(--edge-text-muted);
    font-size: 0.75rem;
    line-height: 1.55;
}

.edge-rhythm__support .edge-details {
    margin-top: 0.7rem;
    padding-top: 0.7rem;
}

#edge-rhythm-floor-note:empty + .edge-details {
    margin-top: 0;
    padding-top: 0;
    border-top: 0;
}
@keyframes edge-chart-shimmer {
    from { background-position: 130% 0, 0 0; }
    to { background-position: -30% 0, 0 0; }
}
@keyframes edge-chart-spin {
    to { transform: rotate(360deg); }
}

@media (prefers-reduced-motion: reduce) {
    .edge-compare__fill,
    .edge-details > summary::before {
        transition: none;
    }}

/* =============================================================================
   EDGE LAB — INSTRUMENT SKIN (Overview)
   -----------------------------------------------------------------------------
   The landing page's product window (templates/landing.html) is what the product
   actually looks like to a prospect: a near-black instrument panel, hairline
   cyan-tinted rules, 5px corners, and every label and figure set in IBM Plex
   Mono at 8–10px with wide tracking. Signing in then handed the same person a
   generic glass-card SaaS dashboard. This is the Overview adopting the language
   it is already sold in.

   It is applied by overriding the Edge Lab tokens rather than by rewriting
   components: the hub cards, gauges, guard panel and reconciliation table are
   all built by inline JavaScript that reads var(--edge-surface) and
   var(--edge-border), so they re-skin themselves and no renderer had to be
   touched.

   It shipped scoped to #edge-overview-root alone, which left the other 13 Edge
   Lab pages on the glass-card look this section exists to undo. That rollout is
   now finished: every rule below matches :is(#edge-overview-root,
   body.edge-lab-app), so Trades, Evidence, Risk, Method and the rest are skinned
   too. :is() is load-bearing here — it takes the specificity of its most
   specific argument, so each rule keeps the exact 1-1-0 weight the bare id
   selector had. Rewriting these as a plain .edge-lab-app descendant would drop
   them to 0-2-0 and lose to rules that currently lose to them.

   Anything reading these tokens from JavaScript must call getComputedStyle on
   the page root or on body — NOT on documentElement. <html> is above every
   selector above, and custom properties inherit downward only, so
   documentElement silently resolves the pre-skin :root defaults instead.

   The rule the rest of the Edge Lab CSS enforces still holds here: hue means
   P&L and nothing else. What changed is only which green and which red — the
   landing page's calmer sage and coral, in place of the brighter emerald and
   rose, because at mono 10px the saturated pair vibrates against the accent.
   ========================================================================== */
#edge-overview-root,
#edge-daily-root,
body.edge-lab-app,
/* The sidebar is one shared partial mounted by seven shells, only one of which
   carries body.edge-lab-app. Declaring the tokens on the drawer itself is what
   lets its chrome be the same instrument language on every page — see the
   sidebar block at the end of this file. */
#main-sidebar {
    --edge-mono: 'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, monospace;

    /* Hairlines and fills, cyan-tinted rather than neutral grey. */
    --edge-border: rgba(186, 230, 253, 0.14);
    --edge-border-strong: rgba(186, 230, 253, 0.26);
    --edge-surface: rgba(255, 255, 255, 0.018);
    --edge-surface-raised: rgba(255, 255, 255, 0.032);
    --edge-surface-hover: rgba(255, 255, 255, 0.05);
    --edge-track: rgba(186, 230, 253, 0.12);

    --edge-text: #dceaf4;
    --edge-text-muted: #8397a9;
    --edge-text-faint: #7b91a5;

    --edge-pnl-positive: #6fbf9a;
    --edge-pnl-negative: #ff8066;
    --edge-pnl-flat: #7d91a3;
    --edge-pnl-positive-bg: rgba(111, 191, 154, 0.10);
    --edge-pnl-negative-bg: rgba(255, 128, 102, 0.10);

    /* The sage/coral pair at 75%, matching the bodies these wicks belong to.
       Without this override the trade chart draws skinned bodies with
       unskinned wicks. */
    --edge-candle-wick-up: rgba(111, 191, 154, 0.75);
    --edge-candle-wick-down: rgba(255, 128, 102, 0.75);

    --edge-accent: #38bdf8;
    --edge-accent-soft: rgba(56, 189, 248, 0.62);
    --edge-accent-faint: rgba(56, 189, 248, 0.30);
    --edge-accent-bg: rgba(56, 189, 248, 0.08);
    --edge-mint: #67e8f9;

    /* Instrument corners. A 16px radius on a data panel reads as a phone app. */
    --edge-radius: 5px;
    --edge-radius-sm: 3px;

    /* Opaque on purpose: the fills that must stay readable over the plate
       cannot use the skin's near-transparent --edge-surface. */
    --edge-surface-inset: #091625;
    /* No skin equivalent: a deliberately lighter accent for small bright text
       on a dark fill, where --edge-accent is too dim to read. */
    --edge-sky-bright: #7dd3fc;

    color: var(--edge-text);
}

/* The instrument skin stays flat — the full drop-shadow elevation the rest of
   Edge Lab uses read as a generic glass-card dashboard, which is what this
   section exists to undo — but flat-and-shadowless is also why the page read
   as static rather than crafted. One small step of depth instead of zero: a
   hairline top highlight (light catching the top edge of a panel bezel) and
   a barely-there ambient shadow, both far below Edge Lab's normal elevation
   ramp. Borders stay crisp; nothing here is a coloured or blurred halo. */
:is(#edge-overview-root, body.edge-lab-app) .edge-panel,
:is(#edge-overview-root, body.edge-lab-app) .edge-tile,
:is(#edge-overview-root, body.edge-lab-app) .edge-stat-row,
:is(#edge-overview-root, body.edge-lab-app) .edge-gauge {
    box-shadow: inset 0 1px 0 rgba(220, 234, 244, 0.05), 0 1px 3px rgba(2, 6, 15, 0.28);
}

/* Restrained hover/focus: the border reads one step brighter and the surface
   lifts a single pixel — never the full raised-card ramp .edge-tile and
   .edge-stat-row use elsewhere, which this skin deliberately does not use. */
:is(#edge-overview-root, body.edge-lab-app) .edge-tile:hover,
:is(#edge-overview-root, body.edge-lab-app) .edge-stat-row:hover {
    border-color: var(--edge-border-strong);
    box-shadow: inset 0 1px 0 rgba(220, 234, 244, 0.06), 0 2px 6px rgba(2, 6, 15, 0.32);
    transform: translateY(-1px);
}

:is(#edge-overview-root, body.edge-lab-app) .edge-tile:focus-within {
    border-color: var(--edge-accent-faint);
}

/* ------------------------------------------------------------ micro-type --- */
/* Every label, axis tick, badge and figure on this page is mono. Prose — the
   panel descriptions and the method footnotes — stays in the body sans, because
   mono at a readable size is a wall. */
:is(#edge-overview-root, body.edge-lab-app) .edge-panel__eyebrow,
:is(#edge-overview-root, body.edge-lab-app) .edge-tile__label,
:is(#edge-overview-root, body.edge-lab-app) .edge-tile__sub,
:is(#edge-overview-root, body.edge-lab-app) .edge-chip,
:is(#edge-overview-root, body.edge-lab-app) .edge-stat-badge,
:is(#edge-overview-root, body.edge-lab-app) thead th {
    font-family: var(--edge-mono);
    font-weight: 500;
    letter-spacing: 0.1em;
    text-transform: uppercase;
}

:is(#edge-overview-root, body.edge-lab-app) .edge-panel__eyebrow,
:is(#edge-overview-root, body.edge-lab-app) .edge-tile__label,
:is(#edge-overview-root, body.edge-lab-app) thead th {
    font-size: 0.75rem;
    line-height: 1.2;
    color: var(--edge-text-faint);
}

/* Figures are mono at medium weight, never bold: the mockup's numbers read as
   instrument readouts because they are even-weight and evenly spaced. */
:is(#edge-overview-root, body.edge-lab-app) .edge-tile__value,
:is(#edge-overview-root, body.edge-lab-app) .tabular-nums,
:is(#edge-overview-root, body.edge-lab-app) td {
    font-family: var(--edge-mono);
    font-variant-numeric: tabular-nums;
}

:is(#edge-overview-root, body.edge-lab-app) .edge-tile--lead .edge-tile__value {
    font-size: clamp(1rem, 11.5cqi, 1.875rem);
    color: var(--edge-accent);
}

/* The loading bar under a headline tile in the landing mock. Static here —
   there is nothing to animate once the number is real — and drawn in the accent
   rather than in a P&L hue. */
:is(#edge-overview-root, body.edge-lab-app) .edge-tile--lead {
    position: relative;
    border-color: var(--edge-border-strong);
}

:is(#edge-overview-root, body.edge-lab-app) .edge-tile--lead::after {
    content: "";
    position: absolute;
    left: 0;
    bottom: 0;
    width: 64%;
    height: 1px;
    background: linear-gradient(90deg, var(--edge-accent), transparent);
}

/* ------------------------------------------------------------ row control -- */
:is(#edge-overview-root, body.edge-lab-app) .edge-dash-bar__status {
    font-family: var(--edge-mono);
    letter-spacing: 0.06em;
}

/* Chips are the mockup's status pill: a hairline capsule, mint text, no fill. */
:is(#edge-overview-root, body.edge-lab-app) .edge-chip {
    font-size: 0.6875rem;
    letter-spacing: 0.08em;
    border-radius: 999px;
    border: 1px solid var(--edge-accent-faint);
    background: var(--edge-accent-bg);
    color: var(--edge-mint);
}

/* The one headline figure a hub card is allowed. Mono and medium, like the
   metric readouts in the product window, not a bold display number. */
:is(#edge-overview-root, body.edge-lab-app) .text-2xl {
    font-family: var(--edge-mono);
    font-size: 1.375rem;
    font-weight: 500;
    letter-spacing: -0.01em;
}

/* The kicker above a hub card's title, written inline by the renderers. */
:is(#edge-overview-root, body.edge-lab-app) .uppercase.tracking-\[0\.14em\] {
    font-family: var(--edge-mono);
    font-size: 0.75rem;
    letter-spacing: 0.1em;
    color: var(--edge-text-faint);
}

/* --------------------------------------------------------- chart lettering --
   Axis ticks are drawn as SVG <text> with a font-size presentation attribute.
   CSS wins over a presentation attribute, so the ticks join the rest of the
   page's mono without the drawing code carrying any typography of its own. */
:is(#edge-overview-root, body.edge-lab-app) svg text {
    font-family: var(--edge-mono);
    font-size: 11px;
    letter-spacing: 0.06em;
}

/* The chart plate: a faint ruled field behind the line, the way a terminal
   draws one, rather than a flat card. */
:is(#edge-overview-root, body.edge-lab-app) #edge-curve-wrap {
    border: 1px solid var(--edge-border);
    border-radius: var(--edge-radius-sm);
    background-color: rgba(0, 0, 0, 0.12);
    background-image:
        linear-gradient(rgba(255, 255, 255, 0.03) 1px, transparent 1px),
        linear-gradient(90deg, rgba(255, 255, 255, 0.03) 1px, transparent 1px);
    background-size: 100% 44px, 78px 100%;
}

@media (prefers-reduced-motion: reduce) {
    .edge-panel,
    .edge-tile,
    .edge-stat-row,
    .edge-gauge,
    .edge-rhythm__fill {
        transition: none;
    }}

#edge-daily-root .edge-panel__eyebrow,
#edge-daily-root .edge-legend,
#edge-daily-root .edge-tile__label {
    font-family: var(--edge-mono);
    font-size: 0.625rem;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--edge-text-faint);
}

#edge-daily-root .edge-tile__value,
#edge-daily-root .edge-tile__sub {
    font-family: var(--edge-mono);
}
#edge-daily-root .edge-tile__sub { font-size: 0.625rem; color: var(--edge-text-faint); }

@keyframes edge-coach-breathe {
    0%, 100% { opacity: 0.35; transform: scale(0.98); }
    50%      { opacity: 0.7;  transform: scale(1.02); }
}