/* Observer panel — the few rules the kit does not carry yet. Tokens only (kit rule 4): no
   colour, spacing or radius typed here.

   Rhythm (GUIDELINES §4, copied on day one as it asks, until the kit's .page carries it): a
   screen's blocks sit in #view, and one rule on the container spaces them all; no block carries
   an outer margin of its own. Vertical margins collapse, so a block that asks for more gets
   exactly that, never the sum. */
#view > * + *             { margin-top: var(--gap); }
#view > * + .section      { margin-top: var(--s5); }
#view > * + .tile-section,
#view > .tile-section + * { margin-top: var(--s4); }

/* Identifiers (site ids, key prefixes, domains, scopes) read character by character, in every
   language left to right: the kit's .secret uses the same stack for the same reason. */
.mono { font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace; direction: ltr; unicode-bidi: isolate; overflow-wrap: break-word; }

/* ---- Settings (screens/settings/) ---- */

/* A list card is the kit's .table-card (no padding, so on a phone each row's own pad is the one
   inset, §0.31); its head and its save bar take the card's pad themselves. */
.table-card > .table-intro { display: grid; gap: var(--s1); padding: var(--card-pad) var(--card-pad) var(--s2); }
.table-card > .table-intro:last-child { padding-block-start: 0; }
.table-card > .table-intro:empty { display: none; }
.table-card > .empty { padding: var(--s3) var(--card-pad) var(--card-pad); }
.table-card .card-head { margin: 0; }

/* The copy button beside a code box speaks in the page's type, not the code's. */
.secret .btn { font-family: var(--font); }

/* A tab's cards are peers, one gap apart (the panel is a .stack). */
.settings-panel:focus { outline: none; }

/* The site a site-scoped tab is about: as wide as a name needs, never the whole card. */
.site-picker { max-width: 22rem; min-width: 0; }

/* "Only an owner or admin can…": the lock leads the sentence on its line. */
.role-note { display: flex; align-items: center; gap: var(--s0); }
.role-note .ci { --ci-size: 16px; flex: none; }

/* Scopes on a key wrap as tags; a revoked key reads as history. */
.tag-list { display: inline-flex; flex-wrap: wrap; gap: 4px; }
/* 720, the table's step to cards: a value sits on the row's end edge, so its tags do too. */
@media (max-width: 720px) {
  .tag-list { justify-content: flex-end; }
  /* A row's name cell holds a name, a badge and an id under it: as a card's title it reads as text,
     not as the kit's label-and-value pair (a flex row would squeeze the name to a word a line). */
  .settings-panel .table td.cell-lead { display: block; }
  /* The column's name keeps its word whole; the value beside it is what wraps (as agents-settings does). */
  .settings-panel .table td::before { flex: none; max-width: 45%; overflow-wrap: normal; }
}
.table tr.is-revoked td { color: var(--ink-3); }

/* Manage › add a domain: the field and its button on one line, the button at the field's foot. */
.inline-add { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--s1); }
.inline-add > .field { flex: 1 1 14rem; min-width: 0; }

/* Radio and checkbox rows in a dialog (tiers, scopes, sites) sit a step apart. */
.tier-choices, .dialog fieldset.field { display: grid; gap: var(--s1); border: 0; padding: 0; margin: 0; min-width: 0; }
.check small { display: block; color: var(--ink-3); font-size: var(--t-1); font-weight: 400; }
.tier-choices .badge { margin-inline-start: var(--s0); vertical-align: middle; }

/* Team: the role select takes its words' width, not the row's. */
.team-list .role-select { width: auto; max-width: 9rem; flex: none; }

/* The danger zone inside Manage: the kit's card style, set off from the settings above it. */
.dialog .danger-zone { display: grid; gap: var(--s1); }
.dialog .danger-zone h3 { font-size: var(--t0); }

/* Goals: a long match list (the sign-up rule has thirty patterns) must not squeeze the goal's
   name and kind to a word per line; it wraps instead. Wide screens only: 720 is the table's own
   step to cards, where every cell has the row's width. */
@media (min-width: 721px) {
  .goals-table td:nth-child(1), .goals-table td:nth-child(2) { min-width: 11rem; }
}

/* Who can do what: the reader's own role is the column marked. */
.role-matrix th.is-mine { color: var(--accent-ink); }

/* 560 (the kit's one-column step): a team row wraps its role select under the name rather than
   squeezing the address to a word per line (§0.33). */
