/* Emgrand Intelligence / Vectra rebrand (2026-08-08): one deliberate dark
   theme, not a light default with a dark override - that part of the
   original rebrand still holds and is unchanged. What changed is the
   in-app accent: Vectra is one Intelligence System nested under EmGrand
   (docs/design/emgrand-brand-style-guide.md), and per that guide's "one
   accent dominates per surface" rule, a page that belongs to Vectra uses
   Vectra's own accent - silver, not EmGrand's brass. Since this whole
   authenticated app IS Vectra's product surface, --accent moved from gold
   to silver; brass is reserved for the EmGrand tier of the nav only (see
   .global-bar below). See 404.html/500.html's own comment on why their
   copy of this palette has to move in lockstep with this one.
   Every value below was RECOMPUTED against WCAG contrast math, not
   carried over by eyeball: silver (#b2b2b3) on --bg/--surface clears
   8.4:1+ as text/icon/border color, silver-tint (#e7e7e5, the hover
   state - brighter not darker, same "reads as live" reasoning as the old
   gold hover) clears 15:1+, and --on-accent (dark text ON a filled
   silver button) reuses --bg itself at 8.88:1 rather than the silver-deep
   token, which measures only ~2.2:1 on these backgrounds and was
   rejected as a foreground color for that reason. Status hues
   (--st-*) are unrelated to brand and are untouched - they still clear
   5.4:1+, and every REAL form input / selectable picker card
   (.form input, .field-picker select, .look-tile, .look-opt,
   .layout-card, .drawing-card) still uses --border-2, which clears the
   3:1 non-text bar (unaffected by the accent change - it was never gold).
   Plain row/section dividers stay on --border on purpose - they are
   decorative, not an outline a user needs to perceive as a boundary. */
:root {
  color-scheme: dark;
  --bg: #14110d;
  --surface: #1c1712;
  /* recessed panel tone (diagram boxes, seal stroke) */
  --bg-2: #241e17;
  --text: #f4ecdb;
  --text-2: #bdae92;
  /* 5.5:1 on --surface / 5.8:1 on --bg */
  --text-3: #9c8d6c;
  /* decorative dividers only - never an interactive element's own
     outline, which is what --border-2 is for */
  --border: #3d3021;
  /* 3.3:1 on --surface, 3.5:1 on --bg - clears WCAG 1.4.11 non-text
     contrast for input/card outlines */
  --border-2: #7a6842;
  /* Vectra's accent (docs/design/emgrand-brand-style-guide.md) - 8.4:1+
     as foreground text/border on --bg/--surface, 8.88:1 as background
     with --on-accent text */
  --accent: #b2b2b3;
  /* brighter, not darker, on hover/press - preserves the "reads as live"
     reasoning the old gold hover state used */
  --accent-2: #e7e7e5;
  --on-accent: #14110d;
  /* EmGrand's accent (parent-brand tier of the nav only, .global-bar) -
     7.36:1 on --bg */
  --brass: #c89b3c;
  --radius: 4px;
  --radius-lg: 6px;
  --font-display: "Avenir Next", "Century Gothic", "Segoe UI Semibold",
    -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;

  --st-neutral: #93a3b8;
  --st-blue: #7fb3e0;
  --st-violet: #b79cf0;
  --st-green: #6fcf97;
  /* shifted from the old amber's yellow-gold toward orange (#302 lesson,
     applied preemptively): a warning color this close to --accent's hue
     would read as branding, not a status */
  --st-amber: #e8935a;
  --st-red: #e2685f;
}

* { box-sizing: border-box; }
/* author display rules (flex/grid) must never defeat the hidden attribute */
[hidden] { display: none !important; }

/* Keyboard-focus ring (#162): several controls suppress the UA outline
   (outline: none with a border-color swap), which leaves keyboard users
   with no focus indicator at all on buttons/links/toggles. :focus-visible
   fires for keyboard focus only, so mouse users see no change. */
:is(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  font-size: 15px;
  line-height: 1.6;
}

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

h1, h2, h3 { font-family: var(--font-display); font-weight: 600; line-height: 1.3; }
h1 { font-size: 22px; margin: 0; }
h2 { font-size: 18px; }

/* Two-tier nav (emgrand-brand-style-guide.md "Layout"): a persistent
   EmGrand parent-brand bar above the Vectra product bar. Both stay on the
   app's one dark ground - .global-bar on --bg (darkest), .appbar on
   --surface (one step up) - rather than switching to a light surface for
   the top tier, which would break the single-dark-theme decision this
   file's header comment documents. Separation comes from that shade
   step plus the accent swap (brass above, silver below), not a color
   bar or edge stripe (style guide: "No accent stripes"). */
.global-bar {
  display: flex; align-items: center;
  padding: 7px 20px;
  background: var(--bg);
  border-bottom: 1px solid var(--border);
}
.global-brand {
  display: inline-flex; align-items: center; gap: 6px;
  color: var(--brass); font-family: var(--font-display); font-weight: 600;
  letter-spacing: .06em; font-size: 12px; text-transform: uppercase;
}
.appbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 20px;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
}
.brand {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  color: var(--text);
}
.brand-mark { display: block; flex: none; height: 32px; width: auto; }
.brand-word {
  display: block; font-family: var(--font-display); font-weight: 700;
  letter-spacing: .04em; font-size: 15px;
}
.appbar-nav { display: inline-flex; align-items: center; gap: 16px; }
.appbar-nav a:not(.btn) { color: var(--text-2); font-family: var(--font-display); }
.org-pill {
  font-family: var(--font-display); font-size: 12.5px; color: var(--text-2);
  border: 1px solid var(--border-2); border-radius: 20px; padding: 5px 12px;
}

.container { max-width: 760px; margin: 0 auto; padding: 28px 20px 60px; }

.page-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; margin: 0 0 20px;
}
.page-head .muted { color: var(--text-3); font-size: 14px; }

.btn {
  display: inline-flex; align-items: center; gap: 6px;
  font: inherit; font-size: 14px; cursor: pointer;
  padding: 8px 14px; border-radius: var(--radius);
  border: 1px solid var(--border-2); background: var(--surface); color: var(--text);
}
.btn:hover { border-color: var(--text-3); text-decoration: none; }
.btn-primary { background: var(--accent); color: var(--on-accent); border-color: transparent; }
.btn-primary:hover { background: var(--accent-2); }
/* a clicked run/preview button stays visible and turns happy blue while
   the job runs (never dimmed away by the disabled state) */
