/* ==========================================================================
   office-theme.css  ·  DZT "Operator Console" redesign
   --------------------------------------------------------------------------
   A pure OVERRIDE layer. It is loaded AFTER office.css and touches nothing in
   it. It works two ways:
     1. It redefines the existing --o-* design tokens on the SAME selector
        (#office, #owner, #portal) that office.css uses, so a widened surface
        ladder, a real green ink tier, a mid ink step and a 4px spacing scale
        propagate through every untouched rule in office.css automatically.
     2. It restates a handful of component rules (type hierarchy, nav active,
        buttons, tabs, cards, tables) at a specificity that MATCHES the live
        rule, so later source order wins with no !important anywhere.

   Identity is preserved, not reinvented: dark theme, the stand's green as the
   accent, steel + amber, squared 3/4/6px radii, the dark-label-on-green rule.
   Every colour is a token; every value was hand-verified for WCAG AA on the
   surface it actually lands on.

   FULLY REVERTIBLE: delete this file's <link> from app/office.html and the
   dashboard returns to exactly what office.css ships. Nothing else changes.

   Fonts: Archivo (--display) and Inter (--body) are already @font-face'd and
   preloaded via tokens.css / app.css / office.html — no @font-face is needed
   or added here. The lever is Archivo's untapped 800/900 weights.
   ========================================================================== */


/* ==========================================================================
   1 · TOKENS — redefined on the live selector so every fix propagates
   ========================================================================== */

/* The content pane shows the body ground; lift the rail above it by keeping
   the pane the deepest plane. Matches office.css's body:has() specificity. */
body:has(#office), body:has(#owner), body:has(#portal) {
  background: #07090B;              /* deepest plane — the floor */
}

#office, #owner, #portal {
  /* ---- surfaces: 5 real steps, widened so a card reads by FILL, not by a
     1px cage (card-on-ground now ~1.30:1, was 1.057:1). No shadow on flat
     surfaces — depth is fill + the top-lit hairline below. ---- */
  --o-bg:      #0E1216;   /* rail/console chassis + board-column well */
  --o-inset:   #151B20;   /* input well, chip, board card, table-header band */
  --o-panel:   #1E262D;   /* the card / stat cell — reads as an object */
  --o-raised:  #2A343B;   /* tile on a panel, 2ndary button, row/tab hover */
  --o-high:    #333E46;   /* floating layers only: menu, modal, drawer */
  --o-hover:   rgba(255, 255, 255, 0.055);
  --o-press:   rgba(255, 255, 255, 0.10);
  --o-scrim:   rgba(5, 7, 9, 0.72);      /* ONE scrim — repoint modal/drawer here */

  /* ---- lines: solid hex, nudged louder so a dense table resolves ---- */
  --o-line:    #303A42;   /* divider inside a panel (~1.32:1) */
  --o-line-2:  #414C55;   /* panel edge / strongest horizontal (~1.74:1) */
  --o-edge-hi: rgba(255, 255, 255, 0.05); /* top-lit hairline; the real 3608 */

  /* ---- ink: 4 steps — the missing MID tier added so hierarchy isn't
     carried by colour alone. Contrast on --o-panel. ---- */
  --o-text:    #FFFFFF;   /* 15.3:1 — primary */
  --o-strong:  #DDE3E7;   /* 11.8:1 — NEW: headings, emphasized, 2nd table col */
  --o-dim:     #AEB8BF;   /* 7.6:1  — body/secondary (bluer, off the steel) */
  --o-faint:   #8B959C;   /* 5.0:1  — metadata + UPPERCASE micro-labels ONLY */

  /* ---- accent: GREEN is now the brand accent WITH a text-layer presence;
     steel demoted to structural marks and separated from body gray by HUE. */
  --o-accent-deep:  #3C8F45;  /* green FILL; dark label var(--o-bg) = 4.83:1 AA */
  --o-accent-hi:    #46A050;  /* hover — BRIGHTER (5.95:1): energizes, not recedes */
  --o-accent-press: #327C3B;  /* active/pressed */
  --o-green-ink:    #7BD98A;  /* NEW green as INK (8.8:1): active nav, links, good, hero */
  --o-green-wash:   rgba(60, 143, 69, 0.15);   /* active-nav bg, good chips */
  --o-accent:       #9DB2C0;  /* STEEL — marks/rings/neutral series/monogram, not text */
  --o-accent-wash:  rgba(157, 178, 192, 0.12);

  /* ---- status: two-tone MARK + INK, extended to red (was ad-hoc #8f3a2a) ---- */
  --o-warn:     #C4772F;  --o-warn-ink: #E8A87C;  --o-warn-bg: #1A1008;
  --o-bad:      #B4462F;  --o-bad-ink:  #E8927C;  --o-bad-bg:  #1A0C08;
  --o-neutral:  #6E7A82;
  --o-link:     #6CB6FF;  --o-link-hi:  #A8D6FF;
  --o-focus:    #46A050;  /* ONE on-palette ring — retires the orphan mint */

  /* ---- type: same fixed desk ramp (sound numbers); wire the dead --o-num
     to Archivo with lining+tabular figures for COLUMN numerals. ---- */
  --o-t-xs:  0.6875rem;  --o-t-sm:  0.8125rem;  --o-t-md: 0.875rem;
  --o-t-lg:  1rem;       --o-t-xl:  1.25rem;    --o-t-title: 1.75rem;
  --o-t-num: 2rem;       --o-t-hero: 3.25rem;
  --o-num:   'Archivo', 'Helvetica Neue', Arial, sans-serif;

  /* ---- geometry: machined square identity preserved (do NOT bubble to 12px);
     --o-pill reserved for counts/badges/monograms/dots only. ---- */
  --o-r-sm: 3px;  --o-r: 4px;  --o-r-lg: 6px;  --o-pill: 999px;
  --o-rail-w: 15.5rem;

  /* ---- NEW: a real 4px spacing scale (was only --o-pad + --o-rail-w) ---- */
  --o-s1: 4px;  --o-s2: 8px;  --o-s3: 12px; --o-s4: 16px;
  --o-s5: 20px; --o-s6: 24px; --o-s7: 32px; --o-s8: 48px;
  --o-pad:       1.25rem;   /* 20px — comfortable card padding */
  --o-pad-dense: 0.75rem;   /* 12px — sparse/one-line/tool cards */
  --o-pad-lg:    1.5rem;    /* 24px — primary content card */

  /* ---- NEW: elevation. Flat surfaces stay shadowless (owner ruling); the
     top-lit hairline is the only "lift" a resting card gets. Real shadow is
     reserved for layers that genuinely FLOAT. ---- */
  --o-e1: inset 0 1px 0 var(--o-edge-hi);                 /* cards, stat band, buttons */
  --o-e2: 0 2px 8px rgba(0, 0, 0, 0.5);                   /* dropdown, popover, drag */
  --o-e3: 0 14px 40px rgba(0, 0, 0, 0.6);                 /* modal, drawer, palette */
  --o-focus-glow: 0 0 0 3px rgba(70, 160, 80, 0.30);      /* the one focus glow */
}