@media (max-width: 560px) {
  .team-list > li { flex-wrap: wrap; }
  .team-list .list-main { flex-basis: calc(100% - 56px); }
}

/* ---- Reports (components/report/, screens overview · portfolio · pages · realtime) ---- */

/* Five stat tiles in a row (the Overview): 5 across, then 3 + 2 at 1100 (the kit's cols-4 step),
   then 2 + 2 + 1 at 560. A row never ends in a hole: the last tiles widen to fill it. */
.stat-row-5 { --cols: 5; }
@media (max-width: 1100px) {
  .stat-row-5 { --cols: 6; }
  .stat-row-5 > * { grid-column: span 2; }
  .stat-row-5 > :nth-child(n+4) { grid-column: span 3; }
}
@media (max-width: 560px) {
  .stat-row-5 { --cols: 2; }
  .stat-row-5 > *, .stat-row-5 > :nth-child(n+4) { grid-column: auto; }
  .stat-row-5 > :last-child { grid-column: 1 / -1; }
}
.stat-sub { color: var(--ink-3); font-size: var(--t-1); }
.stat-sub .link { font-size: inherit; }
.stat-none { color: var(--ink-3); }
.delta-wrap { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 6px; }

/* A share bar inside a cell: the number on a tinted track as long as its share of the largest
   named row (the kit's .bars look, inside a table so the Other row can be pinned under it). */
.share { position: relative; display: block; min-width: 4.5rem; padding: 2px var(--s0); isolation: isolate; text-align: end; font-variant-numeric: tabular-nums; }
.share::before { content: ""; position: absolute; inset-block: 0; inset-inline-start: 0; z-index: -1; width: var(--w, 0%); border-radius: var(--radius-sm); background: var(--accent-soft); }
:root[data-theme^="contrast"] .share::before { background: none; border-bottom: 3px solid var(--accent); border-radius: 0; }
.table tr[data-pin] .share::before { background: var(--paper-2); }
.ranked .share-cell { width: 42%; }
/* Six columns: the bar gives up room so a site's name is never broken a few letters a line. */
.sites-table .share-cell { width: 20%; }
.ranked td.cell-lead { min-width: 10rem; }
.other-label { font-style: italic; }

/* Paths and site names in a lead cell wrap rather than push the table wider than the card. */
.ranked td.cell-lead { overflow-wrap: anywhere; }
.path { direction: ltr; unicode-bidi: isolate; }
.site-cell, .goal-name { display: grid; gap: 2px; justify-items: start; }
.site-cell small { color: var(--ink-3); font-size: var(--t-1); }
.goal-name .badge { font-weight: 400; }
.row-spark { display: block; width: 96px; height: 28px; }
.row-spark .spark { width: 100%; height: 100%; }
.withheld { color: var(--ink-3); }
.is-high { color: var(--bad); font-weight: 600; }
.report-none { padding: var(--s2) var(--card-pad) var(--card-pad); color: var(--ink-3); }
.card:not(.card-flush) .report-none { padding: 0; }

/* Tabs inside a flush card take the card's pad; their panels hold a table edge to edge. */
.report-tabs { padding-inline: var(--card-pad); }
.report-tabs .tabs { margin-bottom: 0; }
.report-panel:focus-visible { outline: 3px solid var(--focus); outline-offset: -3px; }
.report-devices { display: grid; gap: var(--s2); padding-block-start: var(--s2); }
.report-devices > figure, .report-devices > .card-sub { padding-inline: var(--card-pad); }

/* A card head's controls (Pages: sort and rows) sit on one line with their labels. */
.card-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s0) var(--s1); }
.field-inline { display: flex; align-items: center; gap: var(--s0); margin: 0; }
.field-inline .select { width: auto; min-width: 0; max-width: 100%; }

/* All sites: the line under the tiles reads as a note, not a block of its own. */
.portfolio-note { color: var(--ink-2); max-width: 72ch; }

/* Realtime: the number and the chart side by side, the chart taking the room. */
.realtime-top { display: grid; grid-template-columns: minmax(10rem, auto) minmax(0, 1fr); gap: var(--s3); align-items: center; }
.realtime-now { font-size: var(--t4, var(--t3)); }
.realtime-auto { display: inline-flex; align-items: center; gap: var(--s0); font-weight: 600; }