.btn-clicked, .btn-clicked:disabled, .btn-primary.btn-clicked {
  background: #3b82f6; color: #ffffff; border-color: transparent;
  opacity: 1; cursor: default;
}

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 20px 22px;
}

.job-list { display: flex; flex-direction: column; }
.job-row {
  display: flex; align-items: center; gap: 14px;
  padding: 14px 4px;
  border-top: 1px solid var(--border);
  color: var(--text);
}
.job-row:hover { background: color-mix(in srgb, var(--text) 3%, transparent); }
.job-row:last-child { border-bottom: 1px solid var(--border); }
.job-row .grow { flex: 1; min-width: 0; }
.job-row .name { font-weight: 500; }
.job-row .sub { color: var(--text-3); font-size: 13px; }
.job-row .chev { color: var(--text-3); }

.badge {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12px; font-weight: 500; white-space: nowrap;
  padding: 3px 10px; border-radius: 999px;
  color: var(--fg, var(--st-neutral));
  background: color-mix(in srgb, var(--fg, var(--st-neutral)) 15%, var(--surface));
}
.badge::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
/* #585: status pill mapping onto the --st-* ramp. Violet is the only
   state waiting on a PERSON (awaiting_confirmation); every other in-flight
   state is blue, because the client did not cause it to pause. This
   corrects the original mapping, which had those two swapped -
   awaiting_confirmation read amber (an outcome hue) and generating_maps
   read violet (implying it waits on the client, which it does not). */
.status-draft { --fg: var(--st-neutral); }
.status-queued, .status-analyzing, .status-processing,
.status-generating_maps { --fg: var(--st-blue); }
.status-awaiting_confirmation { --fg: var(--st-violet); }
.status-queued::before, .status-analyzing::before,
.status-processing::before, .status-generating_maps::before {
  animation: pulse 1.6s ease-in-out infinite;
}
/* #600. The JOB DETAIL poller (_job_detail_js.html) adds .status-unknown
   when it gives up, so the last status it read stops passing for a live
   one. The list poller in base.html does NOT - it clears its interval and
   calls vectraPollStopped to show the notice, and its rows keep whatever
   status they last rendered. An earlier version of this comment said
   "both pollers", which was never true; if the list ever needs the same
   treatment, the class is here and unused for it.
   It has to come after the .status-* rules above (same specificity, source
   order decides) and it kills the pulse as well as the colour - the
   pulsing dot is what makes a badge read as live, so leaving it running
   would undo the point. */
.status-unknown { --fg: var(--st-neutral); }
.status-unknown::before { animation: none; }

/* The #600 notice. Not .messages: that block is server-rendered per
   request, this one ships hidden on every page and is revealed by JS. */
.page-notice {
  margin: 0 0 14px; padding: 10px 14px;
  border: 1px solid color-mix(in srgb, var(--st-amber) 40%, var(--surface));
  border-left: 3px solid var(--st-amber);
  border-radius: 8px;
  background: color-mix(in srgb, var(--st-amber) 7%, var(--surface));
  color: var(--text-1, inherit); font-size: 14px;
}
.page-notice a { color: var(--st-amber); }

@keyframes pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.25; }
}
@media (prefers-reduced-motion: reduce) {
  .badge::before { animation: none; }
}
.status-completed { --fg: var(--st-green); }
.status-completed_warnings { --fg: var(--st-amber); }
/* #545: the shared .badge 15% mix leaves failed-status text at 4.43:1,
   just under AA's 4.5:1 - the only status that misses. Narrower mix here
   lightens this one badge's background without touching --st-red itself
   (used elsewhere for alarms/errors/limits where this isn't a factor). */
.status-failed { --fg: var(--st-red); background: color-mix(in srgb, var(--st-red) 10%, var(--surface)); }
/* #588: an operator-written ledger row (a comp) rendered distinctly from
   a customer-driven one, reusing .badge rather than a new component. */
.badge-comp { --fg: var(--st-violet); }
.badge-comp::before { content: none; }

.detail-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }

.progress-area { display: flex; align-items: center; gap: 10px; margin: 4px 0 14px; }
.spinner {
  flex: none; width: 16px; height: 16px; border-radius: 50%;
  border: 2px solid var(--border-2); border-top-color: var(--accent);
  animation: spin 0.9s linear infinite;
}
@media (prefers-reduced-motion: reduce) {
  .spinner { animation: none; border-top-color: var(--border-2); }
}
@keyframes spin { to { transform: rotate(360deg); } }
.progress-track {
  display: none; flex: 1; max-width: 280px; height: 6px;
  border-radius: 999px; overflow: hidden;
  background: color-mix(in srgb, var(--text) 10%, transparent);
}
.progress-fill {
  height: 100%; width: 0; border-radius: 999px;
  background: var(--accent); transition: width 0.6s ease;
}
/* uncounted engine phases (import, save, layout prep): a sliding sheen
   says "alive" while the phase text says WHAT is happening */
.progress-fill.indeterminate {
  background: repeating-linear-gradient(
    -60deg,
    var(--accent) 0 10px,
    color-mix(in srgb, var(--accent) 55%, transparent) 10px 20px
  );
  background-size: 200% 100%;
  animation: progress-slide 1.1s linear infinite;
  transition: none;
}
@keyframes progress-slide {
  from { background-position: 0 0; }
  to { background-position: 23px 0; }
}
@media (prefers-reduced-motion: reduce) {
  /* was the one animation the reduce block missed (#162): the striped
     gradient stays as the "alive" cue, it just doesn't slide */
  .progress-fill.indeterminate { animation: none; }
}
.progress-text { font-size: 12px; color: var(--text-3); }
/* the copy of the progress area directly below the run buttons */
.confirm-actions .confirm-progress { flex-basis: 100%; margin: 10px 0 0; }
.detail-msg { color: var(--text-2); margin: 6px 0 4px; min-height: 1.2em; }
/* Finding row (#585): the confirm screen's per-finding review unit - label,
   detected value, a confirm control, and an optional change disclosure
   underneath. It already exists as two shapes rather than one, kept
   separate on purpose because they are not the same box model: .kv (below)
   is the single-line form (zone, parcel count) and .parcel-check (further
   down) adds a sample list and/or a .field-picker disclosure beneath the
   label for findings that need more room (parcel ID, owner, access roads,
   Line List, footprint). Both drive their confirm control through the same
   .addon-mini.verify-toggle switch and their disclosure through the same
   .field-picker, which is what actually collapses the eleven current
   variations into shared markup - a third wrapper class here would only
   rename what's already unified. */