/* ==========================================================================
   2 · TYPOGRAPHY — the SIZE + WEIGHT + INK hierarchy the audit found missing:
   eyebrow -> title -> section -> card -> body -> caption -> table -> micro-
   label -> figures. Selectors match the live rules and meet/exceed their
   specificity so later source order wins. Tokens only.
   ========================================================================== */

/* ---- EYEBROW / CRUMB (live :is() rule at office.css:3593) ----------------
   Green kicker announces the section, above a heavier title. */
:is(#office, #owner, #portal) .ofc-top__where p {
  font-family: var(--display);
  font-size: var(--o-t-xs);
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--o-green-ink);
}

/* ---- VIEW TITLE (live :is() rule at office.css:3577) ---------------------
   The one apex per screen. 900 on the dashboard home (#office gets data-view
   via JS) for a single true masthead. */
:is(#office, #owner, #portal) .ofc-top__where h1 {
  font-family: var(--display);
  font-size: var(--o-t-title);
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.1;
  color: var(--o-text);
}
#office[data-view="dashboard"] .ofc-top__where h1 { font-weight: 900; }

/* ---- SECTION HEADING (populate the empty --o-t-xl tier) ------------------
   Analytics panel heads ("The numbers", "The chat funnel") were 16px = same as
   a card title -> flat equal stack. Promote to the 20px section tier so a group
   of cards reads as a section, not another card. (Canonical rule — the data
   group's shorter .ofc-anl__title restatement is folded in here.) */
:is(#office, #owner, #portal) .ofc-anl__title {
  font-family: var(--display);
  font-size: var(--o-t-xl);
  font-weight: 700;
  letter-spacing: -0.012em;
  line-height: 1.15;
  color: var(--o-text);
}

/* ---- CARD TITLE (one canonical rule; folds the raw 17px onto --o-t-lg) ----
   Retires the stale 16px .ofc-card h2 and the raw 1.0625rem. --o-strong (not
   white) so the card head sits one ink step under the view title. */