/* Vitals: the page picker is a long searchable list, so it may take the width a phone gives it. */
.vitals-path { min-width: 0; max-width: 22rem; }
.vitals-pcts { display: flex; flex-wrap: wrap; gap: 2px var(--s1); font-variant-numeric: tabular-nums; }
.vitals-note { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s0); margin: 0; color: var(--ink-2); font-size: var(--t-1); }
/* Good / needs improvement / poor as one bar: the status tokens every mode defines, a hairline
   gap between zones so they read apart without colour, and the legend says each share in words. */
.rating { display: grid; gap: 6px; margin-block-start: var(--s1); }
.rating-bar { display: flex; gap: 2px; height: 10px; border-radius: 99px; overflow: hidden; background: var(--field); }
.rating-seg { flex: 0 0 var(--w, 0%); min-width: 3px; }
.rating-seg[data-tone="good"], .rating-legend i[data-tone="good"] { background: var(--ok); }
.rating-seg[data-tone="warn"], .rating-legend i[data-tone="warn"] { background: var(--warn); }
.rating-seg[data-tone="bad"], .rating-legend i[data-tone="bad"] { background: var(--bad); }
.rating-legend { margin: 0; font-variant-numeric: tabular-nums; }
:root[data-theme^="contrast"] .rating-bar { outline: 2px solid var(--ink); }

/* Funnels: the chosen funnel's row is marked, each step is a kit meter, and the editor's rows are
   number · kind · value · remove on one line that wraps on a phone. */
.funnels-table tr.is-current td { background: var(--accent-wash); }
.funnel-chip { display: inline-flex; align-items: center; gap: 4px; max-width: 100%; }
.funnel-chip .ci { --ci-size: 14px; flex: none; }
.funnel-chip .mono { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.funnel-facts { --cols: 3; }
.funnel-steps { list-style: none; display: grid; gap: var(--s2); margin: 0; padding: 0; }
.funnel-step-name { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 6px; min-width: 0; }
.funnel-step-name .ci { --ci-size: 16px; flex: none; color: var(--ink-3); }
.funnel-step-name .mono { overflow-wrap: anywhere; }
.funnel-step-no { display: inline-grid; place-items: center; min-width: 1.6rem; height: 1.6rem; border-radius: 99px; background: var(--accent-soft); color: var(--accent-ink); font-size: var(--t-1); font-variant-numeric: tabular-nums; flex: none; }
.funnel-step-note { margin: 0; color: var(--ink-2); font-size: var(--t-1); }
.funnel-edit { list-style: none; display: grid; gap: var(--s1); margin: 0; padding: 0; }
.funnel-edit-row { display: grid; grid-template-columns: auto minmax(7rem, 9rem) minmax(0, 1fr) auto; align-items: center; gap: var(--s1); margin: 0; }
.funnel-edit-row > .error-text { grid-column: 2 / -1; }

/* Quality: one heading per form, its leak count beside the name. */
.quality-forms { gap: var(--s3); }
.quality-form { display: grid; gap: var(--s1); }
.quality-form-name { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s1); margin: 0; font-size: var(--t0); }

/* Privacy: the tier as a large badge beside its words; the retention windows as three figures. */
.privacy-panel { padding-block-start: var(--s2); }
.privacy-tier { display: flex; align-items: flex-start; gap: var(--s2); }
.privacy-tier h3 { margin: 0 0 4px; font-size: var(--t1, var(--t0)); }
.privacy-tier-badge { font-size: var(--t1, var(--t0)); padding: 6px 12px; flex: none; }
.privacy-ret .stat-value, .privacy-ret .stat-label { margin: 0; }
.audit-detail { color: var(--ink-2); font-size: var(--t-1); overflow-wrap: anywhere; }

/* 720, the table's own step to cards: a share bar and a spark fill their card row. */
@media (max-width: 720px) {
  .ranked .share-cell { width: auto; }
  .ranked .share { flex: 1 1 auto; }
  .ranked td.cell-lead { display: block; }
  .row-spark { width: 100%; }
}
/* 640, the kit's sheet step: the realtime number goes above its chart. */
@media (max-width: 640px) {
  .realtime-top { grid-template-columns: minmax(0, 1fr); }
  .funnel-facts { --cols: 1; }
  .funnel-edit-row { grid-template-columns: auto minmax(0, 1fr) auto; }
  .funnel-edit-row > .input { grid-column: 1 / -1; grid-row: 2; }
  .vitals-path { max-width: none; }
}
/* ---- Hosted Observer: plans and workspaces (billing.mjs, views/paywall.mjs) ---- */

/* The bar between the top bar and the page: the plan banner, then the site picker. Same rhythm
   as #view's blocks, so the page below starts one gap later. */