.kv { display: flex; justify-content: space-between; gap: 12px; padding: 10px 0; border-top: 1px solid var(--border); font-size: 14px; }
/* the confirmation page's parcel count - the NUMBER only: bold Times
   New Roman at 2.24em (Pete's spec, 2026-07-18: 40% up, then another
   60% on the number itself; the word "parcels" stays row-sized) */
.parcel-count {
  font-family: "Times New Roman", Times, serif;
  font-weight: 700;
  font-size: 2.24em;
}
.kv:first-of-type { border-top: none; }
.kv .k { color: var(--text-2); }

.section-title { font-size: 15px; font-weight: 500; margin: 20px 0 6px; }
.outputs { list-style: none; padding: 0; margin: 0; }
.outputs li { display: flex; align-items: center; gap: 18px; padding: 9px 0; border-top: 1px solid var(--border); }
/* overflow-wrap: file names are unbroken tokens (1.002001_shapefiles.zip)
   - without a break opportunity they'd overflow the flex box straight
   under the download link */
.outputs .oname { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
.outputs li a { flex: none; white-space: nowrap; margin-left: auto; }
.empty { color: var(--text-3); font-size: 14px; padding: 4px 0; }

.outputs-head { margin: 4px 0 14px; }
.btn-glow {
  box-shadow: 0 0 12px color-mix(in srgb, var(--accent) 55%, transparent),
              0 0 3px color-mix(in srgb, var(--accent) 70%, transparent);
}
.btn-glow:hover {
  box-shadow: 0 0 18px color-mix(in srgb, var(--accent) 75%, transparent),
              0 0 5px color-mix(in srgb, var(--accent) 85%, transparent);
}
.btn-sm { padding: 5px 11px; font-size: 13px; white-space: nowrap; }

/* Deliverable tree node (#585): recursive - the same node renders a
   spread, a county, an owner, or a leaf parcel. .parcel-folder is the
   node itself (the <details>/<summary> row plus its per-level download
   button); .spread-folder, .county-folder and .owner-folder are thickness/
   indent modifiers layered on the same base for the three groupings
   (spread -> county -> parcel; owner -> parcel; and the flat fallback,
   which is bare .parcel-folder with no modifier). One component already
   serves all of them - see .spread-folder / .county-folder / .owner-folder
   further down for where each grouping opts in. */
.parcel-folder {
  display: flex; align-items: flex-start; gap: 12px;
  border-top: 2px solid var(--border-2); padding: 6px 10px 6px 6px;
}
/* collapsed bars carry an accent gradient: bright at the center and
   brightest at the right, under the Download parcel button */
.parcel-folder:has(details:not([open])) {
  background: linear-gradient(
    90deg,
    color-mix(in srgb, var(--accent) 3%, transparent) 0%,
    color-mix(in srgb, var(--accent) 16%, transparent) 50%,
    color-mix(in srgb, var(--accent) 9%, transparent) 72%,
    color-mix(in srgb, var(--accent) 30%, transparent) 100%
  );
}
.parcel-folder details { flex: 1; min-width: 0; }
.parcel-folder summary {
  display: flex; align-items: center; gap: 10px;
  padding: 5px 0; cursor: pointer; list-style: none; user-select: none;
}
.parcel-folder summary::-webkit-details-marker { display: none; }
.folder-icon { flex: none; width: 0; height: 0; margin-left: 2px;
  border-left: 9px solid var(--text-2);
  border-top: 6px solid transparent; border-bottom: 6px solid transparent;
  transition: transform 0.15s;
  filter: drop-shadow(0 0 4px var(--accent));
}
/* child-scoped: every tier carries .parcel-folder, so a descendant
   selector would pre-rotate every NESTED arrow the moment the outer
   tier opens (the "arrows stop rotating after the first tier" bug) */
.parcel-folder details[open] > summary .folder-icon { transform: rotate(90deg); }
.folder-files { margin-left: 21px; }
.folder-files li { font-size: 13px; }
.folder-files li:first-child { border-top: none; }
.parcel-folder .btn-sm { margin-top: 3px; }

/* nested deliverable tree (long jobs): spread -> county -> parcel */
.spread-folder { border-top: 3px solid var(--border-2); }
.spread-folder > details > summary .oname { font-weight: 600; }
.county-folder { margin-left: 20px; border-top: 1px solid var(--border); }
.county-folder .parcel-folder { margin-left: 20px; border-top: 1px solid var(--border); }

.parcel-check { padding: 12px 0 10px; border-top: 1px solid var(--border); }
.parcel-check-q { margin: 0 0 6px; font-weight: 700; }
.parcel-check-field { margin: 0 0 4px; font-weight: 700; color: var(--accent); }
.parcel-check-samples {
  list-style: none; margin: 0; padding: 0;
  font-size: 13px; color: var(--text-2);
  font-variant-numeric: tabular-nums;
}
.parcel-check-samples li { padding: 1px 0; }

/* verification toggles (confirmation page): compact yes/no switch used on
   each analysis question and category row */
.check-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.addon-mini {
  display: inline-flex; align-items: center; gap: 8px;
  cursor: pointer; user-select: none; flex: none;
  min-height: 24px; /* #545: WCAG 2.5.8 - the bare 22px switch undershot this */
}
.addon-mini .addon-state { width: 24px; font-size: 12px; }
.analysis-layers .addon-mini { justify-content: flex-end; }
.field-picker { margin: 10px 0 4px; }
/* the picker question reads like the other check questions: full text
   color (white in dark theme), bold */
.field-picker .parcel-check-q { margin: 0 0 6px; }
.field-picker .parcel-check-q label { color: var(--text); font-weight: 700; cursor: pointer; }
.field-picker select {
  font: inherit; font-size: 14px; padding: 7px 10px; min-width: 260px;
  border: 1px solid var(--border-2); border-radius: var(--radius);
  background: var(--surface); color: var(--text);
}
.field-picker select:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 22%, transparent);
}