:is(#office, #owner, #portal) .ofc-card > h2,
:is(#office, #owner, #portal) .ofc-card > h3,
:is(#office, #owner, #portal) .ofc-card__t,
:is(#office, #owner, #portal) .ofc-card__bar h2,
:is(#office, #owner, #portal) .ofc-card__bar h3,
:is(#office, #owner, #portal) .ofc-card h2 {
  font-family: var(--display);
  font-size: var(--o-t-lg);
  font-weight: 700;
  letter-spacing: -0.012em;
  color: var(--o-strong);
  margin: 0 0 0.15rem;
}

/* ---- CARD CAPTION -------------------------------------------------------
   Was four recessive treatments stacked (11px + 400 + --o-faint + opacity .86,
   which silently broke AA). Now one: 13px / --o-dim, full opacity. */
:is(#office, #owner, #portal) .ofc-sub {
  font-size: var(--o-t-sm);
  font-weight: 400;
  line-height: 1.5;
  color: var(--o-dim);
  opacity: 1;
}

/* ---- BODY / READING (mail body) ----------------------------------------
   Finally populates the real 14px reading tier: a stranger's text at reading
   size, comfortable leading, generous measure (kept from the original). */
:is(#office, #owner, #portal) .ofc-mail__body {
  font-family: var(--body);
  font-size: var(--o-t-md);
  font-weight: 400;
  line-height: 1.6;
  color: var(--o-dim);
}

/* ---- MAIL DETAIL ENTRY POINT -------------------------------------------
   The opened subject was 16px/700 (same as a card head). It is the confident
   entry point you navigated in to read. (Canonical — the data group's shorter
   restatement is folded in here; the read-list who/what hierarchy lives in the
   DATA section where it is correctly scoped to read rows only.) */
:is(#office, #owner, #portal) .ofc-mail__h {
  font-family: var(--display);
  font-size: var(--o-t-xl);
  font-weight: 800;
  letter-spacing: -0.015em;
  line-height: 1.15;
  color: var(--o-text);
}

/* ---- COLUMN FIGURES -----------------------------------------------------
   Wire the (previously dead) --o-num token to Archivo with tabular + lining
   figures so money/counts line up under each other. Pure font — no colour, so
   it never fights the td ink / state semantics in the DATA section. */
:is(#office, #owner, #portal) .ofc-table td.num,
:is(#office, #owner, #portal) .ofc-table th.num,
:is(#office, #owner, #portal) .ofc-lines td.num,
:is(#office, #owner, #portal) .ofc-lines th.num,
:is(#office, #owner, #portal) .ofc-table td[data-num],
:is(#office, #owner, #portal) .ofc-lines td[data-num],
:is(#office, #owner, #portal) .ofc-board__money {
  font-family: var(--o-num);
  font-variant-numeric: tabular-nums;
  font-feature-settings: 'tnum' 1, 'lnum' 1;
}

/* ---- MICRO-LABEL REGISTER (metadata tier) ------------------------------
   The uppercase Archivo register for PURE metadata stays --o-faint. The
   STRUCTURAL members of this register (table th, rail group, board head) are
   lifted to --o-strong and defined in their own component sections (DATA /
   NAV) so surface + border live with them. */
:is(#office, #owner, #portal) .ofc-stat__k {
  font-family: var(--display);
  font-size: var(--o-t-xs);
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--o-faint);
}
:is(#office, #owner, #portal) .ofc-anl__trendlbl {
  font-family: var(--display);
  font-size: var(--o-t-xs);
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--o-faint);
}

/* ---- STAT NUMBER -------------------------------------------------------
   Archivo 800, PROPORTIONAL (undoes the blanket tabular rule that overrode the
   intentional proportional setting). NB: no font-size/colour here on purpose,
   so the hero's 52px + warn-ink (specificity 0,2,0) survives. */
:is(#office, #owner, #portal) .ofc-stat__n {
  font-family: var(--display);
  font-weight: 800;
  letter-spacing: -0.03em;
  font-variant-numeric: proportional-nums;
  font-feature-settings: 'pnum' 1, 'lnum' 1;
}
/* The hero figure is the one type-driven focal point: green when clear. */
:is(#office, #owner, #portal) .ofc-stat--hero.is-clear .ofc-stat__n {
  color: var(--o-green-ink);
}


/* ==========================================================================
   3 · NAV — the sidebar (.ofc-side*, .ofc-rail*)
   Overrides office.css live rules 3517 (group header), 3533/3543/3547 (item +
   active), 3556/3685 (active icon), 3681 (dead green fill), .ofc-i (:450) and
   .ofc-me__mark (:502). Green finally marks "you are here"; the IA spine is
   FELT; daily-driver items carry more weight. Zero geometry shift on state.
   ========================================================================== */

/* ---- GROUP HEADERS: the section spine, asserted not whispered ------------ */
:is(#office, #owner, #portal) .ofc-side__g {
  margin: 1.35rem 0 0.45rem;
  padding: 0 0.85rem 0.5rem;
  border-bottom: 1px solid var(--o-line);
  font-family: var(--display);
  font-size: var(--o-t-xs);          /* 11px */
  font-weight: 800;                  /* Archivo heavy — the untapped headroom */
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--o-strong);            /* was --o-faint: spine now felt */
}
:is(#office, #owner, #portal) .ofc-rail__nav > .ofc-side__g:first-child {
  margin-top: 0;
}

/* ---- ITEMS AT REST: lift off the wall of gray --------------------------- */
:is(#office, #owner, #portal) .ofc-side__a {
  position: relative;
  padding-inline-start: 1rem;
  border-radius: var(--o-r-sm);
  color: var(--o-dim);
  font-size: var(--o-t-sm);          /* 13px base */
  font-weight: 600;
}
:is(#office, #owner, #portal) .ofc-side__a .ofc-i {
  color: var(--o-dim);               /* was --o-faint */
  stroke-width: 1.75;                /* was 1.6 — more presence */
}

/* ---- DAILY-DRIVER RHYTHM: the Today group reads larger ------------------
   Pure-CSS group scoping, no markup change: bump every item after the first
   header, then reset items that follow a *second* header back to 13px, leaving
   only Today's three (Dashboard / Jobs / Crews) at 14px. */
:is(#office, #owner, #portal) .ofc-side__g:first-child ~ .ofc-side__a {
  font-size: var(--o-t-md);          /* 14px */
}
:is(#office, #owner, #portal) .ofc-side__g ~ .ofc-side__g ~ .ofc-side__a {
  font-size: var(--o-t-sm);          /* 13px — every group past Today */
}

/* ---- HOVER: unchanged behaviour, brighter icon -------------------------- */
:is(#office, #owner, #portal) .ofc-side__a:hover {
  background: var(--o-hover);
  color: var(--o-text);
}
:is(#office, #owner, #portal) .ofc-side__a:hover .ofc-i {
  color: var(--o-strong);
}

/* ---- ACTIVE: brand green finally marks the current section --------------
   Overrides the live steel-wash (3543) AND the dead green-fill-white (3681).
   Green wash + a green LEADING BAR + green icon + white label + heavy weight.
   Greyscale-safe (shape + weight, not colour alone), carries aria-current, and
   shifts ZERO geometry (bg/colour/::before only). */
:is(#office, #owner, #portal) .ofc-side__a.is-on {
  background: var(--o-green-wash);
  color: var(--o-text);
  font-weight: 700;
}
:is(#office, #owner, #portal) .ofc-side__a.is-on::before {
  content: '';
  position: absolute;
  inset-inline-start: 0;
  inset-block: 0.28rem;
  width: 3px;
  border-radius: var(--o-pill);
  background: var(--o-accent-hi);    /* brighter green edge, was steel */
}
:is(#office, #owner, #portal) .ofc-side__a.is-on .ofc-i {
  color: var(--o-green-ink);         /* beats 3685 white (1,3,0 > 0,3,0) */
}

/* ---- FOOT: retire the orphan mint on the monogram ----------------------
   .ofc-me__mark border was a hardcoded sage matching no token; fold it onto
   the line token (fill/ink already the steel monogram). */
:is(#office, #owner, #portal) .ofc-me__mark {
  border-color: var(--o-line-2);
}


/* ==========================================================================
   4 · BUTTONS — the 3-role taxonomy with real states, square radii, and the
   three real Inter weights (400/600/700). Selectors carry the :is() wrap to
   match the base rules' (1,1,0); source order breaks the tie.
   ========================================================================== */

/* --- PRIMARY: the one confident CTA. Green FILL, dark plate label (AA
   4.83:1 — do NOT flip to white), a machined top-lit bevel, no gradient. --- */
:is(#office, #owner, #portal) .ofc-primary {
  border-color: var(--o-accent-deep);
  background: var(--o-accent-deep);
  background-image: none;
  color: var(--o-bg);
  font-weight: 700;
  box-shadow: var(--o-e1);              /* the only lift a resting button gets */
}
:is(#office, #owner, #portal) .ofc-primary:hover:not(:disabled) {
  background-color: var(--o-accent-hi); /* brighter (5.95:1) — energizes */
  border-color: var(--o-accent-hi);
}
:is(#office, #owner, #portal) .ofc-primary:active:not(:disabled) {
  background-color: var(--o-accent-press);
  border-color: var(--o-accent-press);
  box-shadow: none;                     /* pressed sits flat */
  transform: none;
}
:is(#office, #owner, #portal) .ofc-primary:disabled {
  background: var(--o-inset);
  background-image: none;
  border-color: var(--o-line);
  color: var(--o-faint);
  box-shadow: none;
  cursor: default;
}

/* --- SECONDARY (.ofc-ghost): a real SURFACE, not a cardboard outline. --- */
:is(#office, #owner, #portal) .ofc-ghost {
  border-color: transparent;
  background: var(--o-raised);
  background-image: none;
  color: var(--o-text);
  box-shadow: var(--o-e1);
}
:is(#office, #owner, #portal) .ofc-ghost:hover:not(:disabled) {
  background: var(--o-high);
  color: var(--o-text);
}
:is(#office, #owner, #portal) .ofc-ghost:active:not(:disabled) {
  background: var(--o-high);
  box-shadow: none;
  transform: none;
}
:is(#office, #owner, #portal) .ofc-ghost:disabled { opacity: 0.5; cursor: default; }

/* DESTRUCTIVE-NEXT-CLICK: preserved two-tone mark+ink state on the ghost. */
:is(#office, #owner, #portal) .ofc-ghost.is-armed {
  border-color: var(--o-warn);
  background: var(--o-warn-bg);
  color: var(--o-warn-ink);
  box-shadow: none;
}

/* --- TERTIARY (.ofc-quiet): a legible text button, not disabled metadata. --- */
:is(#office, #owner, #portal) .ofc-quiet {
  color: var(--o-dim);
  font-size: var(--o-t-sm);
  font-weight: 600;
}
:is(#office, #owner, #portal) .ofc-quiet:hover:not(:disabled) {
  background: var(--o-hover);
  color: var(--o-text);
}
:is(#office, #owner, #portal) .ofc-quiet:active:not(:disabled) {
  background: var(--o-press);
  transform: none;
}
:is(#office, #owner, #portal) .ofc-quiet:disabled { opacity: 0.5; cursor: default; }

/* --- IN-CELL MINI BUTTON: square (kill the leftover pill), readable weight. --- */
:is(#office, #owner, #portal) button.ofc-mini {
  border-radius: var(--o-r);
  color: var(--o-text);
  font-weight: 600;
}
:is(#office, #owner, #portal) button.ofc-mini:hover:not(:disabled) {
  background: var(--o-raised);
  color: var(--o-text);
}
:is(#office, #owner, #portal) button.ofc-mini:disabled { opacity: 0.5; cursor: default; }
:is(#office, #owner, #portal) .ofc-mini:focus-visible {
  outline: 2px solid var(--o-focus);
  outline-offset: 2px;
  border-color: var(--o-focus);
  box-shadow: var(--o-focus-glow);
}

/* --- ONE on-palette FOCUS ring for every pressable, replacing the steel
   outline and the mint glow. Resting elevation carries through so the ring
   layers on top rather than erasing the bevel. --- */
:is(#office, #owner, #portal) .ofc-primary:focus-visible,
:is(#office, #owner, #portal) .ofc-ghost:focus-visible {
  outline: 2px solid var(--o-focus);
  outline-offset: 2px;
  box-shadow: var(--o-e1), var(--o-focus-glow);
}
:is(#office, #owner, #portal) .ofc-quiet:focus-visible {
  outline: 2px solid var(--o-focus);
  outline-offset: 2px;
  box-shadow: var(--o-focus-glow);
}


/* ==========================================================================
   5 · TABS / SEGMENTED / FILTER TOGGLES — one language, replacing 5 idioms.
   Every selector carries :is(#office,#owner,#portal) so it beats the bare-class
   originals AND the id-wrapped .ofc-ghost base on source order. Selected = fill
   + GREEN INK + 2px green underline + weight 700 (greyscale-safe: colour +
   underline + weight), never white-on-green (the 3.33:1 fail).
   ========================================================================== */

/* --- the segmented TRACK: a squared inset well, not a 999px pill ---------- */
:is(#office, #owner, #portal) .ofc-anl__range {
  display: flex;
  gap: 2px;
  padding: 3px;
  background: var(--o-inset);
  border-radius: var(--o-r);            /* retire the 999px pill */
  box-shadow: var(--o-e1);              /* top-lit hairline, reads as recessed */
}

/* --- REST: transparent, dim label, 600, squared --------------------------- */
:is(#office, #owner, #portal) .ofc-anl__r,
:is(#office, #owner, #portal) .ofc-ph-filter__b,
:is(#office, #owner, #portal) .ofc-addr__b {
  border-radius: var(--o-r);
  background: transparent;
  color: var(--o-dim);
  font-weight: 600;
  box-shadow: none;
  transition: background-color .12s ease, color .12s ease, box-shadow .12s ease;
}
/* the two stand-alone filter chips keep their 1px box model but lose the drawn
   cage at rest — the underline, not an outline, marks selection */
:is(#office, #owner, #portal) .ofc-ph-filter__b,
:is(#office, #owner, #portal) .ofc-addr__b {
  border: 1px solid transparent;
}

/* --- HOVER (only when not selected): quiet lift + full-ink label ---------- */
:is(#office, #owner, #portal) .ofc-anl__r:hover:not(.is-on),
:is(#office, #owner, #portal) .ofc-ph-filter__b:hover:not(.is-on),
:is(#office, #owner, #portal) .ofc-addr__b:hover:not(.is-on):not([aria-pressed="true"]) {
  background: var(--o-hover);
  color: var(--o-text);
}

/* --- SELECTED: raised fill + green ink + 2px green underline + 700 -------- */
:is(#office, #owner, #portal) .ofc-anl__r.is-on,
:is(#office, #owner, #portal) .ofc-ph-filter__b.is-on,
:is(#office, #owner, #portal) .ofc-addr__b.is-on,
:is(#office, #owner, #portal) .ofc-addr__b[aria-pressed="true"],
:is(#office, #owner, #portal) .ofc-mail__tools .ofc-ghost.is-on {
  background: var(--o-raised);
  border-color: transparent;
  color: var(--o-green-ink);
  font-weight: 700;
  box-shadow: inset 0 -2px 0 var(--o-accent-hi);   /* the green bottom-rule */
}

/* counts inside a selected filter lift out of the faint tier (but stay
   neutral, not green) so they stay legible against the raised fill */
:is(#office, #owner, #portal) .ofc-addr__b.is-on b,
:is(#office, #owner, #portal) .ofc-addr__b.is-on .ofc-addr__n,
:is(#office, #owner, #portal) .ofc-addr__b[aria-pressed="true"] b,
:is(#office, #owner, #portal) .ofc-addr__b[aria-pressed="true"] .ofc-addr__n,
:is(#office, #owner, #portal) .ofc-ph-filter__b.is-on .ofc-ph-filter__n {
  color: var(--o-strong);
}

/* --- FOCUS: the one on-palette green ring, retiring the steel outline ----- */
:is(#office, #owner, #portal) .ofc-anl__r:focus-visible,
:is(#office, #owner, #portal) .ofc-ph-filter__b:focus-visible,
:is(#office, #owner, #portal) .ofc-addr__b:focus-visible,
:is(#office, #owner, #portal) .ofc-mail__tools .ofc-ghost.is-on:focus-visible {
  outline: 2px solid var(--o-focus);
  outline-offset: 2px;
}


/* ==========================================================================
   6 · SURFACES — cards / stats / panels
   Selectors match the :is(#office,...) form (1,1,0) so they beat both bare
   .ofc-card (0,1,0) and the live :is()-wrapped rules at 3608. Depth is fill +
   one top-lit hairline (--o-e1), never shadow on a flat card (owner ruling).
   ========================================================================== */

/* --- DEFAULT card: reads by FILL now (panel-on-ground ~1.30:1), so the cage
   drops to the QUIET line and the top-lit hairline supplies the only lift.
   Fixes the 3608 no-op (which set border-top to the colour it already was). */
:is(#office, #owner, #portal) .ofc-card {
  background: var(--o-panel);
  border: 1px solid var(--o-line);
  border-radius: var(--o-r-lg);
  box-shadow: var(--o-e1);
}

/* --- PRIMARY card (NEW class): the focal panel you opened the view for —
   earns the louder full edge and more air. One per view. */
:is(#office, #owner, #portal) .ofc-card--primary {
  border: 1px solid var(--o-line-2);
  padding: var(--o-pad-lg);
}

/* --- TOOL card (NEW class): a utility/form panel beside the content —
   recedes. No drawn box; separated by fill + spacing only, denser padding. */
:is(#office, #owner, #portal) .ofc-card--tool {
  background: var(--o-panel);
  border-color: transparent;
  box-shadow: none;
  padding: var(--o-pad-dense);
}

/* --- MUTED card: a note ABOUT the screen. Keep the dashed semantic marker,
   drop the lift, tighten padding so it recedes with the tool tier. */
:is(#office, #owner, #portal) .ofc-card--muted {
  border-style: dashed;
  border-color: var(--o-line);
  box-shadow: none;
  padding: var(--o-pad-dense);
}

/* --- GRID: let panels read by SPACE, not outlines — 16px gutter. */
:is(#office, #owner, #portal) .ofc-grid {
  gap: var(--o-s4);
}

/* --- STAT TILES: distinct OBJECTS, not one hairline-subdivided box.
   v2 (2026-09-15, from-pixels critique): the gap:1px band read as the exact
   "cardboard box cut into equal cells" the brief bans, and the hero did not
   dominate. Now each stat is its own tile with real gaps, a fill that reads on
   the darker ground, a squared edge and a top-lit hairline; the hero/lead tile
   is raised, spans two columns, carries a coloured left rule (amber = needs
   action, green = clear/neutral) and the big figure — one unmistakable focal
   point per band. */
:is(#office, #owner, #portal) .ofc-stats {
  background: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  overflow: visible;
  gap: 0.7rem;
}
:is(#office, #owner, #portal) .ofc-stat {
  background: var(--o-panel);
  border: 1px solid var(--o-line);
  border-radius: var(--o-r-lg);
  box-shadow: var(--o-e1);
  padding: 1.1rem 1.2rem 1.2rem;
  transition: border-color 0.15s, transform 0.15s, box-shadow 0.15s;
}
/* A stat that is itself a link lifts, so "clickable" reads without a border. */
:is(#office, #owner, #portal) a.ofc-stat:hover {
  border-color: var(--o-line-2);
  transform: translateY(-1px);
  box-shadow: var(--o-e1), var(--o-e2);
}

/* HERO (an alert metric) and LEAD (a neutral headline) are the focal tile:
   raised surface, two columns, a coloured left rule replacing the tiny dot. */
:is(#office, #owner, #portal) .ofc-stat--hero,
:is(#office, #owner, #portal) .ofc-stat--lead {
  grid-column: span 2;
  position: relative;
  background: var(--o-raised);
  border-color: var(--o-line-2);
  padding-left: 1.5rem;
}
:is(#office, #owner, #portal) .ofc-stat--hero::after,
:is(#office, #owner, #portal) .ofc-stat--lead::after {
  content: '';
  position: absolute;
  left: 0; top: 0.95rem; bottom: 0.95rem;
  width: 3px;
  border-radius: 0 2px 2px 0;
  background: var(--o-warn);              /* default hero = needs action */
}
:is(#office, #owner, #portal) .ofc-stat--hero.is-clear::after,
:is(#office, #owner, #portal) .ofc-stat--lead::after {
  background: var(--o-accent-deep);       /* clear, or a neutral lead = green rule */
}
/* the left rule is the signal now — retire the small dot to avoid double accent */
:is(#office, #owner, #portal) .ofc-stat--hero .ofc-stat__k::before,
:is(#office, #owner, #portal) .ofc-stat--lead .ofc-stat__k::before { display: none; }
/* a LEAD headline is neutral: strong white figure, not an amber alert */
:is(#office, #owner, #portal) .ofc-stat--lead .ofc-stat__n { color: var(--o-strong); }
:is(#office, #owner, #portal) .ofc-stat--lead .ofc-stat__k { color: var(--o-faint); }


/* ==========================================================================
   7 · DATA SURFACES — tables, CRM board, mailbox split, analytics
   Specificity is matched to each target: wrap in :is(#office,#owner,#portal)
   ONLY where the live rule is id-scoped (table th at 3632); otherwise stay
   UNWRAPPED so the existing state modifiers (td.is-missing, .is-unpriced,
   .is-hot, .is-unread, is-due, is-retired …) keep winning by their own
   specificity. This is the deliberate fix for the collision where an id-wrapped
   td ink rule would have clobbered those absence/warn semantics.
   ========================================================================== */

/* ---- TABLES: header = the strongest horizontal, not the faintest ----------
   MERGED here: the surface/border (was the data block) AND the uppercase
   register + --o-strong ink (was the typography block) in one th rule. Matches
   the id-scoped live rule at 3632 so it wins by source order. th.num/.is-num
   only set text-align, so no conflict. */
:is(#office, #owner, #portal) .ofc-table th,
:is(#office, #owner, #portal) .ofc-lines th {
  background: var(--o-inset);                 /* recessed band vs the card */
  border-bottom: 2px solid var(--o-line-2);   /* the wall, not one more hairline */
  font-family: var(--display);
  font-size: var(--o-t-xs);
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--o-strong);                     /* was --o-faint metadata */
}

/* First column = the record's identity; second = the key secondary field.
   Unwrapped + :not() guards so absence semantics and number columns are left
   intact, and so these don't outrank the state modifiers. */
.ofc-table td:first-child:not(.is-missing) {
  color: var(--o-strong);
  font-weight: 600;
}
.ofc-table td:nth-child(2):not(.is-missing):not(.num) {
  color: var(--o-strong);
}

/* Zebra to group a long record without drawing 20 boxes. v2 (cycle 3, from the
   populated Invoices table): 0.015 was imperceptible — on a wide financial row
   (NUMBER … OWING) the eye lost the line, so the striping did nothing. Raised to
   a real-but-quiet 0.04, and hover lifted clearly ABOVE the zebra (0.09, explicit
   not the shared --o-hover token) so a hovered row reads over an even row. */
.ofc-table tbody tr:nth-child(even) td,
.ofc-lines tbody tr:nth-child(even) td {
  background: rgba(255, 255, 255, 0.04);
}
.ofc-table tbody tr:hover td,
.ofc-lines tbody tr:hover td {
  background: rgba(255, 255, 255, 0.09);
  color: var(--o-text);
}

/* ---- CRM BOARD: keep the one place depth-by-fill is right; fix the cap -----
   MERGED: the darker sticky-cap surface (data block) + the confident Archivo
   label (register). Column head was a LIGHTER strip than the well it caps and
   the faintest ink in the column. is-hot (0,3,0) still wins its warn-ink. */
.ofc-board__h {
  background: var(--o-inset);
  color: var(--o-strong);
  font-family: var(--display);
  font-weight: 800;
}

/* The well->tile->hover fill ladder already carries the card, so the low-
   contrast 1px cage earns nothing. Drop it to transparent (width stays 1px so
   hover / is-due / role=button borders still render) and give the resting tile
   the one top-lit hairline instead. */
.ofc-board__card {
  border-color: transparent;
  box-shadow: var(--o-e1);
}

/* ---- MAILBOX: read rows get who-vs-what hierarchy; list is a well ----------
   Read rows ONLY (:not(.is-unread) is mutually exclusive with the unread rules
   at 1775-1778, so those are untouched — this is the correct scope; an
   id-wrapped generic .ofc-mail__from would have clobbered the unread state). */
.ofc-split__item:not(.is-unread) .ofc-mail__from {
  color: var(--o-strong);
  font-weight: 600;
}
.ofc-split__item:not(.is-unread) .ofc-mail__subj { color: var(--o-dim); }
.ofc-split__item:not(.is-unread) .ofc-mail__snip { color: var(--o-faint); }

/* The one status mark in a grey list finally pops: green, not steel. */
.ofc-mail__dot { background: var(--o-green-ink); }

/* Earn the two-pane split with a surface step, not one hairline: list recesses
   into a well, pane sits on the card plane. */
.ofc-split__list { background: var(--o-bg); }
.ofc-split__pane { background: var(--o-panel); }

/* ---- ANALYTICS: legible marks (title/range/trendlbl are owned by the
   typography + tabs sections; only the chart marks live here) --------------- */

/* Bars: square to match the machined identity; real red for the bad tone. */
.ofc-anl__bartrack { border-radius: var(--o-r-sm); }
.ofc-anl__barfill  { border-radius: var(--o-r-sm); }
.ofc-anl__barfill.is-bad { background: var(--o-bad); }

/* Lines/areas read as a 2px line over an 11%-steel wash you cannot see. Raise
   the good series to bright green ink + a thicker stroke; the good area uses
   the green wash so magnitude has a fill. */
.ofc-anl__area.is-good     { fill: var(--o-green-wash); }
.ofc-anl__linepath         { stroke-width: 2.5; }
.ofc-anl__linepath.is-good { stroke: var(--o-green-ink); }

/* Convo tiers onto tokens (were ad-hoc mint/salmon hexes): the two-tone
   mark+ink families, extended to red. */
.ofc-anl__tier.is-corpus  { background: var(--o-green-wash); color: var(--o-green-ink); }
.ofc-anl__tier.is-refused { background: var(--o-bad-bg);     color: var(--o-bad-ink); }
.ofc-anl__unans           { color: var(--o-bad-ink); }
.ofc-anl__search:focus-visible { outline-color: var(--o-focus); }

/* ==========================================================================
   8 · CRM BOARD (cycle 2, 2026-09-15, from-pixels) — the priority column must
   SHOUT, the wells must recede, the count reads as a chip. The board is the
   heart of the CRM and "Not replied yet" is the one column that costs money
   while it sits — it had a 0.34-opacity border nobody sees. Now it is an
   amber-walled lane you cannot miss, even empty.
   ========================================================================== */
/* Wells recede: the recessed fill carries them, so drop the heavy ring to a
   hairline and give the column a touch more air. */
:is(#office, #owner, #portal) .ofc-board__col {
  border-color: var(--o-line);
  padding: 0.6rem 0.55rem;
  gap: 0.45rem;
}
/* THE COLUMN THAT COSTS MONEY WHILE YOU READ IT — unmistakable. */
:is(#office, #owner, #portal) .ofc-board__col.is-hot {
  border-color: var(--o-warn);
  background: var(--o-warn-bg);
  box-shadow: inset 0 2px 0 var(--o-warn);
}
:is(#office, #owner, #portal) .ofc-board__col.is-hot .ofc-board__h {
  background: transparent;
  color: var(--o-warn-ink);
}
/* The per-column count is a chip, not a loose number (2nd span = count; the
   money total carries its own .ofc-board__hv class and is untouched). */
:is(#office, #owner, #portal) .ofc-board__h > span:nth-of-type(2) {
  min-width: 1.45rem;
  padding: 0.06rem 0.42rem;
  border-radius: var(--o-pill);
  background: var(--o-raised);
  color: var(--o-dim);
  font-size: var(--o-t-xs);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  text-align: center;
}
:is(#office, #owner, #portal) .ofc-board__col.is-hot .ofc-board__h > span:nth-of-type(2) {
  background: var(--o-warn);
  color: var(--o-bg);
}

/* ==========================================================================
   9 · EMPTY STATES (cycle dash-design 1, 2026-09-15, from-pixels) — the detail
   pane's "Nothing open" was sad centred gray text that read as broken/dead on
   the CRM, mailbox, estimates, invoices and buying split views. A composed
   empty state instead: a squared steel emblem, a strong title, a quiet hint —
   intentional, not unfinished. CSS-only (no markup change): the container's
   own ::before draws the emblem; its <b>/<span> children carry the copy.
   ========================================================================== */
:is(#office, #owner, #portal) .ofc-split__empty {
  gap: 0.45rem;
  padding: 2rem;
  color: var(--o-faint);
}
:is(#office, #owner, #portal) .ofc-split__empty::before {
  content: '';
  width: 48px;
  height: 48px;
  margin: 0 auto 0.6rem;
  border-radius: var(--o-r-lg);
  background-color: var(--o-inset);
  background-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%239DB2C0'%20stroke-width='1.6'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M3%2013l3-8h12l3%208'/%3E%3Cpath%20d='M3%2013v5a1%201%200%200%200%201%201h16a1%201%200%200%200%201-1v-5'/%3E%3Cpath%20d='M3%2013h5l1.4%202h5.2l1.4-2h5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: center;
  background-size: 24px 24px;
  border: 1px solid var(--o-line-2);
  box-shadow: var(--o-e1);
}
:is(#office, #owner, #portal) .ofc-split__empty b {
  font-family: var(--display);
  font-weight: 700;
  font-size: var(--o-t-lg);
  letter-spacing: -0.01em;
  color: var(--o-strong);
}
:is(#office, #owner, #portal) .ofc-split__empty span {
  font-size: var(--o-t-sm);
  color: var(--o-faint);
}

/* Cycle dash-design 2 (2026-09-15): LIST empty-states. `li.ofc-board__empty` is
   the message a list shows when it has no rows — "Nothing matches that." (mailbox,
   catalogue, contracts, invoices, buying search), an empty inbox, a read error.
   It was cramped tiny left-aligned faint text that read as a broken row. Now a
   calm, centred, breathing message — intentional, not unfinished. Scoped to `li.`
   so the tiny column "none" (a <p>, in the CRM board) is deliberately untouched. */
:is(#office, #owner, #portal) li.ofc-board__empty {
  list-style: none;
  padding: 1.6rem 1rem;
  text-align: center;
  color: var(--o-faint);
  font-size: var(--o-t-sm);
}

/* Cycle dash-design 4 (2026-09-15, from the populated CRM board): the deal VALUE
   on a lead card (.ofc-board__v) was xs and inline with city/timeline — the one
   number that sizes an opportunity had no more weight than "Rocklin". Promote it
   to the card's scannable figure: Archivo, a step up in size, --o-strong. Kept
   NEUTRAL, not green — 6+ values on one board would flood the "green = action"
   signal; prominence comes from size+weight. Baseline-aligned row keeps the
   city/timeline sitting beside it. */
:is(#office, #owner, #portal) .ofc-board__v {
  font-family: var(--display);
  font-size: var(--o-t-md);
  font-weight: 800;
  letter-spacing: -0.02em;
  color: var(--o-strong);
}

/* Cycle dash-design 5 (2026-09-15, from the populated Catalogue): line-item
   tables (.ofc-lines — catalogue, estimate lines) put long, often-IDENTICAL
   explanations in a <td><small> (tax-treatment reasoning, price-age note).
   Unlike the .ofc-note cells these were never clamped, so every row ballooned
   into a paragraph and the SAME tax note repeated down the entire table — the
   "repetitive / wall of text" failure. Clamp the in-cell <small> to two lines
   and reveal the rest on row hover, exactly the restraint .ofc-table td .ofc-note
   already uses. Short subs (SKU, "per ton", dates) are one line and untouched. */
:is(#office, #owner, #portal) .ofc-lines td small {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  max-width: 22rem;
}
:is(#office, #owner, #portal) .ofc-lines tbody tr:hover td small {
  -webkit-line-clamp: unset;
  overflow: visible;
}

/* Cycle dash-design 6 (2026-09-15, from the populated Calls & texts): every row
   in the phone log carried an "Incoming"/"Outgoing" chip drawn as the SAME thin
   outlined box as the "Missed" chip — so the one chip that actually owes someone
   a callback had no more visual weight than the direction metadata that repeats
   on every single row. And is-in leaned on var(--o-accent), which the theme
   redefined from green to STEEL, so "Incoming" read as a generic grey outline
   with no directional sense at all — exactly the "generic badge" failure.
   Rethink as a two-tier chip language matching DZT's "amber = the one thing that
   needs a person" rule:
   - direction (in/out) drops the drawn cage and becomes quiet borderless
     metadata with a directional glyph (down = arriving, up = leaving); it
     recedes so a scanning eye skips past it;
   - Missed keeps an amber FILL and now stands ALONE as the only loud chip in the
     log, so a scan down a long day lands straight on the calls still owed a
     callback. */
:is(#office, #owner, #portal) .ofc-ph__tag {
  display: inline-flex;
  align-items: center;
  gap: 0.3em;
  border: 0;
  border-radius: var(--o-r-sm);
  padding: 0.12em 0.4em;
  background: transparent;
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--o-faint);
  white-space: nowrap;
}
:is(#office, #owner, #portal) .ofc-ph__tag::before {
  font-weight: 800;
  font-size: 0.92em;
  line-height: 1;
}
/* incoming: arriving to us — down glyph, steel mark, dim label (one tier up from
   outgoing, since an inbound is the side that may still be owed a reply) */
:is(#office, #owner, #portal) .ofc-ph__tag.is-in {
  color: var(--o-dim);
}
:is(#office, #owner, #portal) .ofc-ph__tag.is-in::before {
  content: "\2193";                 /* down = arriving */
  color: var(--o-accent);
}
/* outgoing: leaving us — up glyph, faintest tier, recedes most */
:is(#office, #owner, #portal) .ofc-ph__tag.is-out::before {
  content: "\2191";                 /* up = leaving */
  color: var(--o-faint);
}
/* MISSED: the earned attention chip — amber fill + amber ink + a no-answer mark.
   The only filled chip in the log; direction chips beside it are plain metadata,
   so this is the shape the eye finds first. */
:is(#office, #owner, #portal) .ofc-ph__tag.is-missed {
  padding: 0.12em 0.5em 0.12em 0.42em;
  background: var(--o-warn-bg);
  color: var(--o-warn-ink);
  border: 1px solid color-mix(in srgb, var(--o-warn) 55%, transparent);
}
:is(#office, #owner, #portal) .ofc-ph__tag.is-missed::before {
  content: "\2715";                 /* × = no answer */
  color: var(--o-warn-ink);
}

/* Cycle dash-design 6b (2026-09-15, same Calls & texts screen, the log below the
   queue): a per-number call sliver reads "☎ They called you 1× · 1 missed", and
   the "· N missed" — the ONE part that means a call went unanswered and is still
   owed a callback — sat at xs size / weight 600 in warn-ink, so on a scan down a
   day of calls it disappeared into the same faint caption as "They called you".
   Promote it to a real amber attention flag (brighter ink, uppercase, a nudge
   larger, 700) so the same "amber = the one thing that needs a person" signal
   that the queue's Missed chip carries also fires here. The " · " separator is
   baked into the span's text, so this strengthens inline rather than pill-wrapping
   it (which would trap the middot inside the fill). */
:is(#office, #owner, #portal) .ofc-ph__callmiss {
  font-weight: 700;
  font-size: 0.92em;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--o-warn-ink);
}