.ws-bar { display: grid; gap: var(--gap); margin-bottom: var(--gap); }
.ws-bar[hidden] { display: none; }
.ws-banner .btn-row { margin-top: var(--s0); }

/* Three plans side by side where they fit, one per row on a phone (no fixed column count: the
   grid wraps by width, so 375 px gets one column and nothing scrolls sideways). */
.plan-grid { display: grid; gap: var(--gap); grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr)); align-items: stretch; }
.plan-card { display: grid; gap: var(--s1); align-content: start; }
.plan-card.is-featured { box-shadow: inset 0 0 0 var(--rule-w) var(--accent); }
.plan-head { display: flex; align-items: center; justify-content: space-between; gap: var(--s1); }
.plan-head h3 { font-size: var(--t2); }
.plan-price b { font-size: var(--t3); }
.plan-price span { color: var(--ink-2); }
.plan-lines { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s0); }
.plan-lines li { display: flex; gap: var(--s0); align-items: flex-start; }
.plan-lines .ci { --ci-size: 16px; flex: none; color: var(--accent-ink); margin-top: 2px; }
.plan-card > .btn, .plan-card > .badge { align-self: end; margin-top: var(--s1); }
.plan-interval { grid-template-columns: repeat(2, minmax(0, 1fr)); max-width: 20rem; }
.muted { color: var(--ink-2); }

/* ---- Sessions, Replay, Heatmaps (screens sessions · replay · heatmap) ---- */

/* The row on screen in the timeline or the player beside it: the kit's selected-row tint. */
.table tr.is-current td { background: var(--accent-soft); }
.table tr.is-current td:first-child { box-shadow: inset 3px 0 0 var(--accent); }
:root[dir="rtl"] .table tr.is-current td:first-child { box-shadow: inset -3px 0 0 var(--accent); }
/* The row's real button: its time, in the link colour, one line; the row itself takes the press too. */
/* 720, the table's step to cards: the whole card is tinted, not each label-and-value pair. */
@media (max-width: 720px) {
  .table tr.is-current td, .table tr.is-current td:first-child { background: none; box-shadow: none; }
  .table tr.is-current { background: var(--accent-soft); box-shadow: inset 3px 0 0 var(--accent); }
  :root[dir="rtl"] .table tr.is-current { box-shadow: inset -3px 0 0 var(--accent); }
}
.session-open { padding: 0; border: 0; background: none; font: inherit; font-weight: 600; color: var(--accent-ink); white-space: nowrap; font-variant-numeric: tabular-nums; cursor: pointer; text-decoration: underline; text-decoration-color: transparent; text-underline-offset: 3px; }
.session-open:hover { text-decoration-color: currentColor; }
.session-open:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; border-radius: 4px; }
.session-open[aria-current="true"] { color: var(--ink); }
.sessions-table tbody tr, .replay-table tbody tr { cursor: pointer; }

/* The list and the timeline side by side from 1100 (the kit's cols-4 step), stacked under it. */
.sessions-layout { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); gap: var(--gap); align-items: start; }
@media (max-width: 1099px) { .sessions-layout { grid-template-columns: minmax(0, 1fr); } }
.sessions-timeline .card-title:focus { outline: none; }
.sessions-timeline .card-title:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; }

/* A lane per tab: its name and first page, then the track, page blocks under event markers.
   Positions are inline insets, so the axis runs right to left in RTL like every chart (§ RTL). */