/* route-overview map: provided centerline over OpenStreetMap */
.route-map {
  height: 340px; margin: 8px 0 4px;
  border: 1px solid var(--border-2); border-radius: var(--radius);
  background: var(--bg);
}
.route-map-legend {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin: 6px 0 0; font-size: 13px; color: var(--text-2);
}
.route-chip {
  flex: none; width: 22px; height: 0; border-radius: 2px;
  border-top: 4px solid #1d4ed8;
}
.route-chip-true { border-top-style: dashed; border-top-color: #0d9488; margin-left: 10px; }

/* typical-section style chooser: 3 tiles (original + two magnifier
   families); the family tiles open a 6-style popup for the final pick.
   Thumbnails are the real engine generator's output. */
.look-picker { margin-top: 14px; }
.look-tiles {
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: 12px; margin-top: 8px;
}
@media (max-width: 640px) { .look-tiles { grid-template-columns: 1fr; } }
.look-tile {
  position: relative; display: flex; flex-direction: column; gap: 4px;
  padding: 8px; border: 2px solid var(--border-2);
  border-radius: var(--radius); background: var(--surface);
}
label.look-tile { cursor: pointer; }
.look-tile input[type="radio"] { position: absolute; opacity: 0; pointer-events: none; }
.look-thumbwrap {
  display: flex; align-items: center; justify-content: center;
  background: #ffffff; border: 1px solid var(--border); border-radius: 4px;
  padding: 4px; min-height: 152px; overflow: hidden;
}
.look-thumbwrap img { max-width: 100%; max-height: 148px; height: auto; width: auto; display: block; }
.look-name { font-weight: 600; font-size: 13px; margin-top: 2px; }
.look-desc { font-size: 12px; line-height: 1.35; min-height: 1.2em; }
.look-tile:hover { border-color: var(--text-3); }
.look-tile.sel {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 22%, transparent);
}
.look-tile:has(> input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px; }
.look-check {
  position: absolute; top: 8px; right: 8px; width: 22px; height: 22px;
  border-radius: 50%; background: var(--accent); color: var(--on-accent);
  display: none; align-items: center; justify-content: center;
  font-size: 13px; z-index: 2;
}
.look-tile.sel .look-check { display: flex; }
.look-choose {
  margin-top: 4px; align-self: flex-start; font: inherit; font-size: 12px;
  font-weight: 600; color: var(--accent); background: transparent;
  border: 1px solid var(--border-2); border-radius: 6px;
  padding: 6px 10px; cursor: pointer;
}
.look-choose:hover { border-color: var(--accent); }
.look-choose:disabled { color: var(--text-3); cursor: default; opacity: 0.7; }
.look-tile.locked { opacity: 0.85; }

/* the choose-style popup (modal overlay) */
.look-pop {
  position: fixed; inset: 0; z-index: 60; display: flex;
  align-items: center; justify-content: center; padding: 20px;
}
.look-pop[hidden] { display: none; }
.look-pop-backdrop { position: absolute; inset: 0; background: rgba(10, 12, 14, 0.5); }
.look-pop-sheet {
  position: relative; width: min(620px, 100%); max-height: 86vh; overflow: auto;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-lg); box-shadow: 0 20px 60px rgba(0, 0, 0, 0.35);
}
.look-pop-head {
  position: sticky; top: 0; display: flex; align-items: center; gap: 10px;
  padding: 14px 16px; font-weight: 600;
  background: var(--surface); border-bottom: 1px solid var(--border);
}
.look-pop-x {
  margin-left: auto; width: 30px; height: 30px; border-radius: 6px;
  /* #545: this is a real control, not a decorative panel edge - its
     default (non-hover) state must clear WCAG 1.4.11 on its own. */
  border: 1px solid var(--border-2); background: var(--bg-2); color: var(--text);
  cursor: pointer; font-size: 14px; line-height: 1;
}
.look-pop-grid {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; padding: 16px;
}
@media (max-width: 560px) { .look-pop-grid { grid-template-columns: repeat(2, 1fr); } }
.look-opt {
  position: relative; display: flex; flex-direction: column; gap: 4px;
  cursor: pointer; padding: 6px; border: 2px solid var(--border-2);
  border-radius: var(--radius); background: var(--surface);
}
.look-opt input[type="radio"] { position: absolute; opacity: 0; pointer-events: none; }
.look-opt img {
  width: 100%; height: auto; background: #ffffff;
  border: 1px solid var(--border); border-radius: 4px;
}
.look-opt-name { font-size: 12px; font-weight: 600; text-align: center; }
.look-opt:hover { border-color: var(--accent); }
.look-opt.cur {
  border-color: var(--accent);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 30%, transparent);
}
.look-opt:has(input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px; }
.look-opt-check {
  position: absolute; top: 6px; right: 6px; width: 20px; height: 20px;
  border-radius: 50%; background: var(--accent); color: var(--on-accent);
  display: none; align-items: center; justify-content: center; font-size: 12px;
}
.look-opt.cur .look-opt-check { display: flex; }

/* typical footprint cross-section diagram (confirmation page) */
/* frosted-ice typical section (Pete's approved design, 2026-07-18):
   the SVG carries its own dark blueprint card, legend and dimensions -
   styling lives inline in the SVG, CSS only sizes it. Full-width and
   stacked: the denser drafting text needs the room. */
.xsec { display: block; width: 100%; max-width: 700px; height: auto; margin: 8px 0 2px; }
/* primary + 2nd-most-common configurations side by side (wrap when narrow) */
.xsec-pair { display: flex; flex-direction: column; gap: 18px; align-items: stretch; }
.xsec-cell { min-width: 0; }
.xsec-sub { margin: 8px 0 0; font-weight: 700; }
.suffix-input {
  display: flex; align-items: center; margin-top: 8px; max-width: 340px;
  border: 1px solid var(--border-2); border-radius: var(--radius);
  background: var(--surface); overflow: hidden;
}
.suffix-input input {
  flex: 1; min-width: 0; font: inherit; font-size: 14px;
  padding: 7px 4px 7px 10px; border: none; outline: none;
  background: transparent; color: var(--text);
}
.suffix-input .suffix {
  flex: none; padding-right: 10px; font-size: 14px; color: var(--text-3);
  user-select: none; white-space: nowrap;
}
/* The wrapper sets overflow:hidden, which clips the inner input's outline
   (#471 review LOW-4) - so the ring has to live on the wrapper itself. */
.suffix-input:has(:focus-visible) {
  outline: 2px solid var(--accent); outline-offset: 2px;
}
.suffix-input:focus-within {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 22%, transparent);
}
.custom-config { margin-top: 10px; }
.width-fields { display: flex; gap: 10px; flex-wrap: wrap; }
.width-fields label {
  display: flex; flex-direction: column; gap: 3px;
  font-size: 12px; color: var(--text-2);
}
.width-fields input {
  width: 96px; font: inherit; font-size: 14px; padding: 6px 8px;
  border: 1px solid var(--border-2); border-radius: var(--radius);
  background: var(--surface); color: var(--text);
}
.width-fields input:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 22%, transparent);
}
/* (the old flat-diagram classes - xsec-ws/esmt/cl*/dim/feet/legend/
   swatch - retired with the frosted-ice port; rollback lives in
   _xsec_svg_legacy.html + git) */
.cl-offset-alert {
  margin-top: 8px; padding: 10px 12px; border-radius: 8px;
  border: 1px solid color-mix(in srgb, var(--st-amber) 55%, transparent);
  background: color-mix(in srgb, var(--st-amber) 12%, transparent);
}
.cl-offset-alert .cl-offset-head { margin: 0 0 6px; font-size: 13px; }

.results { width: 100%; border-collapse: collapse; font-size: 14px; }
.results th { text-align: left; font-weight: 500; color: var(--text-2); font-size: 13px; padding: 6px 8px 6px 0; border-bottom: 1px solid var(--border-2); }
.results td { padding: 7px 8px 7px 0; border-bottom: 1px solid var(--border); }
.results .num { text-align: right; font-variant-numeric: tabular-nums; }

/* #587: /ops/ fleet table. `.results` above covers layout; this is only
   the one thing that table doesn't already have - an alarm color for the
   reporter verdict and the "at limit" flag, matching --st-red's use
   elsewhere (status-failed). Wrapped in a scrolling container rather than
   letting the table itself overflow the page: at six columns this is the
   widest table in the app and the narrowest viewport it has to render in. */
.ops-table-wrap { overflow-x: auto; }
/* Public price sheet (#33 repricing): same job as .ops-table-wrap above,
   on a page an anonymous visitor reaches from a phone. The rate card is
   three columns and the volume ladder two, so this is a guard against a
   long product label pushing the PAGE sideways, not a routine scroller. */
.table-scroll { overflow-x: auto; }
.ops-alarm { color: var(--st-red); font-weight: 600; }

.actions { margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--border); }
.confirm-actions { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }
.confirm-actions p { margin: 0; }

.addon-row {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 0; border-top: 1px solid var(--border);
  cursor: pointer; user-select: none;
}
.addon-row:first-of-type { border-top: none; }
.addon-label { flex: 1; font-size: 14px; }
.addon-check { position: absolute; opacity: 0; pointer-events: none; }
.addon-toggle {
  flex: none; position: relative; width: 40px; height: 22px;
  border-radius: 999px; background: var(--border-2);
  transition: background 0.15s;
}
.addon-toggle::after {
  content: ""; position: absolute; top: 3px; left: 3px;
  width: 16px; height: 16px; border-radius: 50%;
  background: var(--surface); transition: left 0.15s;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
}
.addon-check:checked ~ .addon-toggle { background: var(--accent); }
.addon-check:checked ~ .addon-toggle::after { left: 21px; }
.addon-check:focus-visible ~ .addon-toggle {
  /* The input itself is opacity:0, so the global ring lands on something
     nobody can see and this glow was the sole indicator (#471 review
     HIGH-3). A real outline is the indicator; the glow is decoration. */
  outline: 2px solid var(--accent); outline-offset: 2px;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 30%, transparent);
}
.addon-state { flex: none; width: 26px; font-size: 13px; color: var(--text-3); }
.addon-state::before { content: attr(data-off); }
.addon-check:checked ~ .addon-state { color: var(--accent); }
.addon-check:checked ~ .addon-state::before { content: attr(data-on); }

.layout-picker { display: flex; gap: 14px; flex-wrap: wrap; margin: 10px 0 4px; }
.layout-card {
  position: relative; display: flex; flex-direction: column; gap: 6px;
  width: 150px; padding: 8px; cursor: pointer;
  border: 2px solid var(--border-2); border-radius: var(--radius);
  background: var(--surface);
}
.layout-card:hover { border-color: var(--text-3); }
.layout-card:has(input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px; }
.layout-card:has(input:checked) {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 22%, transparent);
}
.layout-card input { position: absolute; opacity: 0; pointer-events: none; }
.layout-card img {
  width: 100%; height: 190px; object-fit: contain;
  background: #fff; border-radius: 4px;
}
.layout-noimg {
  display: flex; align-items: center; justify-content: center;
  height: 190px; color: var(--text-3); font-size: 12px;
  border: 1px dashed var(--border-2); border-radius: 4px;
}
.layout-name { font-size: 12px; text-align: center; color: var(--text-2); word-break: break-all; }
.analysis-layers { margin: 10px 0 4px; }
.warn-list {
  list-style: none; margin: 12px 0 4px; padding: 10px 14px;
  border: 1px solid color-mix(in srgb, var(--st-amber) 45%, var(--border));
  border-radius: var(--radius);
  background: color-mix(in srgb, var(--st-amber) 8%, var(--surface));
  font-size: 13px; color: var(--text-2);
}
.warn-list li { padding: 2px 0; }
.warn-list li::before { content: "⚠ "; color: var(--st-amber); }
/* Layout QC panel: findings about OUR pages (docs/layout-pipeline.md) */
.qc-sev {
  display: inline-block; min-width: 62px; text-align: center;
  font-size: 11px; font-weight: 600; text-transform: uppercase;
  letter-spacing: .04em; border-radius: 4px; padding: 1px 6px;
  margin-right: 6px;
}
/* delivery scorecard (confirmation page): data-quality verdicts over
   the raw delivery - informational, never blocking */