.lanes { display: grid; gap: var(--s1); margin: 0; }
.lane-list { display: grid; gap: var(--s2); }
.lane { display: grid; gap: var(--s0); }
.lane-label { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s0); font-size: var(--t-1); color: var(--ink-2); min-width: 0; }
.lane-label .path { overflow-wrap: anywhere; }
.lane-track { position: relative; block-size: 52px; border-radius: var(--radius-sm); background: var(--paper); box-shadow: inset 0 0 0 var(--rule-w) var(--rule); }
.lane-page { position: absolute; inset-block: 6px; display: flex; align-items: center; min-inline-size: 6px; padding-inline: 6px; overflow: hidden; border-radius: var(--radius-sm); background: var(--accent-soft); box-shadow: inset 0 0 0 var(--rule-w) var(--rule-strong); font-size: var(--t-2); color: var(--ink); white-space: nowrap; }
.lane-page .path { overflow: hidden; text-overflow: ellipsis; }
.lane-dot { position: absolute; inset-block-start: -9px; translate: -50% 0; display: grid; place-items: center; inline-size: 20px; block-size: 20px; border-radius: 50%; background: var(--paper-2); color: var(--tone, var(--ink-3)); box-shadow: 0 0 0 2px var(--tone, var(--ink-3)); }
:root[dir="rtl"] .lane-dot { translate: 50% 0; }
.lane-dot .ci { --ci-size: 12px; }
.lane-axis { display: flex; justify-content: space-between; gap: var(--s1); font-size: var(--t-2); color: var(--ink-3); font-variant-numeric: tabular-nums; }
.ev-cell { display: inline-flex; align-items: flex-start; gap: var(--s0); }
.ev-icon { display: inline-grid; place-items: center; flex: none; inline-size: 22px; block-size: 22px; border-radius: 50%; color: var(--tone, var(--ink-3)); box-shadow: inset 0 0 0 2px var(--tone, var(--ink-3)); }
.ev-icon .ci { --ci-size: 12px; }
.session-log td.cell-lead { min-width: 14rem; overflow-wrap: anywhere; }
.session-log td:nth-child(-n+2) { white-space: nowrap; }
@media (max-width: 720px) { .session-log td.cell-lead { display: block; min-width: 0; } }

/* Replay: the frame keeps a screen's proportion and never gets taller than the window. */
.replay-actions { justify-content: flex-end; flex-wrap: nowrap; }
.replay-stage { border-radius: var(--radius-sm); overflow: hidden; box-shadow: inset 0 0 0 var(--rule-w) var(--rule); background: var(--paper); }
.replay-frame { display: block; inline-size: 100%; block-size: auto; aspect-ratio: 16 / 10; max-block-size: min(600px, 70vh); margin-inline: auto; border: 0; }
.replay-controls { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s1) var(--s2); }
.replay-seek { display: flex; align-items: center; gap: var(--s1); flex: 1 1 16rem; min-width: 0; }
.replay-progress { flex: 1 1 auto; min-width: 0; min-block-size: 24px; accent-color: var(--accent); }
@media (pointer: coarse) { .replay-progress { min-block-size: 44px; } }
.replay-time { flex: none; font-size: var(--t-1); color: var(--ink-2); font-variant-numeric: tabular-nums; }
.replay-options { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s1) var(--s2); }
.replay-skip, .hm-preview-switch { display: inline-flex; align-items: center; gap: var(--s0); font-weight: 600; }
.replay-player .card-title:focus { outline: none; }
.replay-player .card-title:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; }

/* Heatmaps: the controls in one wrapping row; the canvas beside its ranking from 1100, stacked under. */
.hm-controls { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--s2); }
.hm-path-field { flex: 1 1 18rem; min-width: 0; max-width: 28rem; margin: 0; }
.hm-choice { display: grid; gap: var(--s0); }
.hm-choice-label { font-size: var(--t-1); font-weight: 600; color: var(--ink-2); }
.hm-preview-switch { min-block-size: 44px; }
.hm-layout { display: grid; grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr); gap: var(--gap); align-items: start; }
@media (max-width: 1099px) { .hm-layout { grid-template-columns: minmax(0, 1fr); } }
.hm-canvas-wrap { position: relative; display: grid; justify-items: center; min-width: 0; overflow: hidden; border-radius: var(--radius-sm); transition: opacity .2s; }
.hm-canvas-wrap.is-busy { opacity: .55; }
/* Height follows the width the canvas actually gets, so the device's aspect holds even if it is squeezed. */
.hm-canvas { display: block; max-inline-size: 100%; block-size: auto !important; border-radius: var(--radius-sm); }
.hm-legend { display: grid; gap: 4px; margin-block-start: var(--s1); }
.hm-ramp { display: block; block-size: 10px; border-radius: var(--radius-pill); background: var(--ramp); }
.hm-legend-row { display: flex; justify-content: space-between; gap: var(--s1); font-size: var(--t-2); color: var(--ink-3); font-variant-numeric: tabular-nums; }
.hm-elements td.cell-lead { overflow-wrap: anywhere; }
.hm-preview { position: relative; min-block-size: 12rem; }
.hm-preview-frame { display: block; inline-size: 100%; block-size: min(640px, 70vh); border: 0; border-radius: var(--radius-sm); background: var(--paper); box-shadow: inset 0 0 0 var(--rule-w) var(--rule); }
.hm-card .report-none { padding: 0 0 var(--s1); }
@media (prefers-reduced-motion: reduce) { .hm-canvas-wrap { transition: none; } }