.sc-pass { background: color-mix(in srgb, var(--st-green) 18%, var(--surface)); color: var(--st-green); }
.sc-warn { background: color-mix(in srgb, var(--st-amber) 18%, var(--surface)); color: var(--st-amber); }
.scorecard {
  margin: 0 0 14px; padding: 12px 14px; border-radius: var(--radius-lg);
  border: 1px solid var(--border); background: color-mix(in srgb, var(--text) 2%, transparent);
}
.scorecard-head { margin: 0 0 6px; font-size: 14px; }
.scorecard-list { list-style: none; margin: 0; padding: 0; font-size: 13px; }
.scorecard-list li { padding: 3px 0; }
.back { display: inline-block; color: var(--text-2); font-size: 14px; margin-bottom: 12px; }

.form .field { margin: 0 0 16px; }
.form label { display: block; font-size: 13px; color: var(--text-2); margin: 0 0 5px; }
.form input, .form select, .form textarea {
  width: 100%; font: inherit; font-size: 14px;
  padding: 8px 10px; border: 1px solid var(--border-2);
  border-radius: var(--radius); background: var(--surface); color: var(--text);
}
.form input:focus, .form select:focus, .form textarea:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 22%, transparent);
}
.form input[type="file"] { padding: 8px; background: var(--bg); cursor: pointer; }

/* Consent checkbox (signup + reconsent, #522): shared class so both pages
   render it identically. Was `label class="muted"` on signup (the one
   control a user must actively agree to, styled as the faintest text on
   the page) and a bare, unstyled `label class="checkbox"` on reconsent
   that `.form input` was stretching to a full-width bordered text-box
   look (the "floats awkwardly" the issue describes) - this overrides that
   with the higher-specificity type selector below. Full text weight, not
   .muted; the wrapping <label> keeps the whole sentence clickable.
   Selector is `.form label.consent-check`, not the bare class: `.form
   label` above is (0,1,1) and a bare `.consent-check` is only (0,1,0), so
   display/color/font-size silently lost to it - measured via
   getComputedStyle, not eyeballed, since this file has no screenshot
   tooling. */
.form label.consent-check {
  display: flex; align-items: flex-start; gap: 10px;
  color: var(--text); font-size: 14px; line-height: 1.45;
  cursor: pointer; margin: 0 0 5px;
}
.consent-check input[type="checkbox"] {
  flex: none; width: 18px; height: 18px; margin: 3px 0 0;
  padding: 0; border-radius: 3px;
  accent-color: var(--accent);
  cursor: pointer;
}

/* Show/hide password (#463). The wrapper and button are created by JS, so
   without it the field is an ordinary password input and none of this
   applies - the point being that a JS-less render must never be a
   plaintext one. */
.pw-wrap { display: flex; gap: 6px; align-items: stretch; }
.pw-wrap input { flex: 1 1 auto; min-width: 0; }
.pw-toggle {
  /* min-width, because "Hide" is wider than "Show": without it the input
     rewidths on every toggle and the caret jumps (#463 review L8). */
  flex: 0 0 auto; min-width: 68px; font: inherit; font-size: 13px; padding: 0 8px;
  border: 1px solid var(--border-2); border-radius: var(--radius);
  background: var(--bg); color: var(--text-2); cursor: pointer;
}
.pw-toggle:hover { color: var(--text); border-color: var(--text-2); }
.pw-toggle:focus-visible {
  /* No `outline: none` here (#470 review F1). Suppressing it and
     substituting a color-mix glow is precisely the pattern #471/#472
     removed - and #472's stylesheet test names this selector, so keeping it
     would turn main red the moment both landed. The global #162 rule
     already puts the 2px accent ring on the button; the border and glow are
     decoration on top of it. */
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 22%, transparent);
}
/* Announced by screen readers, never shown: the button's own name changes
   too, but a name change is only heard on re-focus, and the person needs
   to know the state changed at the moment they pressed it. */
.visually-hidden {
  position: absolute; width: 1px; height: 1px; margin: -1px;
  padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
  border: 0;
}

/* #545: off-screen until focused, so a keyboard/screen-reader user can jump
   past the appbar nav, but sighted mouse users never see it. */
.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  padding: 10px 16px; background: var(--surface); color: var(--text);
  border-radius: 0 0 6px 0;
}
.skip-link:focus { left: 0; }

.dropzone {
  position: relative;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 4px; padding: 22px 16px; text-align: center;
  border: 1.5px dashed var(--border-2); border-radius: var(--radius);
  color: var(--text-2); font-size: 13px;
  transition: border-color 0.15s, background-color 0.15s;
}
.dropzone.dragover, .dropzone:hover { border-color: var(--accent); }
.dropzone.dz-error { border-color: var(--st-red); }
.dropzone.dragover { background: color-mix(in srgb, var(--accent) 8%, var(--surface)); }
.dropzone input[type="file"] {
  position: absolute; inset: 0; width: 100%; height: 100%;
  opacity: 0; cursor: pointer;
}
/* #545/#162: the real input is opacity:0 and covers the whole zone, so the
   browser's own ring is painted on something invisible - a keyboard user
   tabbing to the upload control saw NOTHING. Same shape, and same fix, as
   the six controls already parametrized in test_stylesheet.py; these two
   were simply missed when that list was drawn up. */
.dropzone:has(input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px; }
.dropzone .dz-icon { font-size: 20px; line-height: 1; color: var(--text-3); }
.dropzone .dz-file { color: var(--accent); font-weight: 500; }
.form .help { font-size: 12px; color: var(--text-3); margin: 5px 0 0; }

/* confirmation-page logo upload (prints lower-left on every exhibit) */
.logo-upload {
  position: relative; display: flex; align-items: center; gap: 10px;
  border: 1.5px dashed var(--border-2); border-radius: var(--radius);
  padding: 12px 14px; margin: 6px 0 2px;
  color: var(--text-2); font-size: 13px; cursor: pointer;
  transition: border-color 0.15s;
}
.logo-upload:hover { border-color: var(--accent); }
.logo-upload input[type="file"] {
  position: absolute; inset: 0; width: 100%; height: 100%;
  opacity: 0; cursor: pointer;
}
.logo-upload:has(input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px; }
.form .error { font-size: 13px; color: var(--st-red); margin: 5px 0 0; }
.form-row { display: flex; gap: 14px; }
.form-row .field { flex: 1; }

/* ---- public pages (landing / pricing / account stubs) ---- */

.container-wide { max-width: 980px; }

.btn-lg { padding: 10px 18px; font-size: 15px; }

.hero { text-align: center; padding: 44px 0 36px; }
.hero-title { font-size: 34px; font-weight: 600; max-width: 640px; margin: 0 auto; }
.hero-sub { color: var(--text-2); max-width: 560px; margin: 14px auto 0; }
.hero-actions { display: flex; justify-content: center; gap: 12px; margin-top: 22px; }

.steps { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; margin: 8px 0 28px; }
.step { position: relative; }
.step h2 { margin: 10px 0 6px; font-size: 16px; }
.step p { margin: 0; font-size: 14px; }
.step-no {
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; border-radius: 50%;
  background: color-mix(in srgb, var(--accent) 15%, var(--surface));
  color: var(--accent); font-size: 13px; font-weight: 600;
}

.sample { display: flex; gap: 22px; align-items: center; }
.sample-copy { flex: 1; }
.sample-copy h2 { margin-top: 0; }
/* .sample-thumb removed with the "(placeholder)" box it styled (#544).
   Layout previews are #245; whatever that adds will want its own sizing
   rather than a dashed-border shell kept alive on spec. */

/* auto-fit, not repeat(3): three tiers today, and a fourth (or a second
   currency column) must not require a CSS edit to stop leaving a dead
   quarter of the row. The shared mobile collapse at .steps below still
   flattens both to one column. */
.tiers { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 14px; margin-bottom: 18px; }
.tier { display: flex; flex-direction: column; gap: 4px; }
.tier h2 { margin: 0; font-size: 16px; }
.tier-featured { border-color: var(--accent); }
.tier-price { font-size: 26px; font-weight: 600; margin: 4px 0; }
.tier-price .per { font-size: 13px; font-weight: 400; color: var(--text-3); }
.tier-list { list-style: none; padding: 0; margin: 0 0 14px; flex: 1; }
.tier-list li { font-size: 13px; color: var(--text-2); padding: 4px 0; border-top: 1px solid var(--border); }
.tier .btn { justify-content: center; }

/* Volume discounts (2026-08-15, Andre): the ladder is the thing an annual
   commitment BUYS, and the page rendered it as flat as everything else -
   a bullet in the same weight and colour as the term line beside it, and
   an "included with Annual" sentence set in the same muted fine print as
   the marginality note below the table. These rules extend the accent
   .tier-featured already gives the annual card down to the section that
   card's commitment pays for - deliberately the same border colour, so
   the two read as one thing rather than as two competing highlights.

   GUARD SCOPE, stated exactly, because the near-miss version of this
   sentence is what gate-1 caught: .tier-unlock, .volume-panel,
   .volume-head, .badge-unlock and .volume-off are all applied inside
   pricing.html's `volume_bands` / `volume_rows` guard, so a plan
   configured without bands advertises nothing. .tier-lacks is the
   EXCEPTION and is applied to an unguarded line on purpose - see its own
   note below, and pricing.html's header comment, which already records
   why that line has no key to hang on.

   Contrast recomputed against this sheet's tokens, not assumed - the
   panel tint lightens the background these sit on, so the header
   comment's numbers do not carry over. The binding one: --text-3 on the
   6% tint is 4.94:1, down from 5.45:1 on --surface and the only value
   here anywhere near AA's 4.5:1 for 13px body text. --text-2, --accent
   as text and as the 1px outline, and .badge-unlock's --accent on
   .badge's own 15% mix all clear it by margins wide enough that quoting
   them would just be four more numbers to go stale. */
.tier-list li.tier-unlock { color: var(--accent); font-weight: 600; }
/* The monthly card's mirror-image line. "Unlocks with annual" only reads
   if the tier WITHOUT the ladder is visibly the lesser of the two, so the
   pair is styled as a pair - neither line means much on its own.
   The line this lands on is deliberately unguarded (pricing.html's header
   comment: it asserts the ABSENCE of a ladder, so there is no config key
   to gate it on), which means this rule alone CAN paint with the guard
   closed. That is muting a line that stays true when no ladder exists, so
   it advertises nothing - but it is the one rule in this block that
   renders in that state, and an audit of the guard has to know it. */
.tier-list li.tier-lacks { color: var(--text-3); }

.volume-panel {
  background: color-mix(in srgb, var(--accent) 6%, var(--surface));
  border: 1px solid var(--accent);
  border-radius: var(--radius-lg);
  padding: 18px 20px;
  margin-bottom: 18px;
}
.volume-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.volume-head h2 { margin: 0; }
.badge-unlock { --fg: var(--accent); }
/* Not a status pill: .badge::before paints a dot that reads as a live
   state, and a published rate has none. .badge-comp is the precedent for
   suppressing it on a non-status reuse - it does the same thing without
   recording why, so the reason is written out here rather than cited. */
.badge-unlock::before { content: none; }
.volume-table .volume-off { color: var(--accent); font-weight: 600; }

.small { font-size: 13px; }
.muted { color: var(--text-3); }

.footer {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  max-width: 980px; margin: 0 auto; padding: 18px 20px 28px;
  border-top: 1px solid var(--border); font-size: 13px;
}
.footer-nav { display: inline-flex; gap: 14px; }
.footer-nav a { color: var(--text-2); }

@media (max-width: 720px) {
  .steps, .tiers { grid-template-columns: 1fr; }
  .sample { flex-direction: column; }
  .hero-title { font-size: 26px; }
  /* was display:none - Jobs/Account simply vanished on phones with no
     other way to reach them (#162). Compact and wrappable instead. */
  .appbar-nav { flex-wrap: wrap; gap: 10px; justify-content: flex-end; }
  .appbar-nav a:not(.btn) { font-size: 13px; }
}

/* Drawing-type chooser (#87): three product cards on the data loading page */
.drawing-picker { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 14px; margin: 8px 0 18px; }
.drawing-card {
  position: relative; display: flex; flex-direction: column; align-items: center;
  gap: 8px; padding: 18px 14px 14px; text-align: center; cursor: pointer;
  border: 2px solid var(--border-2); border-radius: 10px; background: var(--bg-2);
  transition: border-color 0.15s, box-shadow 0.15s;
}
.drawing-card input[type="radio"] { position: absolute; opacity: 0; pointer-events: none; }
.drawing-card:has(input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px; }
.drawing-card:has(input:checked) {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 25%, transparent);
}
.drawing-logo { width: 64px; height: 64px; }
.dlogo-frame { fill: none; stroke: var(--text-2); stroke-width: 2.5; }
.dlogo-line { fill: none; stroke: var(--accent); stroke-width: 3; stroke-linecap: round; stroke-linejoin: round; }
.dlogo-accent { fill: var(--accent); stroke: none; }
.dlogo-seal { fill: none; stroke: var(--bg-2); stroke-width: 2; }
.drawing-name { font-weight: 700; }
.drawing-desc { line-height: 1.35; }
.drawing-disclaimer { font-size: 12px; color: var(--st-amber); line-height: 1.35; }

/* Plat-type sub-picker (#773): hidden unless Legal Plats is the checked
   drawing_type, reactively - same :has() mechanism as the card highlight
   above, so it needs no JS and no page reload to appear. */
.plat-type-field { display: none; }
.form:has(input[name="drawing_type"][value="legal_plats"]:checked) .plat-type-field {
  display: block;
}
.soon-banner {
  position: absolute; top: 10px; right: -8px; transform: rotate(8deg);
  /* --on-accent, not #fff: --accent is light gold, so white-on-accent
     would be illegible (#162's original teal case measured 1.86:1). */
  background: var(--accent); color: var(--on-accent); font-size: 12px; font-weight: 700;
  padding: 2px 10px; border-radius: 4px; box-shadow: 0 1px 4px rgba(0,0,0,0.25);
}
/* Legal Plats (#123): live but Under Construction - selectable, amber-flagged
   (distinct from Route Maps' greyed, non-selectable "Coming Soon").
   60%, not 45% (rebrand review): at 45% the mix measured 2.9:1 against
   --bg-2, the card's own background - under the 3:1 non-text bar for an
   interactive outline. 60% clears it against both --bg-2 and --surface. */
.drawing-card.is-construction { border-color: color-mix(in srgb, var(--st-amber) 60%, var(--border)); }
/* #302, single-theme rebrand: one --st-amber now, so one ink - white
   measured 2.4:1 against the new orange-leaning amber (fails AA);
   --on-accent (near-black) measures 7.2:1. */
.soon-banner.construction-banner { background: var(--st-amber); color: var(--on-accent); }

/* Separate takings (#85): toggles inside a tract folder */
.sep-takes { margin: 6px 0 4px 21px; display: flex; flex-direction: column; gap: 4px; }
.sep-takes-row { display: inline-flex; align-items: center; gap: 8px; }
.sep-takes-label { font-size: 13px; }
.sep-takes-list { margin-left: 4px; font-size: 13px; }
.sep-takes-list summary { cursor: pointer; color: var(--text-2); }

/* Landowner grouping toggle + owner folders (Pete, 2026-07-16) */
.outputs-head { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; }
.owner-group-toggle { margin-left: auto; display: inline-flex; align-items: center; gap: 8px; }
.owner-folder { border-top: 3px solid var(--border-2); }
.owner-folder > details > summary .oname { font-weight: 600; }
.owner-folder .parcel-folder { margin-left: 20px; border-top: 1px solid var(--border); }

/* Detail sheets choice (#88) */
.details-choice { display: flex; flex-direction: column; gap: 6px; margin: 4px 0 14px; font-size: 14px; }
.details-choice label { display: flex; align-items: baseline; gap: 8px; }
.details-choice .details-fix { margin-left: 24px; color: var(--text-2); font-size: 13px; }

/* Allowance meter (#585): plan usage against the included allowance -
   account page today, confirm panel and the operator fleet table once
   #583/#587 land. A bar only for the case it can actually measure: a
   bounded, per-period allowance (quota.included is not None and
   quota.renews is true). Unlimited (included is None - nothing to
   measure against) and lifetime/one-time allowances (renews is false -
   not a period fraction) stay text-only; drawing a bar for either would
   imply a ceiling or a reset that isn't there. */
.allowance-meter { margin: 8px 0; }
.allowance-track {
  height: 8px; border-radius: 999px; overflow: hidden;
  background: var(--bg-2);
}
.allowance-fill { height: 100%; background: var(--accent); }
/* At quota.at_limit (accounts/plans.py's quota_state): the fill reads as
   exhausted, not just full - the same st-red the status ramp uses for a
   terminal FAILED. Unreachable under today's three PLANS entries - the only
   plan whose bar renders (annual) always has overage_allowed=True, which
   forces at_limit False, and the only plan where at_limit can be True
   (trial) never renders the bar at all (renews=False). Kept because
   at_limit is quota_state()'s general per-plan field, not something this
   component invented, and a future bounded plan with overage disabled
   would hit it. */
.allowance-fill.at-limit { background: var(--st-red); }

/* Consequence panel (#585): the block naming what a destructive action
   deletes, stated before the client presses the button rather than only
   inside a native confirm() dialog. Used today by the destructive re-run
   (a FAILED job's partial output) and discard; deactivate and offboard
   stay in Django admin (see docs/frontend-rebuild.md) so they don't
   instantiate this yet. Reuses the amber warning treatment already
   established by .warn-list/.cl-offset-alert rather than inventing a
   second "this is dangerous" language. */
.consequence-panel {
  margin: 10px 0; padding: 12px 14px; border-radius: var(--radius-lg);
  border: 1px solid color-mix(in srgb, var(--st-amber) 45%, var(--border));
  background: color-mix(in srgb, var(--st-amber) 8%, var(--surface));
}
.consequence-panel .consequence-head {
  margin: 0 0 6px; font-size: 13px; font-weight: 600; color: var(--st-amber);
}
.consequence-panel p { margin: 0 0 8px; font-size: 13px; color: var(--text-2); }
.consequence-panel p:last-child { margin-bottom: 0; }
