/* ==========================================================================
   Tantra Control Panel - design system
   ==========================================================================

   One stylesheet, no build step, no framework. Replaces the 285-line inline
   <style> block that used to live in base.html.

   Three rules this file is built on:

   1. Colour is defined ONCE, as a token, on bare :root. Nothing here defines a
      colour only inside a media query, so adding a dark theme later is a token
      swap rather than a rewrite.

   2. Every text token clears 4.5:1 against the WORST background it can land on
      (the tinted canvas, not white). There is deliberately no third faint text
      tier: on a #F4F5F8 canvas the candidate measured 4.46:1, and shipping a
      near-miss is how BlueOneHR v3 ended up with failing labels on every form.
      --ink-decor is for NON-TEXT use only and is named so.

   3. Status is a vocabulary, not a colour. Every status has four possible
      readings - good, attention, bad and UNKNOWN - because a control plane that
      renders "never measured" the same as "measured and fine" reports
      confidence it does not have.
   ========================================================================== */

/* ── Typeface ─────────────────────────────────────────────────────────────
   Bundled, not linked. The Dockerfile already fetches Chart.js locally so the
   console works behind a strict firewall; a webfont CDN would undo that. */

/* The logotype face: Mukta, subset to the five codepoints of तंत्र with its
   layout features kept so the त्र conjunct still forms. 3.6 KB, down from the
   105 KB full face. Used ONLY for the wordmark, never for interface text. */
@font-face{font-family:'Tantra Deva';font-style:normal;font-weight:700;font-display:swap;src:url("../fonts/dv-tantra-700.f46b8dfad867.woff2") format('woff2')}
@font-face{font-family:'JetBrains Mono';font-style:normal;font-weight:400;font-display:swap;src:url("../fonts/jbm-400.0062bf1cab80.woff2") format('woff2')}

/* ── Tokens ──────────────────────────────────────────────────────────────── */

:root{
  /* Chrome. Graphite rather than navy, so the platform layer reads as distinct
     from BlueOneHR (#0D2545) rather than as a shade of it. */
  --chrome:        #12141C;
  --chrome-raised: #1B1E28;
  --chrome-line:   #262A36;
  --chrome-ink:    #FFFFFF;   /* 18.38:1 */
  --chrome-ink-2:  #A8AEBF;   /*  8.29:1 */
  --chrome-ink-3:  #8A90A3;   /*  5.78:1 - group labels */

  /* Surfaces */
  --canvas:   #F4F5F8;
  --surface:  #FFFFFF;
  --surface-2:#FAFBFC;
  --line:     #E2E5EC;
  --line-soft:#EEF0F4;

  /* Text. Worst-case background is --canvas. */
  --ink:       #14161F;   /* 16.54:1 */
  --ink-2:     #3A3F4E;   /*  9.63:1 */
  --ink-3:     #5C6273;   /*  5.58:1 - lowest permissible TEXT tier */
  --ink-decor: #A6ABBA;   /*  2.29:1 - NEVER text. Dividers, icon strokes, disabled glyphs. */

  /* Brand accent. Violet sits outside the status ramp on purpose: a brand
     colour that doubles as "info" makes every status read ambiguously. */
  --accent:       #5B3FD9;   /* white on it: 6.65:1 */
  --accent-ink:   #4A31B5;   /* accent text on accent tint: 7.38:1 */
  --accent-tint:  #EDE9FE;
  --accent-line:  #DDD5FB;
  --accent-bright:#9B85FF;   /* on chrome: 6.30:1 */

  /* Status ramp. Foreground / tint pairs, each verified >= 4.5:1. */
  --ok:      #0B5F30;  --ok-tint:      #E3F5EA;  --ok-line:      #BFE6CE;
  --warn:    #6E4700;  --warn-tint:    #FBF0DC;  --warn-line:    #EFD9AE;
  --bad:     #96201A;  --bad-tint:     #FCE8E7;  --bad-line:     #F3C9C6;
  --busy:    #1A4E9E;  --busy-tint:    #E5EEFB;  --busy-line:    #C6DAF6;
  --unknown: #4A5060;  --unknown-tint: #EDEEF2;  --unknown-line: #DCDFE6;

  /* Space. Dense-dashboard scale. */
  --s1:4px; --s2:8px; --s3:12px; --s4:16px; --s5:24px; --s6:32px; --s7:48px;

  --r1:5px; --r2:8px; --r3:12px;

  --shadow-1: 0 1px 2px rgba(18,20,28,.05);
  --shadow-2: 0 4px 14px rgba(18,20,28,.09);
  --shadow-3: 0 16px 44px rgba(18,20,28,.16);

  --sidebar-w: 244px;
  --topbar-h:  56px;
  --mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  --font-deva: 'Tantra Deva', 'Mukta', 'Noto Sans Devanagari', sans-serif;
  --sans:'Instrument Sans',system-ui,sans-serif;
  --serif:'Instrument Serif',Georgia,serif;
}

/* ── Reset ───────────────────────────────────────────────────────────────── */

*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
html{-webkit-text-size-adjust:100%}
body{
  font-family:var(--sans);
  font-size:14px;
  line-height:1.5;
  color:var(--ink);
  background:var(--canvas);
  -webkit-font-smoothing:antialiased;
}
a{color:var(--accent);text-decoration:none}
a:hover{text-decoration:underline}
button,input,select,textarea{font:inherit;color:inherit}
button{cursor:pointer}
:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:3px}

/* ══════════════════════════════════════════════════════════════════════════
   APPLICATION SHELL
   ══════════════════════════════════════════════════════════════════════════ */

.app{display:grid;grid-template-columns:var(--sidebar-w) 1fr;min-height:100vh;min-height:100dvh}

/* ── Main column ─────────────────────────────────────────────────────────── */

.main{display:flex;flex-direction:column;min-width:0}

/* ── Page ────────────────────────────────────────────────────────────────── */

.page{padding:var(--s5);max-width:1560px;width:100%;flex:1 1 auto}
.crumbs .sep{color:var(--ink-decor)}

/* ── Buttons ─────────────────────────────────────────────────────────────── */

.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:6px;
  padding:7px 14px;border-radius:var(--r2);border:1px solid transparent;
  font-size:13px;font-weight:600;white-space:nowrap;text-decoration:none;
  transition:background .13s,border-color .13s,color .13s;
  min-height:34px;
}
.btn:hover{text-decoration:none}
.btn svg{width:15px;height:15px}
.btn--quiet{background:transparent;color:var(--ink-3)}
.btn--quiet:hover{background:var(--canvas);color:var(--ink-2)}
.btn--sm{padding:4px 10px;min-height:28px;font-size:12px}
.btn[disabled],.btn.is-disabled{opacity:.45;pointer-events:none}

/* ── Filter bar ──────────────────────────────────────────────────────────── */

.filters{
  display:flex;align-items:center;gap:var(--s2);flex-wrap:wrap;
  padding:var(--s3) var(--s5);border-bottom:1px solid var(--line-soft);
  background:var(--surface-2);border-radius:var(--r3) var(--r3) 0 0;
}
/* The global input rule sets width:100%, which inside a horizontal filter bar
   makes every select span the card and stacks the row. Controls here size to
   their content. */
.filters select{width:auto;min-width:130px;flex:0 0 auto}
.filters .btn{flex:0 0 auto}
.field label,.lbl{font-size:12px;font-weight:600;color:var(--ink-2)}
input[type=text],input[type=search],input[type=email],input[type=number],
input[type=password],input[type=date],select,textarea{
  width:100%;background:var(--surface);
  border:1px solid var(--line);border-radius:var(--r2);
  padding:7px 11px;font-size:13px;color:var(--ink);
  min-height:34px;transition:border-color .13s,box-shadow .13s;
}
input:hover,select:hover{border-color:var(--ink-decor)}
input:focus,select:focus,textarea:focus{
  outline:none;border-color:var(--accent);
  box-shadow:0 0 0 3px rgba(91,63,217,.13);
}
select{cursor:pointer;padding-right:28px;appearance:none;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2.5 4.5L6 8l3.5-3.5' fill='none' stroke='%235C6273' stroke-width='1.5' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 9px center;background-size:12px;
}
table.tbl{width:100%;border-collapse:collapse}
.tbl th{
  background:var(--surface-2);color:var(--ink-3);
  font-size:10.5px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;
  padding:9px var(--s4);text-align:left;white-space:nowrap;
  border-bottom:1px solid var(--line);
}
.tbl td{
  padding:11px var(--s4);border-bottom:1px solid var(--line-soft);
  vertical-align:middle;font-size:13px;
}
.tbl tbody tr:last-child td{border-bottom:0}
.tbl tbody tr:hover td{background:var(--surface-2)}
.tbl td .sub{display:block;font-size:11.5px;color:var(--ink-3);margin-top:1px}
.tbl a.strong{font-weight:600;color:var(--ink)}
.tbl a.strong:hover{color:var(--accent)}
.tbl td.right,.tbl th.right{text-align:right}

/* ── Definition rows ─────────────────────────────────────────────────────── */

.dl{display:grid;grid-template-columns:minmax(140px,190px) 1fr;gap:9px var(--s4)}
.dl dt{font-size:12px;font-weight:600;color:var(--ink-3)}
.dl dd{font-size:13px;color:var(--ink)}

/* ── Tabs ────────────────────────────────────────────────────────────────── */

.tabs{display:flex;gap:2px;border-bottom:1px solid var(--line);margin-bottom:var(--s5);overflow-x:auto}
.tabs a{
  padding:9px var(--s4);font-size:13px;font-weight:600;color:var(--ink-3);
  border-bottom:2px solid transparent;margin-bottom:-1px;white-space:nowrap;
}
.tabs a:hover{color:var(--ink-2);text-decoration:none}
.tabs a.is-active{color:var(--accent);border-bottom-color:var(--accent)}

/* ── Empty / error states ────────────────────────────────────────────────── */

.blank{
  text-align:center;padding:var(--s7) var(--s5);color:var(--ink-3);
  display:flex;flex-direction:column;align-items:center;gap:var(--s2);
}
.blank h3{font-size:14px;font-weight:700;color:var(--ink-2)}
.blank p{font-size:13px;max-width:44ch;line-height:1.55}

/* ── Messages ────────────────────────────────────────────────────────────── */
/* Django emits success / error / warning / info / debug. The previous
   stylesheet styled the first three, so an info message rendered as unstyled
   black text. All five are covered here. */

.msgs{display:flex;flex-direction:column;gap:var(--s2);margin-bottom:var(--s4)}
.msg{
  display:flex;align-items:flex-start;gap:9px;
  padding:10px var(--s4);border-radius:var(--r2);font-size:13px;
  border:1px solid transparent;
}
.msg--success{color:var(--ok);   background:var(--ok-tint);   border-color:var(--ok-line)}
.msg--error  {color:var(--bad);  background:var(--bad-tint);  border-color:var(--bad-line)}
.msg--warning{color:var(--warn); background:var(--warn-tint); border-color:var(--warn-line)}
.msg--info   {color:var(--busy); background:var(--busy-tint); border-color:var(--busy-line)}
.msg--debug  {color:var(--unknown);background:var(--unknown-tint);border-color:var(--unknown-line)}

/* ── Code ────────────────────────────────────────────────────────────────── */

.code{
  background:var(--chrome);color:#E4E6EE;font-family:var(--mono);
  font-size:12px;padding:var(--s4);border-radius:var(--r2);
  overflow-x:auto;white-space:pre;line-height:1.65;
}

/* ── Utilities ───────────────────────────────────────────────────────────── */

.muted{color:var(--ink-3)}

/* ── Responsive ──────────────────────────────────────────────────────────── */
/* Desktop first by intent, usable to tablet. Below 1080px the sidebar becomes
   a horizontal rail rather than shrinking; below 720px tables reflow to
   stacked records rather than being squeezed into a scrollbar. */

@media (max-width:1080px){
  .app{grid-template-columns:1fr}
}
@media (max-width:720px){
  .page{padding:var(--s4)}
  .tbl,.tbl tbody,.tbl tr,.tbl td{display:block;width:100%}
  .tbl thead{display:none}
  .tbl tr{
    border:1px solid var(--line);border-radius:var(--r2);
    margin:0 var(--s4) var(--s3);background:var(--surface);
  }
  .tbl td{
    border-bottom:1px solid var(--line-soft);
    display:flex;justify-content:space-between;gap:var(--s4);align-items:center;
    padding:9px var(--s3);
  }
  .tbl td::before{
    content:attr(data-th);font-size:10.5px;font-weight:700;letter-spacing:.08em;
    text-transform:uppercase;color:var(--ink-3);flex:0 0 auto;
  }
  .tbl td.right{text-align:left}
  .dl{grid-template-columns:1fr;gap:2px var(--s4)}
  .dl dd{margin-bottom:var(--s3)}
}

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{transition-duration:.01ms !important;animation-duration:.01ms !important}
}


/* ===========================================================================
   HYBRID CONTROL PLANE - the frozen design grammar
   ===========================================================================
   Rules:     TANTRA_CONTROL_PLANE_DESIGN_GRAMMAR.md   (frozen 2026-08-23)
   Plan:      TANTRA_IMPLEMENTATION_PLAN.md            (F1-F3, foundation)

   Every rule below is namespaced under .hcp. Nothing here can reach a template
   that has not been converted, so conversion proceeds one screen per commit
   rather than as one cutover. base.html and its fourteen pages are untouched.

   A screen joins the system by extending one of the three mode templates, each
   of which stamps its own root:

       <div class="hcp" data-mode="operator|entry|customer" data-d="calm|working|dense">

   Mode is architecture - which shell a screen extends. Density is a five-token
   switch. Both are asserted by the gate test rather than left to convention.
   =========================================================================== */

/* Bundled, not linked. The console must work behind a strict firewall, which is
   also why Chart.js and the Devanagari logotype subset live in the repository. */
@font-face{font-family:'Instrument Sans';font-style:normal;font-weight:400;font-display:swap;src:url("../fonts/is-400.64d7b23d069a.woff2") format('woff2')}
@font-face{font-family:'Instrument Sans';font-style:normal;font-weight:500;font-display:swap;src:url("../fonts/is-500.6a6919c7a327.woff2") format('woff2')}
@font-face{font-family:'Instrument Sans';font-style:normal;font-weight:600;font-display:swap;src:url("../fonts/is-600.244d3ce7dfd5.woff2") format('woff2')}
@font-face{font-family:'Instrument Sans';font-style:normal;font-weight:700;font-display:swap;src:url("../fonts/is-700.36aef1392b5e.woff2") format('woff2')}
@font-face{font-family:'Instrument Serif';font-style:normal;font-weight:400;font-display:swap;src:url("../fonts/iser-400.c9d1f8887330.woff2") format('woff2')}

.hcp *,.hcp *::before,.hcp *::after{box-sizing:border-box}
.hcp button{font:inherit;color:inherit;background:none;border:0;cursor:pointer;text-align:left}
.hcp a{color:inherit;text-decoration:none}
.hcp .sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
/* The logotype face was bundled in Phase 1 under a different family name than
   the prototype used; mapped rather than renamed, because legacy pages still
   reference the original declaration. */
.hcp .deva{font-family:var(--font-deva);font-weight:700}

/* -- isolation from the legacy sheet --------------------------------------
   Namespacing the RULES under .hcp does not protect the MARKUP. A legacy
   selector like `.row{display:flex}` contains no .hcp and reaches straight into
   a converted page: it turned every table row into a flex container, so the
   header and the body could not agree on a single column position.

   Measured rather than guessed, by diffing per class the properties the legacy
   section sets against the properties this section re-declares. These are the
   ones that were still leaking. Declared here, near the top, so a later rule in
   this section still wins.
   ------------------------------------------------------------------------- */
.hcp .page{max-width:none;width:auto}
.hcp .btn{padding:0 16px;min-height:0;border:0;gap:0;text-decoration:none;white-space:nowrap;
  transition:background .12s ease,color .12s ease,border-color .12s ease}
/* Legacy gives a button inside .filters a flex value, which made the one in the
   filter bar grow into the space the selects gave up. Found by the gate, not by
   looking. */
.hcp .filters .btn{flex:0 0 auto}
.hcp .btn[disabled]{opacity:.5;pointer-events:none}
.hcp .code{overflow-x:auto}
.hcp .dl dd{margin-bottom:0}
.hcp .filters select{min-width:0;width:auto}
/* Every legacy message variant carries its own border colour. The gate caught
   .msg--success the moment S8 used one; the rest are sealed now rather than one
   screen at a time. */
.hcp .msg--error,.hcp .msg--success,.hcp .msg--warning,
.hcp .msg--info,.hcp .msg--debug{border-color:transparent}
.hcp .tbl .sub{display:inline;margin-top:0}
.hcp .tbl tr{border:0;border-radius:0;margin:0}
.hcp .tabs{gap:0;margin-bottom:0}
/* ── tokens ─────────────────────────────────────────────────────────────── */
.hcp{
  --paper:#F7F6FA;        /* violet-biased paper, not default grey */
  --surface:#FFFFFF;
  --sunken:#EFEDF5;
  /* Measured, not chosen by eye. A divider still has to be visible on a
     mediocre panel; the previous value was 1.17:1 against paper. */
  --rule:#D2CFDE;         /* 1.42:1 on paper, 1.47:1 on surface */
  --rule-hard:#C7C4D6;    /* 1.71:1 on surface */
  --chrome:#141320;
  --chrome-2:#1F1D2E;
  --chrome-rule:#2A2840;

  --ink:#16151E;          /* 16.82:1 */
  --ink-2:#45435A;        /*  8.86:1 */
  /* --dim was carrying two jobs and 61% of all text on the audit log, at eight
     sizes and three weights, so metadata and secondary content read as one
     tone. It is now METADATA ONLY. Secondary content moved up to --ink-2. */
  --dim:#63607A;          /*  5.60:1. Metadata only: timestamps, labels, counts */
  /* Meaningful non-text graphics: the divergence arrow, the never-probed
     outline, the unknown marker. These carry information, so 3:1, not the
     2.14:1 they were. Still never used for text. */
  --decor:#8D8A9F;        /*  3.35:1 on surface */

  --accent:#5B3FD9;
  --accent-ink:#4A31B5;
  --accent-tint:#EDE9FE;
  --accent-bright:#A78BFA;

  --ok:#0B6B3C; --warn:#7A4E00; --bad:#9E1F19; --busy:#1A4E9E; --unk:#4F556A;
  --ok-t:#E4F4EA; --warn-t:#FBF1DD; --bad-t:#FBE9E8; --busy-t:#E7EFFC; --unk-t:#EEEDF3;


  /* The prototype declared this on body. Stripping the harness took the
     declaration with it -- correctly, since a body rule would have reached the
     fourteen legacy pages -- and nothing re-homed it, so four bundled weights
     sat unreferenced while the whole surface rendered in the legacy face.
     Found by the first shell that rendered. */
  font-family:var(--sans);
  -webkit-font-smoothing:antialiased;

  background:var(--paper);color:var(--ink);
}
/* The three densities. Five tokens, one system. */
.hcp[data-d="calm"]   {--row:46px;--pad:34px;--gap:26px;--fs:14.5px;--gut:30px}
.hcp[data-d="working"]{--row:38px;--pad:24px;--gap:18px;--fs:13.5px;--gut:24px}
.hcp[data-d="dense"]  {--row:31px;--pad:14px;--gap:12px;--fs:12.5px;--gut:20px}
.hcp{font-size:var(--fs)}
.mn{font-family:var(--mono);font-variant-numeric:tabular-nums}

/* -- canonical gutter primitive -------------------------------------------
   Approved 2026-08-23. The slot that holds a status marker had four names for
   one concept, three of which differed only in optical alignment against
   different type sizes.

   gut--table is the one STRUCTURAL variant, and the reason is recorded: a <td>
   cannot inherit a grid track, so the slot needs an explicit width where the
   grid contexts take the first var(--gut) column of their row.

   Naming normalisation only. No visual change; the frozen grammar is untouched.
   ------------------------------------------------------------------------- */
.hcp .gut{flex:0 0 auto}
.hcp .gut--table{width:var(--gut);padding-right:0 !important}
.hcp .gut--top{padding-top:4px}
.hcp .gut--center{align-self:center}

/* -- canonical status-shape primitive -------------------------------------
   One marker, one size, reduced only where the surface is genuinely smaller.
   Status is shape first, colour second, word third; the five shapes are drawn
   by the template partial that renders them, so there is one definition of
   each in the codebase.
   ------------------------------------------------------------------------- */
.hcp .mk{display:inline-block;width:11px;height:11px;flex:0 0 11px;vertical-align:-1px}
.hcp .pill .mk,.hcp .cellx .mk,.hcp .census i .mk{width:9px;height:9px;flex:0 0 9px}
.hcp .cellx.h-ok .mk{display:none}

/* -- mode, enforced in CSS as well as in templates -------------------------
   Grammar 12. Entry and Customer cannot show operator chrome even if a template
   mistakenly includes it. Defence in depth beside the gate test, not a
   substitute for it.
   ------------------------------------------------------------------------- */
.hcp[data-mode="entry"] .nav,   .hcp[data-mode="entry"] .bar,
.hcp[data-mode="entry"] .crumb, .hcp[data-mode="entry"] .prod,
.hcp[data-mode="entry"] .cmdb,  .hcp[data-mode="entry"] .drawer,
.hcp[data-mode="entry"] .pal,
.hcp[data-mode="customer"] .nav,   .hcp[data-mode="customer"] .bar,
.hcp[data-mode="customer"] .crumb, .hcp[data-mode="customer"] .prod,
.hcp[data-mode="customer"] .cmdb,  .hcp[data-mode="customer"] .drawer,
.hcp[data-mode="customer"] .pal{display:none !important}

.tn{font-variant-numeric:tabular-nums}


/* ── shell ──────────────────────────────────────────────────────────────── */
.hcp .app{display:grid;grid-template-columns:240px 1fr;min-height:100vh;min-height:100dvh}

/* When a drawer opens on a dense surface the shell reclaims the navigation to
   an icon rail. The working surface is what the operator came for; 184px of
   nav labels is the cheapest thing on the screen to give up. */
.hcp .app--rail{grid-template-columns:60px 1fr}
.hcp .app--rail .nav__b{justify-content:center;padding:0}
.hcp .app--rail .ebrand__t,.hcp .app--rail .nav__g h5,
.hcp .app--rail .nl .lb,.hcp .app--rail .nl .ct,
.hcp .app--rail .nav__col .lb{display:none}
.hcp .app--rail .nl{justify-content:center;padding:9px 0;gap:0}
.hcp .app--rail .nl.on::before{left:0}
.hcp .nav{background:var(--chrome);color:#fff;display:flex;flex-direction:column;min-width:0;
  position:sticky;top:0;height:100vh;height:100dvh;overflow-y:auto;overscroll-behavior:contain}
.hcp .nav__b{display:flex;align-items:center;gap:10px;height:58px;padding:0 16px;border-bottom:1px solid var(--chrome-rule);flex:0 0 auto}
/* The brand was inline markup here and had its own two rules. It is now the
   shared .ebrand primitive, and those rules had become a trap: `.hcp .nav__b
   span` is one element more specific than `.hcp .ebrand`, so it silently set
   the brand block to display:block and stacked the mark above the wordmark.
   Fourth cascade collision in this project; source order and specificity are
   worth checking whenever two rules could describe the same element. */

/* Product context is part of the navigation surface, not a floating dropdown. */
/* -- product scope, in the LIGHT bar -------------------------------------
   Moved out of the dark rail on 2026-08-25. Dark navigates, light qualifies,
   and the two chromes are what carry that distinction; a scope control sitting
   among the destinations was asking the operator to tell them apart by noticing
   which one was a <details>.

   A popover at every width now. In the rail it was an open list because the
   list WAS the navigation surface. In the bar an open list hangs over the page.
   ------------------------------------------------------------------------- */
.hcp .prod{position:relative;flex:0 0 auto}
.hcp .prod__d{position:relative}
.hcp .prod__c{display:flex;align-items:center;gap:8px;height:30px;padding:0 9px;
  border:1px solid var(--rule);border-radius:8px;background:var(--paper);
  cursor:pointer;list-style:none;max-width:290px}
.hcp .prod__c::-webkit-details-marker{display:none}
.hcp .prod__c:hover{border-color:var(--rule-hard);background:var(--surface)}
.hcp .prod__d[open] .prod__c{border-color:var(--accent);background:var(--surface)}
/* The verb. It is the first word of the control and it is not a page name,
   which is the cheapest of the five things that say scope rather than
   destination. */
.hcp .prod__lbl{font-size:9px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--dim);font-weight:700;flex:0 0 auto}
.hcp .prod__now{display:flex;align-items:center;gap:7px;min-width:0;flex:1}
.hcp .prod__now b{font-size:12.5px;font-weight:600;color:var(--ink);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* The count of what is in scope. No destination carries one. */
.hcp .prod__now .n{font-size:11px;color:var(--dim);flex:0 0 auto;
  font-variant-numeric:tabular-nums}
.hcp .prod__chev{width:13px;height:13px;flex:0 0 13px;color:var(--decor);
  transition:transform .15s ease;margin-left:auto}
.hcp .prod__d[open] .prod__chev{transform:rotate(180deg)}
.hcp .prod__l{position:absolute;top:calc(100% + 6px);left:0;z-index:60;min-width:290px;
  background:var(--surface);border:1px solid var(--rule);border-radius:11px;padding:7px;
  box-shadow:0 18px 44px rgba(22,21,30,.16)}
/* The contract, stated where the choice is made. */
.hcp .prod__h{font-size:11.5px;color:var(--ink-2);line-height:1.5;padding:6px 9px 9px;
  margin:0;border-bottom:1px solid var(--rule);max-width:34ch}
.hcp .prod__l form{display:block}
.hcp .prod__l form:first-of-type{margin-top:5px}
.hcp .prod__i{display:flex;align-items:center;gap:9px;padding:6px 9px;border-radius:7px;
  width:100%;font-size:12.5px;color:var(--ink-2)}
.hcp .prod__i:hover{background:var(--sunken);color:var(--ink)}
.hcp .prod__i.on{background:var(--accent-tint);color:var(--accent-ink);font-weight:600}
.hcp .prod__i .n{margin-left:auto;font-size:11px;color:var(--dim);font-variant-numeric:tabular-nums}
.hcp .prod__i .dot{width:9px;height:9px;flex:0 0 9px;border-radius:50%;background:var(--decor)}
.hcp .prod__i.on .dot{background:var(--accent)}
.hcp .prod__c .dot{width:9px;height:9px;flex:0 0 9px;border-radius:50%;background:var(--decor)}
.hcp .prod__i.dev{color:var(--dim);cursor:not-allowed}
.hcp .prod__i.dev:hover{background:none;color:var(--dim)}
.hcp .prod__i.dev .n{font-size:8.5px;letter-spacing:.09em;text-transform:uppercase;font-weight:700}
.hcp .prod__i[aria-disabled="true"]{cursor:not-allowed}
.hcp .prod__empty{display:flex;align-items:center;gap:8px;height:30px;padding:0 9px;
  border:1px dashed var(--rule-hard);border-radius:8px;font-size:12px;color:var(--dim)}

/* -- the estate band ------------------------------------------------------
   Three figures, each with the denominator it was counted out of. A bare 3 is a
   boast; "3 of 14 answered a probe" is a measurement, and the denominator is
   the whole reason this band exists rather than a row of KPI cards.

   The figure slot is the serif; everything qualifying it is the interface face,
   which is the D1 contract doing its one job in the one place it matters most.
   ------------------------------------------------------------------------- */
.hcp .est{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--gap);
  margin-top:var(--gap)}
@media (max-width:900px){.hcp .est{grid-template-columns:minmax(0,1fr)}}
.hcp .est__c{border:1px solid var(--rule);border-radius:12px;padding:15px 17px 13px;
  background:var(--surface);display:flex;flex-direction:column;min-width:0}
.hcp .est__l{font-size:9px;letter-spacing:.15em;text-transform:uppercase;
  color:var(--dim);font-weight:700}
.hcp .est__n{display:flex;align-items:baseline;gap:10px;margin-top:6px;min-width:0}
.hcp .est__n .of{font-size:12.5px;color:var(--ink-2);line-height:1.4;
  font-family:var(--sans);letter-spacing:0}
.hcp .est__bar{display:flex;gap:2px;height:6px;margin-top:11px;border-radius:3px;
  overflow:hidden;background:var(--sunken)}
.hcp .est__bar i{display:block;height:100%}
.hcp .est__bar i.u{background:transparent;box-shadow:inset 0 0 0 1.2px var(--decor)}
.hcp .est__k{display:flex;flex-direction:column;gap:4px;margin-top:11px;font-size:12px}
.hcp .est__k > span{display:flex;align-items:center;gap:7px;color:var(--ink-2)}
.hcp .est__k .c{margin-left:auto;font-variant-numeric:tabular-nums;color:var(--ink)}

/* -- the commercial band --------------------------------------------------
   Where a figure would go and there is nothing to put in it, the slot says so
   in the slot. `None contracted` is not an empty state below a zero; it IS the
   figure, which is the second half of the figure-slot definition and the
   clearest case of it in the product.
   ------------------------------------------------------------------------- */
.hcp .comm{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  gap:var(--gap);margin-top:var(--gap)}
@media (max-width:900px){.hcp .comm{grid-template-columns:minmax(0,1fr)}}
.hcp .comm__c{border:1px solid var(--rule);border-radius:12px;padding:15px 17px 14px;
  background:var(--surface);min-width:0}
.hcp .comm__c p{font-size:12.5px;color:var(--ink-2);line-height:1.6;margin-top:9px;
  max-width:58ch}

/* -- activity, as days ----------------------------------------------------
   31 of the 40 entries on the restored estate are the same action. Ungrouped,
   the feed is thirty-one identical lines and the one thing that happened
   yesterday is below the fold.
   ------------------------------------------------------------------------- */
.hcp .day + .day{margin-top:var(--gap)}
.hcp .day__h{display:flex;align-items:baseline;gap:10px;padding:0 0 7px;
  border-bottom:1px solid var(--rule)}
.hcp .day__h b{font-size:12.5px;font-weight:700}
.hcp .day__h span{font-size:11.5px;color:var(--dim)}
/* FIVE columns, not four. The row carries a marker, a time, a title, what it
   touched and who did it, and declaring four put the fifth on a second grid row
   at the left margin: every actor sat under the time of the row above it,
   which reads as a stray line rather than as part of the entry. Seen in the
   browser, not in the markup, because the markup is five spans either way. */
.hcp .ev{display:grid;
  grid-template-columns:var(--gut) 56px minmax(0,1.1fr) minmax(0,1fr) auto;
  gap:0 12px;align-items:baseline;padding:8px 0;border-bottom:1px solid var(--rule)}
.hcp .ev:last-child{border-bottom:0}
.hcp .ev .t{font-family:var(--mono);font-size:11px;color:var(--dim)}
.hcp .ev .n{font-size:13px;font-weight:600;min-width:0;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
.hcp .ev .d{font-size:12px;color:var(--ink-2);min-width:0;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
.hcp .ev .x{font-size:11.5px;color:var(--dim);white-space:nowrap;text-align:right}
.hcp .ev .rep{font-variant-numeric:tabular-nums;color:var(--ink-2);font-weight:600}
@media (max-width:820px){
  .hcp .ev{grid-template-columns:var(--gut) minmax(0,1fr);row-gap:2px}
  .hcp .ev .t,.hcp .ev .d,.hcp .ev .x{grid-column:2}
  .hcp .ev .x{text-align:left}
}

/* -- what a record does not say -------------------------------------------
   Contract 5. A blank field looks like a rendering fault. A named gap with a
   stated cost looks like a record, and it is the half an operator can act on.
   ------------------------------------------------------------------------- */
.hcp .gaps{margin-top:var(--gap);padding-top:var(--gap);border-top:1px solid var(--rule)}
.hcp .gaps h3{font-size:13px;font-weight:700;letter-spacing:-.01em}
.hcp .gaps ul{list-style:none;padding:0;margin:11px 0 0;display:grid;gap:7px}
.hcp .gaps li{display:grid;grid-template-columns:var(--gut) minmax(0,auto) minmax(0,1fr);
  gap:0 10px;align-items:baseline;font-size:12.5px}
.hcp .gaps li b{font-weight:600;white-space:nowrap}
.hcp .gaps li span{color:var(--ink-2);line-height:1.5}
@media (max-width:700px){
  .hcp .gaps li{grid-template-columns:var(--gut) minmax(0,1fr);row-gap:1px}
  .hcp .gaps li span{grid-column:2}
}

/* -- a page the scope does not reach --------------------------------------
   Contract 3.4. Quieter than the confirmation band, because it is explaining an
   absence of effect rather than reporting one.
   ------------------------------------------------------------------------- */
.hcp .unscoped{display:flex;align-items:flex-start;gap:9px;margin-bottom:var(--gap);
  padding:9px 12px;border:1px dashed var(--rule-hard);border-radius:9px;
  background:var(--sunken);font-size:12.5px;color:var(--ink-2);line-height:1.5;
  max-width:78ch}
.hcp .unscoped .mk{margin-top:2px;flex:0 0 auto}

/* A footnote about what a scope EXCLUDED. Quieter than .unscoped: that
   explains a page, this explains a number.

   Not called .note--scope. It reads as a modifier of .note, which is
   declared later at higher specificity and would silently defeat it; the
   variant-override gate caught that on the way in. It is a different
   component, not a variant of that one, so it has its own name. */
.hcp .scopenote{display:flex;align-items:flex-start;gap:8px;margin-top:12px;
  font-size:12px;color:var(--dim);line-height:1.55;max-width:74ch}
.hcp .scopenote .mk{margin-top:2px;flex:0 0 auto}

/* -- the confirmation band -----------------------------------------------
   The panel CLAIMS that choosing a product does not navigate. This is where
   that claim is demonstrated, which is the only one of the five signals that is
   evidence rather than assertion.
   ------------------------------------------------------------------------- */
.hcp{--band-h:36px}
.hcp .scoped{display:flex;align-items:center;gap:9px;padding:8px var(--pad);min-height:var(--band-h);
  background:var(--accent-tint);border-bottom:1px solid var(--rule);
  font-size:12.5px;color:var(--accent-ink);flex:0 0 auto}
.hcp .scoped b{font-weight:700}
.hcp .scoped__x{margin-left:auto;font-size:11.5px;color:var(--accent-ink);
  text-decoration:underline;text-underline-offset:2px;white-space:nowrap}

.hcp .nav__g{padding:14px 10px 0;flex:0 0 auto}
.hcp .nav__g h5{font-size:9px;letter-spacing:.16em;text-transform:uppercase;color:#9C98B4;font-weight:700;padding:0 10px 6px}
.hcp .nav__g + .nav__g{padding-top:16px}
.hcp .nl{display:flex;align-items:center;gap:10px;padding:7px 10px;border-radius:7px;font-size:13px;color:#A5A2BC;position:relative}
.hcp .nl:hover{background:#262439;color:#fff}
.hcp .nl.on{background:var(--chrome-2);color:#fff;font-weight:600}
.hcp .nl.on::before{content:"";position:absolute;left:-10px;top:6px;bottom:6px;width:2.5px;border-radius:0 2px 2px 0;background:var(--accent-bright)}
.hcp .nl svg{width:15px;height:15px;flex:0 0 15px}
.hcp .nl .ct{margin-left:auto;font-size:10.5px;font-weight:700;font-variant-numeric:tabular-nums;color:#8B87A6}
.hcp .nl .ct.hot{color:#FF9C95}
.hcp .nav__f{padding:8px 10px;border-top:1px solid var(--chrome-rule);flex:0 0 auto;margin-top:auto}
/* The one control that collapses the navigation. Full width so the target is
   the width of the rail rather than the width of a chevron. */
.hcp .nav__col{display:flex;align-items:center;gap:10px;width:100%;padding:8px 10px;
  border-radius:8px;font-size:12px;color:#A5A2BC}
.hcp .nav__col:hover{background:#262439;color:#fff}
.hcp .nav__col svg{width:13px;height:13px;flex:0 0 13px;stroke:currentColor;fill:none;
  stroke-width:1.8;transform:rotate(90deg);transition:transform .15s ease}
.hcp .nav__col[aria-expanded="false"] svg{transform:rotate(-90deg)}
.hcp .app--rail .nav__col{justify-content:center;padding:8px 0;gap:0}

.hcp .main{min-width:0;display:flex;flex-direction:column;position:relative;overflow:hidden}
.hcp .bar{height:52px;flex:0 0 auto;background:var(--surface);border-bottom:1px solid var(--rule);display:flex;align-items:center;gap:14px;padding:0 var(--pad)}
.hcp .crumb{display:flex;align-items:center;gap:8px;font-size:12.5px;color:var(--dim)}
.hcp .crumb b{color:var(--ink);font-weight:600}
.hcp .crumb i{font-style:normal;color:var(--dim)}
.hcp .bar__r{margin-left:auto;display:flex;align-items:center;gap:12px;font-size:12.5px;color:var(--dim)}
.hcp .kbd{font-family:var(--mono);font-size:10.5px;border:1px solid var(--rule-hard);border-bottom-width:2px;border-radius:4px;padding:1px 5px;color:var(--dim);background:var(--surface)}
.hcp .cmdb{display:flex;align-items:center;gap:8px;height:30px;padding:0 10px;border:1px solid var(--rule);border-radius:8px;background:var(--paper);color:var(--dim);font-size:12.5px;min-width:230px}
.hcp .cmdb:hover{border-color:var(--rule-hard);background:var(--surface)}
.hcp .cmdb svg{width:14px;height:14px}

.hcp .page{flex:1;overflow:auto;padding:var(--pad)}
/* A flush page hands its whole box to one component, which then owns the
   scrolling. Without the flex column the investigation surface could not take
   the height it needs. */
.hcp .page--flush{padding:0;display:flex;flex-direction:column;overflow:hidden}

/* -- messages --------------------------------------------------------------
   A redirect that says nothing leaves the operator guessing whether the action
   took. Same five states as everything else, so a message reads with the shape
   first and the colour second.
   ------------------------------------------------------------------------- */
.hcp .msgs{display:flex;flex-direction:column;gap:8px;margin-bottom:var(--gap)}
.hcp .msg{display:flex;align-items:flex-start;gap:9px;padding:10px 13px;border-radius:9px;
  font-size:13px;line-height:1.5;background:var(--unk-t);color:var(--unk);border:1px solid transparent}
.hcp .msg .mk{margin-top:3px}
.hcp .msg--success{background:var(--ok-t);color:var(--ok)}
.hcp .msg--error{background:var(--bad-t);color:var(--bad)}
.hcp .msg--warning{background:var(--warn-t);color:var(--warn)}
.hcp .msg--info,.hcp .msg--debug{background:var(--busy-t);color:var(--busy)}

/* ── state markers: shape first, colour second, word third ──────────────── */
.hcp .mk{display:inline-block;width:11px;height:11px;flex:0 0 11px;vertical-align:-1px}
.hcp .st{display:inline-flex;align-items:center;gap:6px;font-size:.92em;font-weight:500;white-space:nowrap}
.hcp .s-ok{color:var(--ok)} .hcp .s-bad{color:var(--bad)} .hcp .s-warn{color:var(--warn)}
.hcp .s-busy{color:var(--busy)} .hcp .s-unk{color:var(--unk)}

/* Pills are reserved for the single primary state of a record. Everything else
   is typographic, which is what stops a row becoming a wall of badges. */
.hcp .pill{display:inline-flex;align-items:center;gap:5px;font-size:11.5px;font-weight:600;
  padding:2px 9px;border-radius:6px;white-space:nowrap;background:var(--unk-t);color:var(--unk)}
.hcp .p-ok{background:var(--ok-t);color:var(--ok)} .hcp .p-bad{background:var(--bad-t);color:var(--bad)}
.hcp .p-warn{background:var(--warn-t);color:var(--warn)} .hcp .p-busy{background:var(--busy-t);color:var(--busy)}
.hcp .p-acc{background:var(--accent-tint);color:var(--accent-ink)}
.hcp .pill .mk{width:9px;height:9px;flex:0 0 9px}
.hcp .p-unk{background:var(--unk-t);color:var(--unk);box-shadow:inset 0 0 0 1px var(--decor)}

/* The product's signature notation: declared on the left, observed on the
   right, the arrow carrying the divergence. */
.hcp .dv{display:inline-flex;align-items:baseline;gap:7px;font-family:var(--mono);font-size:.86em}
.hcp .dv .d{color:var(--ink-2)}
/* The arrow is a GRAPHIC, not a text character. As text it sat in --decor at
   3.35:1, below the 4.5:1 floor every text token has to clear -- the linter
   caught it about seventy times. Drawn as an SVG it is legitimately a
   meaningful non-text graphic, the 3:1 floor applies, and it is hidden from
   the reading order with the relationship spoken instead. */
.hcp .dv .a{width:15px;height:9px;flex:0 0 15px;color:var(--decor);align-self:center}
.hcp .dv{align-items:center;gap:6px}
.hcp .dv .o{color:var(--ink)}
.hcp .dv .o.miss{color:var(--unk);font-style:italic}
.hcp .dv .o.drift{color:var(--warn)}

/* ── continuous working surface (the anti-card) ─────────────────────────── */
.hcp .sheet{background:var(--surface);border:1px solid var(--rule);border-radius:14px;overflow:hidden}
.hcp .sect{padding:var(--gap) var(--pad)}
.hcp .sect + .sect{border-top:1px solid var(--rule)}
.hcp .sect__h{display:flex;align-items:baseline;gap:12px;margin-bottom:calc(var(--gap) * .6)}
.hcp .sect__h h2{font-size:1.02em;font-weight:700;letter-spacing:-.01em}
.hcp .sect__h .r{margin-left:auto;font-size:.86em;color:var(--dim);font-weight:400}
.hcp .sect__h .r-sub{font-size:12.5px;color:var(--dim)}
.hcp .sect__h .lbl + .r-sub{margin-left:0}
/* A list that is a list, not a set of bullets pretending to be design. */
.hcp .plain{list-style:none;margin:8px 0 0;padding:0;display:grid;gap:5px;font-size:12.5px}
.hcp .plain li{color:var(--ink-2)}
/* One drawer is shown at a time and the rest are in the page, so the selection
   costs no round trip. Declared as a class rather than the hidden attribute
   because .drawer sets display and would beat it. */
.hcp .drawer.is-hidden{display:none}

/* -- dense list surface (S4) ----------------------------------------------
   A filter bar, not a filter panel: it is one row of controls above the table
   rather than a bordered box beside it, so the table keeps the width.
   ------------------------------------------------------------------------- */
.hcp .lede--tight{margin-bottom:0}
.hcp .pagehead{display:flex;align-items:flex-start;gap:20px;margin-bottom:var(--gap)}
.hcp .pagehead .lede{flex:1;min-width:0}
.hcp .pagehead__a{display:flex;align-items:center;gap:9px;flex:0 0 auto;padding-top:3px}
.hcp .btn--quiet{background:var(--surface);color:var(--ink-2);border:1px solid var(--rule-hard)}
.hcp .btn--quiet:hover{background:var(--paper);border-color:var(--decor);color:var(--ink)}
.hcp .btn--inline svg{margin-right:7px}
@media (max-width:1000px){
  .hcp .pagehead{flex-direction:column;gap:12px}
  .hcp .pagehead__a{padding-top:0}
}
.hcp .filters{display:flex;align-items:center;gap:9px;flex-wrap:wrap;
  padding-bottom:var(--gap);border-bottom:1px solid var(--rule);margin-bottom:2px}
.hcp .filters__q{display:flex;align-items:center;gap:8px;height:32px;padding:0 11px;
  border:1px solid var(--rule-hard);border-radius:8px;background:var(--surface);min-width:0;flex:1 1 240px}
.hcp .filters__q svg{width:14px;height:14px;flex:0 0 14px;color:var(--dim)}
.hcp .filters__q input{border:0;outline:0;background:none;font:inherit;font-size:12.5px;
  color:var(--ink);width:100%;min-width:0}
.hcp .filters__q:focus-within{border-color:var(--accent);box-shadow:0 0 0 1px var(--accent)}
.hcp .filters select{height:32px;border:1px solid var(--rule-hard);border-radius:8px;
  background:var(--surface);font:inherit;font-size:12.5px;color:var(--ink);padding:0 8px;flex:0 0 auto}
.hcp .filters select:focus-visible{outline:2px solid var(--accent);outline-offset:1px}
.hcp .filters .btn--inline{height:32px;margin-top:0}
.hcp .filters__n{margin-left:auto;font-size:12px;color:var(--dim);flex:0 0 auto}

/* The foundation already carries the whole dense-table design, including hover,
   the three-channel selected row and an INLINE .sub. Six rules were added here
   that duplicated it, and one of them -- `.hcp .tbl td .sub{display:block}` --
   is one element more specific than `.hcp .tbl .sub`, so it won, stacked the
   slug under the name and overflowed a 31px row by 5px on every line.
   Only the two things the foundation did not have remain. */
.hcp .tbl tr.trow:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}

.hcp .pager{display:flex;align-items:baseline;gap:14px;padding-top:var(--gap);font-size:12px;color:var(--dim)}
.hcp .pager__n{margin-right:auto}
.hcp .lbl{font-size:9.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--dim);font-weight:700}
.hcp .rule{height:1px;background:var(--rule);margin:var(--gap) 0}

/* A card, used only where an object is genuinely bounded and actionable. */
.hcp .obj{background:var(--surface);border:1px solid var(--rule);border-radius:12px;padding:16px 18px}

/* ── calm mode: the serif appears, and only here ────────────────────────── */
/* Calm is a lower density for operational comprehension, not an editorial
   layout. The headline was 4.1 lines and pushed the divergences below the fold,
   which made the most operational surface in the product the least operational
   thing on the screen. It is now a two-line statement. */
/* D1, approved 2026-08-25. The serif used to mark calm, so one element was set
   in two families depending on a density token. Under the frozen contract the
   serif is semantic and belongs to the figure slot alone; a page statement is a
   heading, so it is sans at every density and the density override this
   replaces has nothing left to say. Calm is still legible before a word is
   read, from its spacing, which is what density actually is. */
.hcp .lede h1{font-family:var(--sans);font-weight:700;font-size:23px;line-height:1.28;
  letter-spacing:-.019em;text-wrap:balance;max-width:52ch}
.hcp[data-d="calm"] .lede h1{font-size:25px;line-height:1.26;max-width:56ch}
.hcp .lede h1 em{font-style:italic}
.hcp .lede h1 b{font-weight:400;font-style:normal;border-bottom:2px solid var(--bad);padding-bottom:1px}
.hcp .lede h1 i{font-style:normal;border-bottom:2px dashed var(--decor);padding-bottom:1px}
.hcp .lede p{font-size:13.5px;color:var(--ink-2);line-height:1.6;margin-top:9px;max-width:78ch}

/* The whole fleet as one full-width band: at 14 tenants and at 2,000 it is the
   same 34px of screen, and it reads left to right like a rule. */
.hcp .band{margin-top:20px}
.hcp .band__s{display:flex;gap:2px;align-items:flex-end;height:34px}
/* One bar per tenant only while a bar can still be seen. Measured: at 2,000
   tenants each bar renders at 2px, so above the threshold the band becomes a
   proportional distribution instead. The question the band answers changes from
   "which one" to "how many", which is the right question at that size. */
/* Any element, because a tick that links somewhere is an <a>. */
.hcp .band__s > *{flex:1;border-radius:2px;min-width:3px;padding:0;display:block}
/* Height is the second channel after colour: a failing tenant's bar is short
   and an unmeasured one is shorter and hollow, so the band survives greyscale.
   .bar was already the name of the top bar, hence .tick. */
.hcp .tick--ok{background:var(--ok);height:100%}
.hcp .tick--bad{background:var(--bad);height:58%}
.hcp .tick--unk{background:transparent;box-shadow:inset 0 0 0 1.2px var(--decor);height:30%}
.hcp .band__s > *:hover{outline:2px solid var(--accent);outline-offset:1px}
.hcp .band__n{margin-left:auto;color:var(--dim)}
.hcp .band__p{display:flex;height:34px;border-radius:4px;overflow:hidden;background:var(--sunken)}
.hcp .band__p i{display:block;height:100%}
.hcp .band__p i.u{background:transparent;box-shadow:inset 0 0 0 1.2px var(--decor)}
.hcp .band__l{display:flex;gap:18px;flex-wrap:wrap;margin-top:10px;font-size:12px;align-items:baseline}
.hcp .band__l .sep{color:var(--dim)}
.hcp .band__l b{font-weight:700}
/* ── THE FIGURE SLOT ──────────────────────────────────────
   TANTRA_CONTROL_PANEL_APPROVED_DIRECTION.md section 1.1. The ONE semantic
   entry point into the serif, and the only selector in this file that may name
   it. Gate 1 asserts exactly that, so an eighth serif rule fails the build
   rather than arriving unreviewed.

   A figure slot holds a counted quantity, or the honest replacement for a
   quantity that does not exist, in the position the quantity would occupy.
   "Nothing due" and "None contracted" are the second kind, and they are the
   whole reason the rule is semantic rather than "serif for numbers".

   Never inside .tbl. Instrument Serif's digits are lighter and narrower than
   the sans at table sizes, and the direction does not force its signature into
   the one environment where it reads worse. Gate 2 asserts that too.
   ------------------------------------------------------------------------- */
.hcp .fig{font-family:var(--serif);font-weight:400;line-height:.92;letter-spacing:-.025em;
  font-variant-numeric:tabular-nums;font-size:64px}
/* The denominator and the currency stay in the interface face: they QUALIFY the
   figure rather than being one. Relative, so one rule holds at all three sizes
   instead of a fixed value that would read as a second figure at --sm.

   Declared BEFORE the size variants deliberately. It is a descendant rule and
   does not actually compete with them, but variant_overrides() reads any later
   higher-specificity rule ending in the base class as defeating the modifier,
   and it is right to: proving the exception by hand every time is how the five
   cascade defects that gate was built from got in. Order costs nothing. */
.hcp .fig small,.hcp .fig .of{font-family:var(--sans);font-size:.42em;color:var(--dim);
  letter-spacing:0}
/* An absence occupying the slot is not a 64px word. It keeps the position and
   the family and gives back the size, because it is a sentence, not a number. */
.hcp .fig.unk{font-size:26px;line-height:1.2;color:var(--unk);letter-spacing:-.01em}
.hcp .fig--lg{font-size:64px}
.hcp .fig--md{font-size:46px}
.hcp .fig--sm{font-size:26px;line-height:1;letter-spacing:-.02em}

/* ── the divergence spine (overview primary surface) ────────────────────── */
.hcp .spine{display:flex;flex-direction:column}
.hcp .dvg{display:grid;grid-template-columns:var(--gut) 52px minmax(0,1fr) auto;gap:0 14px;align-items:baseline;
  padding:11px 0;border-top:1px solid var(--rule);width:100%}
.hcp .dvg:hover{background:var(--surface)}
.hcp .dvg.on{background:var(--accent-tint);box-shadow:inset 3px 0 0 var(--accent),inset -3px 0 0 var(--accent)}
.hcp .dvg.on .dvg__b b{font-weight:700;color:var(--accent-ink)}
.hcp .dvg__n{text-align:right}
.hcp .dvg__b b{display:block;font-size:13.5px;font-weight:600;letter-spacing:-.005em}
.hcp .dvg__b p{font-size:12.5px;color:var(--ink-2);line-height:1.5;margin-top:2px;max-width:74ch}
.hcp .dvg__b .who{font-family:var(--mono);font-size:10.5px;color:var(--dim);margin-top:4px;display:block;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.hcp .dvg__g{color:var(--decor);align-self:center}
.hcp .n-bad{color:var(--bad)} .hcp .n-warn{color:var(--warn)} .hcp .n-unk{color:var(--unk)}

/* ── fleet ──────────────────────────────────────────────────────────────── */
/* Compact strip for the overview: the whole fleet in one band. */
.hcp .strip{display:flex;gap:3px;align-items:flex-end;height:44px}
.hcp .strip button{flex:1;border-radius:3px;position:relative;min-width:6px}
.hcp .strip button:hover{outline:2px solid var(--accent);outline-offset:1px}

/* Matrix for Fleet Health: every cell encodes lifecycle, health, drift and a
   health history pattern: four channels, only one of which is colour. */
.hcp .matrix{display:grid;grid-template-columns:repeat(auto-fill,minmax(216px,1fr));gap:10px}
/* Measured: 500 full nodes is 13,490px, fifteen screens of scroll. Past the
   threshold the fleet becomes a true heatmap - same four channels, no text -
   so 2,000 nodes occupy about one screen instead of sixty. */
.hcp .matrix--heat{grid-template-columns:repeat(auto-fill,minmax(22px,1fr));gap:4px}
.hcp .cellx{width:100%;aspect-ratio:1;border-radius:4px;position:relative;display:flex;
  align-items:center;justify-content:center;border:1.5px solid transparent}
.hcp .cellx.h-ok{background:#DCEFE3;border-color:#719F82}
.hcp .cellx.h-bad{background:#F7DEDC;border-color:#BC8781}
.hcp .cellx.h-unk{background:transparent;border-color:var(--decor);border-style:dashed}
/* In heatmap mode a healthy cell is plain fill and only states needing
   attention carry a glyph. With a marker in every cell nothing popped, which
   defeats the point of the view. */
.hcp .cellx .mk{width:9px;height:9px;flex:0 0 9px}
.hcp .cellx.h-ok .mk{display:none}
.hcp .cellx.l-busy{border-style:dotted;border-width:2px}
.hcp .cellx.l-bad{opacity:.55}
/* The cell carries its identity when there is room for it. Above HEAT_MAX the
   text goes and the four channels stay, which is the whole point of the
   threshold: the same encoding at two densities, not two different views. */
.hcp .cellx{aspect-ratio:auto;min-height:78px;flex-direction:column;align-items:flex-start;
  justify-content:flex-start;gap:2px;padding:9px 10px;color:inherit;overflow:hidden}
.hcp .matrix--heat .cellx{aspect-ratio:1;min-height:0;padding:0;
  align-items:center;justify-content:center}
.hcp .cellx .mk{position:absolute;top:9px;right:9px}
.hcp .matrix--heat .cellx .mk{position:static}
.hcp .cellx__n{font-size:12.5px;font-weight:600;color:var(--ink);max-width:100%;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;padding-right:14px}
.hcp .cellx__s{font-family:var(--mono);font-size:10.5px;color:var(--dim);max-width:100%;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.hcp .cellx__t{font-size:10.5px;color:var(--ink-2);margin-top:auto}
/* Drift is the fourth channel and it is a shape, not a colour: an underline the
   cell either has or does not. */
.hcp .cellx.drifted{border-bottom-width:4px;border-bottom-color:var(--warn)}
.hcp .cellx:hover{outline:2px solid var(--accent);outline-offset:1px}
.hcp .cellx:focus-visible{outline:2px solid var(--accent);outline-offset:1px}

.hcp .legend{display:flex;gap:18px;flex-wrap:wrap;align-items:center;margin-top:12px;font-size:12px}
.hcp .legend__k{display:inline-flex;align-items:center;gap:7px;color:var(--ink-2)}
.hcp .lk{width:14px;height:14px;border-radius:3px;border:1.5px solid var(--decor);flex:0 0 14px;display:block}
.hcp .lk--drift{border-bottom-width:4px;border-bottom-color:var(--warn)}
.hcp .lk--busy{border-style:dotted;border-width:2px}
.hcp .lk--susp{opacity:.55;background:var(--sunken)}
.hcp .cellx::after{content:"";position:absolute;right:2px;bottom:2px;width:4px;height:4px;border-radius:50%}
.hcp .cellx.d-1::after{background:var(--warn)}
.hcp .cellx:hover{outline:2px solid var(--accent);outline-offset:1px;z-index:2}
.hcp .node{background:var(--surface);border:1px solid var(--rule);border-radius:11px;padding:12px 14px 11px;
  position:relative;overflow:hidden;display:block;width:100%}
.hcp .node:hover{border-color:var(--rule-hard);box-shadow:0 3px 14px rgba(22,21,30,.07)}
/* Lifecycle is the left edge: solid = active, dashed = never established,
   striped = in flight, none = suspended. Shape, not hue. */
.hcp .node::before{content:"";position:absolute;left:0;top:0;bottom:0;width:3px}
.hcp .node.l-ok::before{background:var(--ok)}
.hcp .node.l-bad::before{background:var(--bad)}
.hcp .node.l-busy::before{background:repeating-linear-gradient(180deg,var(--busy) 0 5px,transparent 5px 10px)}
.hcp .node.l-unk::before{background:repeating-linear-gradient(180deg,var(--decor) 0 3px,transparent 3px 6px)}
.hcp .node__t{display:flex;align-items:baseline;gap:8px}
.hcp .node__t b{font-size:13.5px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}
.hcp .node__t .sku{margin-left:auto;font-family:var(--mono);font-size:10px;color:var(--dim);flex:0 0 auto}
.hcp .node__s{font-family:var(--mono);font-size:10.5px;color:var(--dim);margin-top:1px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.hcp .node__r{display:flex;align-items:center;gap:9px;margin-top:9px;font-size:11.5px}
/* Health history as a pattern of blocks: full = probed and good, low = probed
   and failing, hollow = never probed. Readable without colour. */
.hcp .hist{display:flex;gap:2px;align-items:flex-end;height:18px;margin-top:10px}
.hcp .hist i{flex:1;border-radius:1px;display:block}
.hcp .hist i.g{background:#719F82} .hcp .hist i.b{background:#BC8781}
.hcp .hist i.u{background:transparent;box-shadow:inset 0 0 0 1.2px var(--decor);height:100% !important}

/* ── dense operational table (no card around it) ────────────────────────── */
/* A step trail carries a free-text note and is legitimately wide. It scrolls
   inside its own container so the page never does. */
.hcp .tblwrap{overflow-x:auto;max-width:100%}
.hcp .tbl{width:100%;border-collapse:collapse}
.hcp .tbl thead th{position:sticky;top:0;z-index:3;background:var(--paper);
  font-size:9.5px;letter-spacing:.12em;text-transform:uppercase;color:var(--dim);font-weight:700;
  text-align:left;padding:0 12px 8px;border-bottom:1px solid var(--rule-hard);white-space:nowrap}
.hcp .tbl thead th:first-child{padding-left:var(--pad)}
.hcp .tbl thead th:last-child{padding-right:var(--pad)}
.hcp .tbl td{padding:0 12px;height:var(--row);border-bottom:1px solid var(--rule);white-space:nowrap;vertical-align:middle}
.hcp .tbl td:first-child{padding-left:var(--pad)}
.hcp .tbl td:last-child{padding-right:var(--pad)}
.hcp .tbl tbody tr{cursor:pointer}
.hcp .tbl tbody tr:hover td{background:var(--surface)}
/* Selection was carried by background alone, which is the one thing the status
   vocabulary forbids. It now carries three channels, and the leading edge points
   at the drawer that opened because of it. */
.hcp .tbl tbody tr.on td{background:var(--accent-tint)}
.hcp .tbl tbody tr.on td:first-child{box-shadow:inset 3px 0 0 var(--accent)}
.hcp .tbl tbody tr.on .nm{font-weight:700;color:var(--accent-ink)}
.hcp .tbl tbody tr.on td:last-child{box-shadow:inset -3px 0 0 var(--accent)}
.hcp .er.on{box-shadow:inset 3px 0 0 var(--accent),inset -3px 0 0 var(--accent)}
.hcp .er.on .a{font-weight:700;color:var(--accent-ink)}
.hcp .tbl .nm{font-weight:600;max-width:290px;overflow:hidden;text-overflow:ellipsis}
.hcp .tbl .sub{font-family:var(--mono);font-size:10.5px;color:var(--dim);letter-spacing:.01em;max-width:290px;overflow:hidden;text-overflow:ellipsis}
.hcp .tbl td.num{text-align:right;font-variant-numeric:tabular-nums}

.hcp .filters{display:flex;align-items:center;gap:7px;padding:0 var(--pad) var(--gap);flex-wrap:wrap}
.hcp .fx{font-size:12px;padding:4px 10px;border-radius:7px;border:1px solid var(--rule);color:var(--dim);background:var(--surface)}
.hcp .fx:hover{border-color:var(--rule-hard);color:var(--ink)}
.hcp .fx.on{background:var(--ink);color:#fff;border-color:var(--ink);font-weight:600}
.hcp .fx b{font-variant-numeric:tabular-nums;opacity:.6;margin-left:5px;font-weight:600}
.hcp .fx .mk{opacity:.9}
.hcp .srch{flex:1;max-width:280px;min-width:170px;height:30px;border:1px solid var(--rule);border-radius:8px;
  display:flex;align-items:center;gap:8px;padding:0 10px;background:var(--surface);color:var(--dim);font-size:12.5px}
.hcp .srch svg{width:14px;height:14px}
.hcp .cnt{margin-left:auto;font-size:12px;color:var(--dim);font-variant-numeric:tabular-nums}
.hcp .more{display:flex;align-items:center;justify-content:center;gap:9px;padding:13px;
  border-top:1px solid var(--rule);font-size:12.5px;color:var(--dim);width:100%;background:var(--paper)}
.hcp .more b{color:var(--accent);font-weight:600}

/* ── tenant workspace ───────────────────────────────────────────────────── */
.hcp .ws{display:grid;grid-template-columns:274px 1fr;flex:1;min-height:0}
.hcp .wsr{background:var(--surface);border-right:1px solid var(--rule);padding:22px 20px;display:flex;flex-direction:column;gap:20px;overflow:auto}
.hcp .wsr__id h1{font-size:20px;font-weight:700;letter-spacing:-.02em;line-height:1.2}
.hcp .wsr__id .sub{font-family:var(--mono);font-size:11px;color:var(--dim);margin-top:3px}
.hcp .wsr__id .pills{display:flex;gap:6px;flex-wrap:wrap;margin-top:11px}
.hcp .wsb h6{font-size:9px;letter-spacing:.15em;text-transform:uppercase;color:var(--dim);font-weight:700;margin-bottom:9px}
/* The value track took `auto` and squeezed the label to 36px, so a word like
   "Configuration" overflowed it. The label now has a floor and the value wraps. */
.hcp .pair{display:grid;grid-template-columns:minmax(76px,auto) minmax(0,1fr);gap:7px 12px;font-size:12.5px;align-items:baseline}
.hcp .pair dt{color:var(--ink-2)}
/* overflow-wrap:anywhere broke an email mid-word in the 274px rail. A single
   unbreakable value truncates and keeps the whole string on hover instead. */
.hcp .pair dd{text-align:right;font-weight:500;min-width:0;justify-self:end;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%}
/* The ellipsis above is right for ONE unbreakable value: an email keeps its
   full string on hover. It is wrong for the declared-against-observed notation,
   which is two values and an arrow, and was being cut mid-hash in a 141px cell
   so an operator read a version that did not exist. This cell wraps instead.
   Not solved by letting .dv wrap: inside justify-self:end the flex box then
   collapses to its min-content width, which is worse than the clip. */
.hcp .pair dd.dd--wrap{white-space:normal;overflow:visible;text-overflow:clip;
  justify-self:end;text-align:right}
/* An asynchronous action has to report its own outcome, otherwise the product
   can say "working on it" and never say what happened. Loading is the diamond,
   success the circle, failure the triangle -- three shapes, so the three are
   told apart without colour. */
.hcp .wsact{margin-top:auto;display:flex;flex-direction:column;gap:6px}
.hcp .outcome{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap;
  padding:9px 0 11px;border-top:1px solid var(--rule);margin-bottom:2px}
.hcp .outcome .lbl{flex:0 0 100%}
.hcp .o-when{font-size:11.5px;color:var(--dim);font-family:var(--mono)}
.hcp .wsact button{height:34px;border-radius:8px;border:1px solid var(--rule);font-size:12.5px;font-weight:600;color:var(--ink-2);padding:0 12px;display:flex;align-items:center;gap:8px}
.hcp .wsact button:hover{border-color:var(--accent);color:var(--accent)}
.hcp .wsact button.p{background:var(--ink);color:#fff;border-color:var(--ink)}
.hcp .wsact button.p:hover{background:var(--accent);border-color:var(--accent)}
.hcp .wsm{min-width:0;display:flex;flex-direction:column;overflow:hidden}
.hcp .tabs{display:flex;background:var(--surface);border-bottom:1px solid var(--rule);padding:0 var(--pad);overflow-x:auto;flex:0 0 auto}
.hcp .tab{padding:12px 13px;font-size:13px;font-weight:500;color:var(--dim);border-bottom:2px solid transparent;margin-bottom:-1px;white-space:nowrap;display:flex;align-items:center;gap:7px}
.hcp .tab:hover{color:var(--ink-2)}
.hcp .tab.on{color:var(--accent);border-bottom-color:var(--accent);font-weight:700}
.hcp .tab .mk{opacity:.95}

/* ── provisioning pipeline: declared sequence vs observed trail ─────────── */
.hcp .pipe{display:flex;align-items:stretch;overflow-x:auto;padding-bottom:4px}
.hcp .stg{flex:1 0 auto;min-width:104px;padding-right:8px;position:relative;text-align:left}
.hcp .stg__b{height:5px;border-radius:3px;background:var(--rule-hard)}
.hcp .stg.done .stg__b{background:var(--ok)}
.hcp .stg.now .stg__b{background:repeating-linear-gradient(90deg,var(--busy) 0 7px,#7FA8E0 7px 14px)}
.hcp .stg.fail .stg__b{background:var(--bad)}
.hcp .stg.skip .stg__b{background:repeating-linear-gradient(90deg,var(--decor) 0 3px,transparent 3px 6px)}
.hcp .stg__k{font-size:11px;font-weight:600;color:var(--dim);margin-top:8px;line-height:1.28;letter-spacing:-.005em}
.hcp .stg.done .stg__k{color:var(--ink-2)} .hcp .stg.now .stg__k{color:var(--busy)}
.hcp .stg.fail .stg__k{color:var(--bad)}
.hcp .stg__t{font-family:var(--mono);font-size:10px;color:var(--dim);margin-top:3px}
.hcp .stg.sel{background:var(--accent-tint);border-radius:7px;padding:6px 8px 7px;margin:-6px -0 -7px -8px}

/* ── event stream (not a card of rows) ──────────────────────────────────── */
.hcp .stream{display:flex;flex-direction:column}
.hcp .evt{display:grid;grid-template-columns:var(--gut) 62px minmax(0,1fr);gap:0 14px;align-items:baseline;
  padding:8px 0;border-top:1px solid var(--rule);width:100%}
.hcp .evt:hover{background:var(--surface)}
.hcp .evt__t{font-family:var(--mono);font-size:11px;color:var(--dim);letter-spacing:.01em}
.hcp .evt__b b{font-weight:600;font-size:13px}
.hcp .evt__b span{color:var(--ink-2);font-size:12px}

/* ── investigation (audit) ──────────────────────────────────────────────── */
.hcp .inv{display:grid;grid-template-columns:208px 1fr;flex:1;min-height:0}
.hcp .facets{background:var(--surface);border-right:1px solid var(--rule);padding:16px 12px;overflow:auto;display:flex;flex-direction:column;gap:18px}
.hcp .facet h6{font-size:9px;letter-spacing:.15em;text-transform:uppercase;color:var(--dim);font-weight:700;margin-bottom:7px;padding:0 6px}
.hcp .fc{display:flex;align-items:center;gap:8px;padding:4px 6px;border-radius:6px;width:100%;font-size:12.5px;color:var(--ink-2)}
.hcp .fc:hover{background:var(--paper)}
.hcp .fc.on{background:var(--accent-tint);color:var(--accent-ink);font-weight:600}
.hcp .fc .n{margin-left:auto;font-family:var(--mono);font-size:10.5px;color:var(--dim)}
/* A facet with no tone still needs its gutter, or the labels of the toned and
   untoned rows would not line up. */
.hcp .fc .facet__dot{width:11px;height:11px;flex:0 0 11px;border-radius:50%;
  background:var(--sunken);display:inline-block}
.hcp .fc span:not(.n){min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.hcp .facet{display:flex;flex-direction:column;gap:1px}
.hcp .facet .lbl{margin-bottom:7px;padding:0 6px}
.hcp .facets .filters__q{margin-bottom:4px}
.hcp .invhead{padding:var(--gap) var(--pad) 0;flex:0 0 auto}
.hcp .invhead h1{font-size:1.15em;font-weight:700;letter-spacing:-.012em}
.hcp .invhead p{font-size:12.5px;color:var(--ink-2);margin-top:4px;line-height:1.5;max-width:70ch}
.hcp .invm .rows{padding-top:var(--gap)}
.hcp .invm .tbl thead th:first-child,.hcp .invm .tbl td:first-child{padding-left:var(--pad)}
/* With auto layout the browser sizes every column to its content, and a long
   detail string pushed the table 98px past its container at 1440: contained,
   because .rows scrolls, but the operator had to scroll sideways to read the
   thing they came for. Fixed layout on this surface only, so the detail column
   takes whatever is left and ellipsises inside it. */
.hcp .invm .tbl{table-layout:fixed}
.hcp .invm .tbl th:nth-child(1),.hcp .invm .tbl td:nth-child(1){width:var(--gut)}
.hcp .invm .tbl th:nth-child(2),.hcp .invm .tbl td:nth-child(2){width:164px}
/* Measured at 1280, the pinch point once the facet rail returns: the trail gets
   832px and these three were taking 498 of it, leaving the detail 150. Action
   and deployment ellipsise here and are both facets, where the full label is on
   screen; the detail is the only column with nowhere else to be read. */
.hcp .invm .tbl th:nth-child(3),.hcp .invm .tbl td:nth-child(3){width:190px}
.hcp .invm .tbl th:nth-child(4),.hcp .invm .tbl td:nth-child(4){width:158px}
.hcp .invm .tbl th:nth-child(5),.hcp .invm .tbl td:nth-child(5){width:100px}
.hcp .invm .tbl td{overflow:hidden;text-overflow:ellipsis}
.hcp .tbl td.detail{max-width:none;overflow:hidden;text-overflow:ellipsis;color:var(--ink-2)}
.hcp .undecl{font-style:normal;color:var(--warn);font-weight:700;margin-left:3px;cursor:help}
/* An invitation form is a form, not a panel: one field, one action, and the
   sentence that says what accepting it actually grants. */
/* A lifecycle filter is a row of chips, not a select: there are six states and
   the counts are the reason to pick one, so they belong on screen. */
.hcp .chip{display:inline-flex;align-items:center;gap:7px;height:26px;padding:0 10px;
  border:1px solid var(--rule-hard);border-radius:13px;background:var(--surface);
  font-size:12px;color:var(--ink-2);white-space:nowrap}
.hcp .chip:hover{border-color:var(--decor);color:var(--ink)}
.hcp .chip.on{background:var(--accent-tint);border-color:var(--accent);color:var(--accent-ink);font-weight:600}
.hcp .chip__n{font-size:10.5px;color:var(--dim)}
.hcp .chip.on .chip__n{color:var(--accent-ink)}
.hcp .filters .lbl{flex:0 0 auto}
/* Auto layout gave the prospect column 450px at 853, pushing the table 254px
   past its container. Capped, and two columns shed where the surface narrows.
   Both are recoverable: the state column already says whether a code expired
   unused, and who issued it is in the audit trail. */
.hcp .demotbl td:nth-child(2){max-width:280px;overflow:hidden;text-overflow:ellipsis}
@media (max-width:1180px){
  .hcp .demotbl th:nth-child(4),.hcp .demotbl td:nth-child(4),
  .hcp .demotbl th:nth-child(5),.hcp .demotbl td:nth-child(5){display:none}
  .hcp .demotbl td:nth-child(2){max-width:240px}
}

/* -- provisioning (S9) ----------------------------------------------------
   One row per attempt, opening onto the declared sequence with what was
   observed against it. A disclosure rather than a drawer: the sequence belongs
   underneath the attempt it describes, not in a column beside a list.
   ------------------------------------------------------------------------- */
/* -- tenant workspace (S10) -----------------------------------------------
   The panes are all in the page, so switching a tab is not a request. Hidden by
   a class rather than the hidden attribute, because .wspane sets display and
   would beat it -- the same trap the palette had.
   ------------------------------------------------------------------------- */
.hcp .wspane{display:block;padding:var(--gap) var(--pad) calc(var(--gap) * 2)}
.hcp .wspane.is-hidden{display:none}
.hcp .wsm .rows{flex:1;overflow:auto}
.hcp .inlineform{display:flex;align-items:center;gap:12px;flex-wrap:wrap;padding-top:4px}
.hcp .inlineform p{margin:0}
.hcp .inlineform .note{margin-top:0}
.hcp .wsact .btn--inline{justify-content:flex-start;height:34px;margin-top:0;
  border:1px solid var(--rule);background:var(--surface);color:var(--ink-2);font-size:12.5px}
.hcp .wsact .btn--inline:hover{border-color:var(--accent);color:var(--accent);background:var(--surface)}
.hcp .wsact form{display:block}
.hcp .wsact button{width:100%}
.hcp .tab .tn{color:var(--dim);font-size:11px}
@media (max-width:1000px){
  .hcp .ws{grid-template-columns:1fr;grid-template-rows:auto minmax(0,1fr)}
  .hcp .wsr{border-right:0;border-bottom:1px solid var(--rule);max-height:none}
}

.hcp .ops{display:flex;flex-direction:column}
.hcp .op{border-top:1px solid var(--rule)}
.hcp .op:last-child{border-bottom:1px solid var(--rule)}
.hcp .op__h{display:grid;
  grid-template-columns:var(--gut) 190px minmax(0,1fr) 150px 170px 128px 18px;
  gap:0 14px;align-items:center;padding:10px 0;cursor:pointer;list-style:none}
.hcp .op__h::-webkit-details-marker{display:none}
.hcp .op__h:hover{background:var(--surface)}
.hcp .op[open] .op__h{background:var(--accent-tint);box-shadow:inset 3px 0 0 var(--accent)}
.hcp .op[open] .dvg__g{transform:rotate(180deg)}
.hcp .op__id{font-size:11px;color:var(--dim);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.hcp .op__who{min-width:0}
.hcp .op__who b{font-size:13px;font-weight:600;display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.hcp .op__who .sub{font-size:10.5px;color:var(--dim);display:block}
.hcp .op__when{font-size:11px;color:var(--dim);text-align:right}
.hcp .op__b{padding:4px 0 20px var(--gut);display:flex;flex-direction:column;gap:18px}

/* Every declared step is a row, reached or not. Colour is the second channel:
   the marker shape already separates done, in flight, stopped and not reached. */
.hcp .seq{display:flex;flex-direction:column}
.hcp .seq__s{display:grid;grid-template-columns:var(--gut) 190px 110px 110px minmax(0,1fr);
  gap:0 14px;align-items:baseline;padding:5px 0;font-size:12.5px;border-top:1px solid var(--line-soft)}
.hcp .seq__s:first-child{border-top:0}
.hcp .seq__l{font-weight:500}
.hcp .seq__s--unreached .seq__l{color:var(--dim);font-weight:400}
.hcp .seq__s--current .seq__l{color:var(--busy);font-weight:700}
.hcp .seq__s--stopped .seq__l{color:var(--bad);font-weight:700}
.hcp .seq__t,.hcp .seq__a{font-size:11px;color:var(--dim)}
.hcp .seq__n{font-size:11.5px;color:var(--ink-2);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

@media (max-width:1180px){
  .hcp .op__h{grid-template-columns:var(--gut) minmax(0,1fr) 150px 128px 18px}
  .hcp .op__id,.hcp .op__state{display:none}
  .hcp .seq__s{grid-template-columns:var(--gut) 170px 100px minmax(0,1fr)}
  .hcp .seq__a{display:none}
}

.hcp .issueform{max-width:720px;padding-top:6px}
.hcp .issuegrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(210px,1fr));gap:0 14px}
.hcp .inp--area{height:auto;padding:9px 13px;line-height:1.5;resize:vertical}
.hcp .issueform .note{max-width:60ch}
@media (max-width:1000px){ .hcp .issuegrid{grid-template-columns:minmax(0,1fr)} }

.hcp .inviteform{max-width:420px;padding-top:6px}
.hcp .inviteform .btn--inline{margin-top:4px}
.hcp .inviteform .note{max-width:56ch}
.hcp .tbl td form{display:inline}
/* Widened from .hcp .tbl td button.lnk in commit 3. The reset lived inside the
   table rule, so a button-as-link ANYWHERE else kept its grey OS chrome and
   only the text colour applied. Signup needs one for "send it again", which
   must be a form submit rather than a link. */
.hcp button.lnk{background:none;border:0;padding:0;height:auto;width:auto;margin:0;
  font:inherit;font-size:inherit;cursor:pointer}

.hcp .invm{min-width:0;display:flex;flex-direction:column;overflow:hidden}
.hcp .q{height:46px;flex:0 0 auto;background:var(--surface);border-bottom:1px solid var(--rule);display:flex;align-items:center;gap:10px;padding:0 18px}
.hcp .q__i{flex:1;max-width:520px;height:30px;border:1px solid var(--rule);border-radius:8px;display:flex;align-items:center;gap:8px;padding:0 11px;background:var(--paper);font-family:var(--mono);font-size:11.5px;color:var(--dim)}
.hcp .q__i svg{width:13px;height:13px}
.hcp .q__i em{font-style:normal;color:var(--accent-ink);background:var(--accent-tint);border-radius:4px;padding:0 4px}
.hcp .hgram{display:flex;align-items:flex-end;gap:2px;height:40px;padding:9px 18px 0;background:var(--surface);border-bottom:1px solid var(--rule);flex:0 0 auto}
.hcp .hgram i{flex:1;background:#9690B7;border-radius:1px;min-height:2px;display:block}
.hcp .hgram i.hot{background:var(--accent)}
.hcp .rows{overflow:auto;flex:1}
.hcp .er{display:grid;grid-template-columns:var(--gut) 112px 168px minmax(0,1fr);gap:0 12px;align-items:baseline;
  padding:0 18px;height:var(--row);border-bottom:1px solid var(--rule);width:100%;background:var(--surface)}
.hcp .er:hover{background:var(--paper)}
.hcp .er.on{background:var(--accent-tint)}
.hcp .er > *{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.hcp .er .t{font-family:var(--mono);font-size:11px;color:var(--dim);letter-spacing:.01em}
.hcp .er .a{font-weight:600;font-size:12.5px}
.hcp .er .d{color:var(--ink-2);font-size:12.5px}

/* ── drawer ─────────────────────────────────────────────────────────────── */
.hcp .drawer{position:absolute;top:0;right:0;bottom:0;width:366px;background:var(--surface);
  border-left:1px solid var(--rule-hard);box-shadow:-20px 0 48px rgba(22,21,30,.13);
  display:flex;flex-direction:column;z-index:40}
/* When a drawer is open on a dense surface it TAKES space rather than covering
   it. Overlaying hid the Configuration column on the tenant list, which is the
   one column carrying the declared-against-observed notation. */
/* Three rows, not two: the bar, then the scope band, then the working surface
   beside its drawer. Measured before this line existed: .main is a GRID when a
   drawer is open and .page is pinned to row 2, so the band auto-placed into a
   third row and rendered at the FOOT of a 1100px page. It was in the markup, it
   was styled, and it was 1053px below the control it exists to confirm.
   The band's row collapses to nothing when no product is scoped. */
.hcp .main.hasd{display:grid;grid-template-columns:minmax(0,1fr) 366px;
  grid-template-rows:auto auto minmax(0,1fr)}
.hcp .main.hasd > .bar{grid-column:1 / -1}
.hcp .main.hasd > .scoped{grid-column:1 / -1;grid-row:2}
.hcp .main.hasd > .page,.hcp .main.hasd > .inv{grid-column:1;grid-row:3;min-height:0}
.hcp .main.hasd > .drawer{position:static;width:auto;box-shadow:none;grid-column:2;grid-row:3;border-left:3px solid var(--accent)}
/* The drawer's leading edge answers the row's trailing edge, so the pair reads
   as one object rather than two panels that happen to be adjacent. */
.hcp .drawer{border-left:3px solid var(--accent)}
.hcp .drawer__h{padding:18px 20px;border-bottom:1px solid var(--rule);display:flex;gap:11px;align-items:flex-start}
.hcp .drawer__h h3{font-size:16px;font-weight:700;letter-spacing:-.012em;line-height:1.25}
.hcp .drawer__h .sub{font-family:var(--mono);font-size:11px;color:var(--dim);margin-top:3px}
.hcp .drawer__h .x{margin-left:auto;color:var(--dim);flex:0 0 auto}
.hcp .drawer__b{padding:18px 20px;overflow:auto;display:flex;flex-direction:column;gap:20px}
/* Inline icons inside the drawer have no intrinsic size and were rendering at
   the SVG default, breaking the line they sat on. */
/* An inline SVG has no intrinsic size, so an unsized one renders at the SVG
   default and breaks the line it sits on. Scoping this to named surfaces missed
   an 86px chevron on the workspace, because that surface is an inline-styled
   div rather than a class. Every icon inside a control is sized here; the brand
   marks sit outside controls and keep their own size. */
.hcp button svg:not(.mk):not(.a),
.hcp a svg:not(.mk):not(.a),
.hcp .drawer__b svg:not(.mk):not(.a){width:14px;height:14px;flex:0 0 14px}
.hcp .drawer__h svg:not(.mk){width:15px;height:15px;flex:0 0 15px}
.hcp .wsact svg{width:15px;height:15px;flex:0 0 15px}
.hcp .dvg__g svg{width:15px;height:15px}
.hcp .dl{display:grid;grid-template-columns:96px minmax(0,1fr);gap:7px 12px;font-size:12.5px}
.hcp .dl dt{color:var(--ink-2)} .hcp .dl dd{font-weight:500;overflow-wrap:anywhere}
.hcp .code{font-family:var(--mono);font-size:11.5px;line-height:1.65;color:var(--ink-2);
  background:var(--paper);border:1px solid var(--rule);border-radius:9px;padding:11px 12px;white-space:pre-wrap;overflow-wrap:anywhere}

/* ── login ──────────────────────────────────────────────────────────────── */
/* 680px was the height of the prototype's harness frame. On a real page it
   leaves paper below the fold -- 220px of it at 1440x900. An entry surface is
   the whole window. dvh second so it wins where it is supported. */
.hcp .login{display:grid;grid-template-columns:1.06fr 1fr;min-height:100vh;min-height:100dvh}
.hcp .login__a{background:var(--chrome);color:#fff;padding:44px 48px;display:flex;flex-direction:column;position:relative;overflow:hidden}
.hcp .login__a canvas{position:absolute;inset:0;width:100%;height:100%;opacity:.5}
.hcp .login__a > *{position:relative;z-index:2}
.hcp .login__a h2{font-family:var(--sans);font-weight:700;font-size:35px;line-height:1.16;letter-spacing:-.022em;margin-top:auto;max-width:17ch}
/* THE ITALIC'S TRAILING SPACE. Instrument Serif italic leans into the space
   after it, so an emphasised word and the roman word following it read as one.
   Measured at the rendered 41px: 6.5px of visible gap where a word space is
   10.3px, a 37 percent reduction. Seen on three independent Entry screens,
   "own, declared and", "does not resolve to", and "protects the account, not".

   A margin, not a fix per string, and applied to the italic wherever the serif
   sets it: the same construction is in the operator lede and would read the
   same way there. .04em is the difference measured back, expressed relative to
   the type size so it holds at 27px and 41px alike. margin-right only: the
   space BEFORE an italic is not the one it eats. */
.hcp .login__a h2 em{font-style:italic;color:var(--accent-bright)}
.hcp .login__a p{font-size:14.5px;color:#A5A2BC;margin-top:15px;max-width:40ch;line-height:1.62}
.hcp .login__f{padding:44px 48px;display:flex;flex-direction:column;justify-content:center;background:var(--surface)}
.hcp .login__f .in{max-width:344px;width:100%}
.hcp .login__f h1{font-family:var(--sans);font-weight:700;font-size:28px;line-height:1.14;letter-spacing:-.024em}
.hcp .login__f .sub{font-size:13.5px;color:var(--dim);margin:9px 0 26px;line-height:1.62}
.hcp .fld{margin-bottom:15px}
.hcp .fld label{display:block;font-size:12.5px;font-weight:600;margin-bottom:6px;color:var(--ink-2)}
.hcp .fld .inp{height:42px;border:1px solid var(--rule-hard);border-radius:9px;background:var(--paper);display:flex;align-items:center;padding:0 13px;color:var(--dim);font-size:13.5px}
/* In the prototype .inp was a div standing in for a field. These are the rules
   it needs once it is a real one. */
.hcp .fld input.inp,.hcp .fld select.inp,.hcp .fld textarea.inp{
  display:block;width:100%;font:inherit;font-size:13.5px;color:var(--ink)}
.hcp .fld input.inp::placeholder{color:var(--dim)}
.hcp .fld .inp:focus-visible{outline:2px solid var(--accent);outline-offset:1px;border-color:var(--accent);background:var(--surface)}

/* -- entry: the public catalogue ------------------------------------------
   The only thing the sign-in page knows that the marketing site does not
   already say out loud. Names and availability; no counts, no health, no
   status markers, because entry mode reports no observations.
   ------------------------------------------------------------------------- */
.hcp .cat{margin-top:32px;padding-top:22px;border-top:1px solid var(--chrome-rule)}
.hcp .cat__h{font-size:9px;letter-spacing:.15em;text-transform:uppercase;color:#9C98B4;font-weight:700;display:block}
.hcp .cat__l{list-style:none;margin:12px 0 0;padding:0;display:grid;gap:8px;max-width:34ch}
.hcp .cat__i{display:flex;align-items:baseline;gap:14px;font-size:13.5px}
.hcp .cat__i b{font-weight:600;color:#fff}
.hcp .cat__i span{font-size:11px;color:#9C98B4;margin-left:auto;letter-spacing:.04em;white-space:nowrap}
.hcp .cat__i--soon b{color:#A5A2BC;font-weight:400}
.hcp .btn{height:42px;border-radius:9px;background:var(--accent);color:#fff;font-weight:600;font-size:13.5px;width:100%;margin-top:6px;display:flex;align-items:center;justify-content:center}
.hcp .btn:hover{background:var(--accent-ink)}

/* The modifiers, re-declared. This block redefines .hcp .btn at the SAME
   specificity as .hcp .btn--quiet six hundred rules earlier, and later wins, so
   every button modifier was silently painted accent purple on every Entry
   screen. Found on the signup waiting screen, where a secondary "Check now"
   rendered as a second primary; it was never specific to that screen.
   Source order, not specificity, decided it: the fifth time in this workstream. */
.hcp .btn--quiet{background:var(--surface);color:var(--ink-2);border:1px solid var(--rule-hard)}
.hcp .btn--quiet:hover{background:var(--paper);border-color:var(--decor);color:var(--ink)}
.hcp .btn--ghost{background:var(--surface);color:var(--ink-2);border:1px solid var(--rule-hard)}
.hcp .btn--ghost:hover{background:var(--paper);border-color:var(--decor);color:var(--ink)}
.hcp .foot{font-size:12.5px;color:var(--dim);margin-top:18px;line-height:1.65}
.hcp .foot a{color:var(--accent);font-weight:600}

/* -- entry journey --------------------------------------------------------
   Signup is the only Entry surface that is a JOURNEY rather than a single
   screen, so it needs two things the others never did: a way to say where the
   visitor is, and a way to offer a choice. Sign-in, password reset and
   invitation acceptance all COLLECT; none of them OFFER.

   Both live here in the shared entry section rather than beside the signup
   markup, because a component that exists for exactly one URL is the
   route-specific visual world this phase exists to remove.

   The step indicator is text and a rule, deliberately. Marking done and
   not-yet steps with the status shapes would be new cross-domain state
   visualisation, which Phase 3A excludes.
   ------------------------------------------------------------------------- */
.hcp .prog{display:flex;align-items:center;gap:11px;margin-bottom:21px;font-size:11px;
  font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--dim)}
.hcp .prog__t{flex:1;height:3px;border-radius:2px;background:var(--sunken);overflow:hidden}
.hcp .prog__t i{display:block;height:100%;background:var(--accent);border-radius:2px}

/* What the journey already captured. Shown so the screen is honest about what
   it recorded, and NOT as an input: the step that owns a value is the only step
   allowed to edit it. Rendering it as an editable field that the form then
   ignores is the defect this replaces. */
.hcp .ctx{display:flex;align-items:baseline;gap:9px;flex-wrap:wrap;
  padding:11px 13px;margin-bottom:16px;border:1px solid var(--rule);
  border-radius:9px;background:var(--paper);font-size:12.5px}
.hcp .ctx dt{color:var(--dim);flex:0 0 auto}
/* Wraps, never truncates. A legal name is the thing the visitor typed and is
   about to be invoiced under, so an ellipsis in the middle of it is the one
   place this row must not save space. */
.hcp .ctx dd{margin:0;font-weight:600;color:var(--ink);min-width:0;
  line-height:1.5;overflow-wrap:anywhere}

.hcp .opts{display:flex;flex-direction:column;gap:9px;margin-bottom:16px}
.hcp .opt{display:flex;align-items:flex-start;gap:11px;padding:13px;cursor:pointer;
  border:1px solid var(--rule-hard);border-radius:9px;background:var(--paper)}
.hcp .opt:hover{border-color:var(--decor);background:var(--surface)}
.hcp .opt input{flex:0 0 auto;margin:2px 0 0;accent-color:var(--accent)}
.hcp .opt__b{min-width:0}
.hcp .opt__n{display:block;font-size:13.5px;font-weight:600;color:var(--ink)}
.hcp .opt__d{display:block;margin-top:3px;font-size:12px;line-height:1.5;color:var(--dim)}
/* Progressive: where :has is missing the radio itself still carries the state,
   so the choice is never unreadable, only unhighlighted. */
.hcp .opt:has(input:checked){border-color:var(--accent);background:var(--accent-tint)}
.hcp .opt:focus-within{outline:2px solid var(--accent);outline-offset:1px}

/* -- entry shell ----------------------------------------------------------
   The identity block every Entry surface carries. The prototype held it as
   inline styles on one screen; a shell that sign-in, password reset and
   invitation acceptance all extend needs a name instead.

   #8B87A6 on --chrome is 5.41:1, the same pairing the operator brand uses, so
   the smallest type in the product still clears AA.
   ------------------------------------------------------------------------- */
.hcp .ebrand{display:flex;align-items:center;gap:11px;flex:0 0 auto}
.hcp .ebrand img{width:28px;height:28px}
.hcp .ebrand__t b{font-size:19px;line-height:1.2;display:block}
.hcp .ebrand__t > span{font-size:8.5px;letter-spacing:.15em;text-transform:uppercase;color:#8B87A6;font-weight:700;display:block}
/* The customer header carries the same mark at a smaller size. One brand
   primitive, two surfaces; #9C98B4 is 6.70:1 on --chrome. */
.hcp .ebrand--sm img{width:26px;height:26px}
.hcp .ebrand--sm .ebrand__t b{font-size:16px}
.hcp .ebrand--sm .ebrand__t > span{color:#9C98B4}

/* -- customer shell -------------------------------------------------------
   A session exists, so the page owes the reader two things Entry does not: it
   must say whose account this is, and it must offer a way out. Both live in
   the header, which is why Customer is a third mode and not a variant.
   ------------------------------------------------------------------------- */
.hcp .cust{min-height:100vh;min-height:100dvh;display:flex;flex-direction:column;background:var(--paper)}
.hcp .cust__h{background:var(--chrome);color:#fff;padding:0 40px;height:64px;display:flex;align-items:center;gap:12px;flex:0 0 auto}
/* 7.52:1 on --chrome. The account name is content, not decoration. */
.hcp .cust__org{margin-left:auto;font-size:12.5px;color:#A5A2BC;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.hcp .cust__out{margin-left:14px;flex:0 0 auto}
.hcp .cust__out button{font-size:12.5px;color:#A5A2BC}
.hcp .cust__out button:hover{color:#fff}
.hcp .cust__b{padding:var(--pad) 40px;max-width:960px;width:100%;margin:0 auto;flex:1;min-width:0}
@media (max-width:1000px){
  .hcp .cust__h{padding:0 20px}
  .hcp .cust__b{padding:24px 20px}
}

/* ── command palette ────────────────────────────────────────────────────── */
/* Fixed, not absolute: the prototype sat inside a positioned harness and a real
   page has none, so an absolute palette would scroll away with the document.

   [hidden] is declared explicitly. A class that sets `display` beats the hidden
   ATTRIBUTE, which fails silently and leaves the element permanently open --
   the same defect has been shipped in this codebase before. */
.hcp .pal{position:fixed;inset:0;background:rgba(11,11,16,.42);z-index:60;display:flex;justify-content:center;padding-top:74px}
.hcp .pal[hidden]{display:none}
.hcp .pal__n{padding:22px 16px;font-size:12.5px;color:var(--ink-2);line-height:1.6;border-top:1px solid var(--rule)}
.hcp .pal__n[hidden]{display:none}
.hcp .pal__w{width:min(600px,86%);height:max-content;max-height:440px;background:var(--surface);border:1px solid var(--rule-hard);
  border-radius:14px;box-shadow:0 28px 70px rgba(11,11,16,.34);overflow:hidden;display:flex;flex-direction:column}
.hcp .pal__q{display:flex;align-items:center;gap:10px;padding:14px 16px;border-bottom:1px solid var(--rule)}
.hcp .pal__q svg{width:16px;height:16px;color:var(--dim)}
/* The input intentionally has no border, so focus is carried by the row it sits
   in rather than by an outline on a borderless field. */
.hcp .pal__q input{border:0;outline:0;font:inherit;font-size:15px;flex:1;background:none;color:var(--ink)}
.hcp .pal__q:focus-within{box-shadow:inset 0 -2px 0 var(--accent)}
.hcp .pal__q:focus-within svg{color:var(--accent)}
.hcp .pal__l{overflow:auto;padding:6px 0}
.hcp .pal__g{font-size:9px;letter-spacing:.15em;text-transform:uppercase;color:var(--dim);font-weight:700;padding:9px 16px 5px}
.hcp .pal__i{display:flex;align-items:center;gap:10px;padding:7px 16px;width:100%;font-size:13.5px}
.hcp .pal__i:hover,.hcp .pal__i.on{background:var(--accent-tint)}
.hcp .pal__i .k{margin-left:auto;font-family:var(--mono);font-size:10.5px;color:var(--dim)}
.hcp .pal__i .sub{font-family:var(--mono);font-size:11px;color:var(--dim)}

.hcp .blank{padding:54px 20px;text-align:center;color:var(--dim);display:flex;flex-direction:column;align-items:center;gap:8px}
.hcp .blank h3{font-family:var(--sans);font-size:16px;font-weight:700;letter-spacing:-.012em;color:var(--ink)}
.hcp .blank p{font-size:13px;max-width:46ch;line-height:1.6;color:var(--ink-2)}

/* -- customer surface -----------------------------------------------------
   S2. Two columns while there is room, one when there is not; minmax(0,1fr)
   because a 1fr track's minimum is auto and a long value would otherwise push
   the grid wider than its container.
   ------------------------------------------------------------------------- */
.hcp .pgrid{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:34px;padding-top:22px}
.hcp .dl--wide{grid-template-columns:132px minmax(0,1fr);font-size:13.5px;gap:9px 14px}
/* A value the platform does not have. Italic and --unk, the same way an
   unreported observation reads in the divergence notation, so "no value" looks
   the same everywhere rather than like an empty cell. */
.hcp .miss{color:var(--unk);font-style:italic}
/* -- operator forms -------------------------------------------------------
   Entry had .fld and .inp from the first screen because sign-in is a form.
   Operator mode never needed a multi-field one until the tenant record, which
   carries twenty fields in six groups.

   auto-fill, not auto-fit: auto-fit collapses the empty tracks and stretches a
   lone field the full width of the page, which is what a one-field group would
   have done here.
   ------------------------------------------------------------------------- */
.hcp .fgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));
  gap:0 var(--gut)}
.hcp .fgrid > .fld{margin-bottom:var(--gap)}
.hcp .fld--wide{grid-column:1 / -1}
.hcp .fld__l{display:flex;align-items:baseline;gap:9px;margin-bottom:6px;flex-wrap:wrap}
.hcp .fld__l label{margin-bottom:0}
.hcp .hint{margin-top:6px;font-size:12px;line-height:1.5;color:var(--dim);max-width:52ch}
.hcp .errs{margin:6px 0 0;padding:0;list-style:none;font-size:12px;color:var(--bad);
  font-weight:600;line-height:1.5}

/* The mark on a field whose value the INSTANCE has to converge to, as opposed
   to one only the control plane ever knows. Which fields carry it is decided by
   Tenant.CONVERGING_FORM_FIELDS, and a gate assertion measures that set against
   desired_config() rather than trusting it. */
.hcp .conv{display:inline-flex;align-items:center;gap:5px;padding:1px 7px;
  border:1px solid var(--busy-line, #C9D9F5);border-radius:20px;background:var(--busy-t);
  color:var(--busy);font-size:10px;font-weight:700;letter-spacing:.05em;
  text-transform:uppercase;white-space:nowrap}

.hcp .fset + .fset{margin-top:calc(var(--gap) * 1.4);padding-top:calc(var(--gap) * 1.2);
  border-top:1px solid var(--rule)}
.hcp .fset__h{margin-bottom:calc(var(--gap) * .75)}
.hcp .fset__h h2{font-size:1.02em;font-weight:700;letter-spacing:-.01em}
.hcp .fset__h p{margin-top:4px;font-size:12.5px;color:var(--dim);max-width:64ch;line-height:1.55}

/* The choice component from commit 3, laid along a row for a two-way fork, and
   as a single checkable row. .opt__r exists so the control keeps its own box
   while the label text wraps independently of it. */
.hcp .opts--row{flex-direction:row;flex-wrap:wrap;gap:10px}
.hcp .opts--row .opt{flex:1 1 190px}
.hcp .opt__r{display:flex;align-items:center;flex:0 0 auto}
.hcp .opt__r input{margin:0}
.hcp .opt--check{align-items:center}
/* CASCADE COLLISION, the sixth in this workstream and the first decided by real
   specificity rather than source order. `.hcp .fld label` sets display:block for
   the field label, and an option IS a label, so a choice placed inside a field
   collapsed into a stack: control on one line, text under it, mark under that.
   (0,2,1) beat the component's own (0,2,0).

   Out-specified deliberately rather than reordered, so it cannot be undone by
   someone moving a block. Narrowing `.hcp .fld label` instead would reach every
   Entry screen, which is a bigger change than this defect justifies; recorded
   for the commit 15 cascade audit. */
.hcp .fld label.opt{display:flex}
.hcp .opt--check .conv{margin-left:auto}

.hcp .acts{display:flex;gap:10px;align-items:center;flex-wrap:wrap}

/* -- the tri-state override control ---------------------------------------
   Three mutually exclusive choices per row, in a table, at working density.
   A segmented control rather than three loose radios: the row is answering one
   question, and the three answers are the whole of it.

   label.tri__o and not .tri__o alone, for the reason recorded in commit 5:
   `.hcp .fld label` sets display:block and would flatten it. Stated here at a
   specificity that cannot be undone by moving a block.
   ------------------------------------------------------------------------- */
.hcp .tri{display:inline-flex;border:1px solid var(--rule-hard);border-radius:8px;
  overflow:hidden;background:var(--paper)}
.hcp label.tri__o{display:flex;align-items:center;margin:0;cursor:pointer;
  font-size:12px;font-weight:500;color:var(--ink-2);white-space:nowrap}
.hcp label.tri__o + label.tri__o{border-left:1px solid var(--rule-hard)}
.hcp .tri__o input{position:absolute;opacity:0;width:0;height:0}
.hcp .tri__o span{padding:5px 11px}
.hcp .tri__o:hover span{background:var(--surface);color:var(--ink)}
.hcp .tri__o:has(input:checked) span{background:var(--accent);color:#fff;font-weight:600}
.hcp .tri__o:focus-within span{outline:2px solid var(--accent);outline-offset:-2px}

/* The row is not in its inherited state. Marked on the row, not only in a cell,
   because the point of the screen is which rows this tenant departs from. */
.hcp .tr--ovr td{background:var(--accent-tint)}
.hcp .tbl--feat td{vertical-align:top}
.hcp .tbl--feat td .sub{display:block;margin-top:3px;font-size:11.5px;color:var(--dim);
  line-height:1.45;max-width:34ch;white-space:normal}
.hcp .tbl--feat .st{white-space:nowrap}
/* Off is a known state, so it gets no status shape at all. The five shapes are
   spoken for and none of them means "deliberately not enabled"; borrowing the
   dashed ring would say the platform does not know, which is false.

   BUT NOT --dim EITHER, which is what commit 6 gave it. --dim is the metadata
   tier, and on the feature grid the provenance line sits directly beneath the
   state: "off" over "from SKU BS", both grey, and the two merged into one
   undifferentiated block. Meanwhile every "on" row led with a green mark, so
   the column scanned as marks against smudges rather than as two states.

   --ink-2 is the secondary TEXT tier: it says "this is a value you read", which
   is what a known state is. It does not compete with the green because it is
   not a status colour, and it does not borrow a shape it has no right to. The
   broader question of how many roles --dim carries stays in 3B; this is the one
   place the overload was visible. */
.hcp .s-off{color:var(--ink-2)}

/* -- the settings table ---------------------------------------------------
   It lives in the workspace main column, which is narrower than a full page,
   and one of its values is a URL. Measured at 1280 before this rule: the table
   wanted 882px in roughly 740 and ran 141px past the viewport.

   The value WRAPS rather than the column shrinking or the table scrolling. A
   configuration value is the thing the operator came to read; the established
   priority in this system is to shed or wrap before cutting a value, and there
   is nothing here worth shedding: every column answers part of one question.
   ------------------------------------------------------------------------- */
.hcp .tbl--settings{table-layout:auto}
.hcp .tbl--settings td{white-space:normal;overflow:visible;text-overflow:clip}
/* Scoped to the data row. C3 put a prose panel in this table, and a rule that
   wraps a URL anywhere is right for a value cell and wrong for a sentence. */
.hcp .tbl--settings tr.setr td:nth-child(2){font-family:var(--mono);font-size:.92em;
  overflow-wrap:anywhere;max-width:24ch}
/* break-word, not anywhere: the key already offers its dots as break points
   (the dotted filter), so an arbitrary break is a last resort, not the first
   thing the browser reaches for. */
.hcp .tbl--settings tr.setr td:nth-child(1){overflow-wrap:break-word}
.hcp .tbl--settings tr.setr td:nth-child(4){color:var(--dim);white-space:normal}
/* -- per-setting provenance disclosure (3B.1 C3) --------------------------
   The settings table answers what a value is. This answers why it is that,
   in place, so the reader never leaves the table to find out.

   Two hazards this file has hit before are handled deliberately here. The
   disclosure row is hidden with the hidden attribute and NOTHING below sets
   display on it except the guard, because a display rule on a class has
   silently beaten hidden in this stylesheet already. And the quotation class
   is why__q, not q: .hcp .q is a 46px flex bar elsewhere in this file.
   ------------------------------------------------------------------------- */
.hcp .tbl--settings tr.whyr[hidden]{display:none}

/* The trigger sits on the source, which is the claim it elaborates. It has to
   read as a control without a border: a table of seven bordered buttons would
   turn a reading surface into a form. */
.hcp .whyq{appearance:none;background:none;border:0;padding:0;margin:0;font:inherit;
  color:var(--ink);text-align:left;cursor:pointer;display:inline-flex;align-items:center;gap:6px}
.hcp .whyq::after{content:"";width:5px;height:5px;flex:0 0 5px;
  border-right:1.5px solid var(--dim);border-bottom:1.5px solid var(--dim);
  transform:rotate(45deg) translate(-1px,-1px);transition:transform .12s ease}
.hcp .whyq[aria-expanded="true"]::after{transform:rotate(-135deg) translate(-1px,-1px)}
.hcp .whyq:hover{color:var(--accent-ink)}
.hcp .whyq:hover::after{border-color:var(--accent-ink)}
.hcp .whyq[aria-expanded="true"]{font-weight:600;color:var(--accent-ink)}

/* The open row is a reading panel, not a data row: the fixed row height and
   the nowrap that make the table scannable would make prose unreadable. */
.hcp .tbl--settings tr.whyr{cursor:default}
.hcp .tbl--settings tr.whyr:hover td{background:var(--sunken)}
.hcp .tbl--settings tr.whyr td{height:auto;white-space:normal;background:var(--sunken);
  padding-top:calc(var(--gap) * .7);padding-bottom:calc(var(--gap) * .8)}
.hcp .why{display:flex;flex-direction:column;gap:9px;max-width:76ch}
.hcp .why__lead{font-size:13.5px;line-height:1.6;color:var(--ink);margin:0}
.hcp .why__lead b{font-weight:700}
.hcp .why__why,.hcp .why__rev{font-size:13px;line-height:1.6;color:var(--ink-2);margin:0}
.hcp .why__q{font-style:italic;color:var(--ink)}
.hcp .why__q::before{content:"\201C"}
.hcp .why__q::after{content:"\201D"}
.hcp .why .facts{margin-top:0}

/* Applicable, outranked. Rendered as declarations rather than as an error or a
   history list: same weight of ink as the winner, one step further from the
   eye because it is not what the tenant is getting. */
.hcp .why__also{margin-top:4px;padding-top:9px;border-top:1px solid var(--rule)}
.hcp .why__also .sect__h{margin-bottom:7px}
.hcp .shd{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;
  padding:5px 0;font-size:12.5px;line-height:1.5}
.hcp .shd + .shd{border-top:1px dotted var(--rule)}
.hcp .shd__s{font-weight:600;color:var(--ink-2)}
.hcp .shd__v{color:var(--ink)}
.hcp .shd__m{color:var(--dim);font-size:12px}


/* -- generated files and runbook steps ------------------------------------
   The deployment bundle is the only screen that shows whole files meant to be
   read before they are run, and the only one carrying a numbered runbook a
   person executes by hand.
   ------------------------------------------------------------------------- */
.hcp .steps{margin:0;padding-left:1.35em;display:flex;flex-direction:column;
  gap:calc(var(--gap) * .8);font-size:13px;line-height:1.6;color:var(--ink-2);max-width:78ch}
.hcp .steps li::marker{color:var(--dim);font-weight:700;font-size:12px}
.hcp .steps b{color:var(--ink)}
.hcp .steps code{font-family:var(--mono);font-size:.9em;background:var(--sunken);
  padding:1px 5px;border-radius:4px}

.hcp .cmd{margin-top:7px;padding:10px 12px;border:1px solid var(--rule);border-radius:8px;
  background:var(--chrome);color:#D8D5E8;font-family:var(--mono);font-size:11.5px;
  line-height:1.65;overflow-x:auto;white-space:pre}

.hcp .filed{border:1px solid var(--rule);border-radius:9px;overflow:hidden;
  margin-bottom:var(--gap);background:var(--surface)}
.hcp .filed--secret{border-color:var(--warn-line, #E6D3A8)}
.hcp .filed__h{display:flex;align-items:center;gap:11px;flex-wrap:wrap;
  padding:9px 12px;background:var(--paper);border-bottom:1px solid var(--rule)}
.hcp .filed__n{font-size:12.5px;font-weight:600;color:var(--ink)}
.hcp .filed__d{font-size:11.5px;color:var(--dim)}
.hcp .filed__h .btn{margin-left:auto;margin-top:0}
.hcp .filed__h .conv{background:var(--warn-t);color:var(--warn);border-color:var(--warn-line, #E6D3A8)}
/* The file itself. Capped and scrolled rather than truncated: a compose file is
   two hundred lines and none of it may be silently cut. */
.hcp .filed__b{margin:0;padding:12px;max-height:340px;overflow:auto;
  font-family:var(--mono);font-size:11.5px;line-height:1.6;color:var(--ink-2);
  white-space:pre;background:var(--surface)}
/* min-height is re-declared, not inherited: the legacy .btn--sm is
   unnamespaced and sets min-height:28px, which reaches this markup and
   would quietly override the 26px height. Caught by LegacyBleedTests. */
.hcp .btn--sm{height:26px;min-height:26px;padding:0 11px;font-size:11.5px;border-radius:7px}

.hcp .facts{display:flex;gap:calc(var(--gut) * 1.2);flex-wrap:wrap;margin-top:9px;
  font-size:12.5px}
.hcp .facts div{display:flex;flex-direction:column;gap:2px}
.hcp .facts dt{color:var(--dim);font-size:11px;letter-spacing:.04em;text-transform:uppercase}
.hcp .facts dd{margin:0;font-family:var(--mono);font-size:12px;color:var(--ink)}
/* Contract 1: mono is for MACHINE-produced values. A .facts list is mostly
   hosts, slugs, SKUs and identifiers, so mono is right for the block; on the
   partner record two of its rows are a person's name or address, and setting
   those in mono says they came out of a system. Declared after the base rule
   because it is an exception to it, not a variant of the component. */
.hcp .facts dd.dd--text{font-family:var(--sans);font-size:12.5px}

.hcp .note{font-size:13px;color:var(--ink-2);line-height:1.6;margin-top:10px;max-width:44ch}
.hcp .note--foot{margin-top:26px;font-size:12.5px;color:var(--dim);max-width:64ch;line-height:1.7}
/* An empty state that sits under a heading, not in the middle of a page. */
.hcp .blank--left{align-items:flex-start;text-align:left;padding:34px 0}
.hcp .blank--left p{max-width:56ch}
.hcp .btn--inline{width:auto;padding:0 20px;margin-top:14px}
.hcp .lnk{color:var(--accent-ink);font-weight:600;text-decoration:underline;text-underline-offset:2px}
.hcp .lnk:hover{color:var(--accent)}
/* The legacy sheet already carries .tbl td.right, unprefixed, so it happens to
   reach here too. Declared explicitly so this surface does not depend on a rule
   that retires with base.html. */
.hcp .tbl td.right,.hcp .tbl th.right{text-align:right}
@media (max-width:1000px){
  .hcp .pgrid{grid-template-columns:minmax(0,1fr);gap:26px}
}

/* IN PROGRESS. A control plane's two headline actions -- probe the fleet, run a
   provisioning step -- are both asynchronous, and nothing in the system could
   say "working on it". The diamond already means in-flight; this gives it
   motion, and stops entirely under reduced-motion where the stripe alone
   still reads. */
.hcp .running{position:relative;overflow:hidden}
.hcp .running::after{content:"";position:absolute;left:0;right:0;bottom:0;height:2px;
  background:repeating-linear-gradient(90deg,var(--busy) 0 8px,transparent 8px 16px);
  animation:hcp-run 1.1s linear infinite}
@keyframes hcp-run{to{transform:translateX(16px)}}
.hcp .btn-running{opacity:.75;pointer-events:none;position:relative}
.hcp .btn-running .mk{animation:hcp-pulse 1.1s ease-in-out infinite}
@keyframes hcp-pulse{50%{opacity:.35}}
.hcp .stale{color:var(--warn)}

/* Progressive column shedding. A dense table beside a drawer runs 24px over at
   1280, so rather than overlaying the drawer again -- which re-hides the very
   column the drawer exists to explain -- the table drops its lowest-value
   column, which the drawer is already showing. Shrinking the type instead
   would be the wrong trade. */
@media (max-width:1360px){
  .hcp .main.hasd .tbl thead th:nth-last-child(1),
  .hcp .main.hasd .tbl tbody td:nth-last-child(1){display:none}
}

/* Measured: at an effective 1120px a dense table plus a 366px drawer plus the
   rail leaves the table 184px short. A drawer earns its column only while the
   working surface still fits; below that it goes back to overlaying, which
   costs context but not legibility. */
@media (max-width:1180px){
  .hcp .main.hasd{display:flex;flex-direction:column}
  .hcp .main.hasd > .drawer{position:absolute;top:52px;bottom:0;right:0;
    width:min(366px,84%);box-shadow:-20px 0 48px rgba(22,21,30,.20)}
  /* Only when a band is actually there. The sibling combinator rather than a
     second class, because the band's presence IS the condition and the shell
     already renders it conditionally. 52px is the bar. */
  .hcp .main.hasd > .scoped ~ .drawer{top:calc(52px + var(--band-h))}
  .hcp .inv{grid-template-columns:176px minmax(0,1fr)}
  .hcp .ws{grid-template-columns:242px minmax(0,1fr)}
}
/* Below roughly a thousand effective pixels a fixed side navigation and a
   working surface cannot both be right. The nav becomes a horizontal rail. */
/* ── THE NAVIGATION BREAKPOINT ─────────────────────────────────────────────
   1024 is the contract, and this is the ONLY media block in this stylesheet
   that moves navigation. Above it the sidebar; at 1023 and below, the rail.
   It was 1000, which meant the boundary was undeclared and sat three pixels
   away from the width the supported matrix actually names.
   A gate assertion holds this: exactly one media block may match a navigation
   selector, and its boundary must be 1023. Everything else that responds here
   sheds CONTENT (table columns, the drawer, the facet rail) and may keep its
   own boundary, because a column disappearing is not the shell moving.
   ------------------------------------------------------------------------- */
@media (max-width:1023px){
  /* Two auto rows in a container with a min-height stretch to share it, so the
     rail was taking half the window with nothing in it. The rail takes its own
     height; the working surface takes the rest. */
  .hcp .app,.hcp .app--rail{grid-template-columns:1fr;grid-template-rows:auto minmax(0,1fr);align-content:start}
  /* THE RAIL WRAPS RATHER THAN SCROLLS. Measured at 1023: the rail wanted
     1283px in 1023, so it scrolled, and only FIVE of the eight destinations
     were visible. Demo Codes, Fleet Health and Provisioning sat off the right
     edge with no affordance saying so, and because the group headings were
     hidden here the operator had no cue that Operations existed at all.

     Wrapping fixes it without shrinking anything or shortening a label: the
     groups stay whole, so the break falls between them rather than through one,
     and every destination is on screen. It costs 38px of height and buys back
     three destinations and the group structure.

     The headings come back with it. They were hidden because a single scrolling
     line had no room for them; two lines do, and without them a wrapped rail is
     just eight items in an arbitrary order. */
  /* The rail is a row at the top of the page, so it gives back the full-height
     sticky column the sidebar needs to keep its footer control on screen. */
  .hcp .nav{flex-direction:row;align-items:center;flex-wrap:wrap;row-gap:3px;
    align-content:start;overflow-x:visible;gap:6px;padding-right:12px;
    position:static;height:auto;overflow-y:visible}
  .hcp .nav__b{border-bottom:0;border-right:1px solid var(--chrome-rule);flex:0 0 auto}
  .hcp .nav__g h5{display:flex;align-items:center;margin:0;padding:0 7px 0 3px;
    font-size:9px;letter-spacing:.13em;white-space:nowrap;flex:0 0 auto}
  /* The scope control lives in the light bar and the bar does not fold, so this
     block no longer moves it: it compacts it. The verb goes, because at this
     width the bar is carrying a breadcrumb, a command palette and an identity
     in the same row and the value is what the operator needs; the panel still
     says "Viewing" in full when it opens. Never hidden. An operator who cannot
     change product cannot work, and hiding this is what the version before last
     did below 1000px.

     The one thing that moves here is the OPERATOR'S collapse control, which is
     hidden because at this width the viewport decides. Hidden, not disabled:
     the stored desktop preference is untouched and comes back with the width.
     Both selectors are navigation furniture, so they belong in this block and
     nowhere else. */
  .hcp .prod__lbl{display:none}
  .hcp .prod__c{max-width:210px}
  .hcp .prod__l{min-width:min(290px,86vw)}
  .hcp .nav__f{display:none}
  .hcp .nav__g{display:flex;align-items:center;padding:0;flex:0 0 auto;gap:2px}
  .hcp .nav__g + .nav__g{padding-top:0}
  .hcp .nl{white-space:nowrap}
  .hcp .nl.on::before{left:0;right:0;top:auto;bottom:-2px;width:auto;height:2px;border-radius:0}
  .hcp .ws,.hcp .inv{grid-template-columns:1fr}
  .hcp .wsr,.hcp .facets{border-right:0;border-bottom:1px solid var(--rule)}
}

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{transition-duration:.01ms !important;animation-duration:.01ms !important}
  .hcp .running::after{animation:none}
  .hcp .btn-running .mk{animation:none;opacity:.55}}

/* MEASURED, and it inverts the obvious assumption: the narrowest this table
   ever gets is 1024, not 853. Between 1024 and 1180 the navigation is still
   240px AND the facet rail is still 208px, which leaves the trail 576px; at
   1023 the navigation becomes a rail and the facets become a strip, so the
   table gets the whole window back. So the facets fold at 1180, where a side
   column stops earning its width everywhere else in this system, rather than at
   the navigation boundary. */
/* ── THE TENANT LIST'S COLUMN PRIORITY ─────────────────────────────────────
   Written down because it was got wrong by omission: the table had no width
   rules at all, so at 1152 it overflowed and the column that fell off the right
   edge was LIFECYCLE, a primary state, while Product survived. Nothing decided
   that; it was simply the last column in source order.

   Highest first. Shed from the bottom.

     1. Health        the attention signal, and the reason to look at all
     2. Deployment    identity; without it no other cell can be attributed
     3. Lifecycle     active, suspended, provisioning. A primary state
     4. Configuration declared against observed, the subject of this product
     5. Expiry        commercial state, and it is dated
     6. SKU           the tier
     7. Product       LOWEST, and redundant: the product switcher in the
                      navigation already scopes this view, and it names the
                      product above the table either way

   Product sheds at 1180, which is where every other table in this system gives
   up a column, and it stays shed below that. A column that reappears as the
   window narrows is harder to trust than one that is simply gone. */
/* Scoped to tbl--tenants, and the scoping is the point. Written as
   ".hcp .main .tbl" this rule shed the THIRD COLUMN OF EVERY TABLE in the main
   region below 1180: the audit log lost Action, the feature matrix lost
   Override for this tenant, the settings table lost Source, operators lost What
   it can do. A column priority is a statement about one table's columns and
   cannot be written against a generic class. */
@media (max-width:1180px){
  .hcp .main .tbl--tenants th:nth-child(3),
  .hcp .main .tbl--tenants td:nth-child(3){display:none}
}

@media (max-width:1180px){
  /* The timestamp was being cut to "23 Aug 2026 1...". A truncated value is
     worse than a missing column, so the operator column sheds instead: it is
     also a facet, so nothing becomes unreachable. */
  .hcp .invm .tbl th:nth-child(5),.hcp .invm .tbl td:nth-child(5){display:none}
  /* Measured: the widest timestamp needs 157px at 13px JetBrains Mono plus the
     cell's 24px of padding. 164 so it is never the value that gets cut, because
     in an investigation the time is the anchor. Action and deployment may
     ellipsise: both are also facets, where the full label is on screen. */
  .hcp .invm .tbl th:nth-child(2),.hcp .invm .tbl td:nth-child(2){width:164px}
  .hcp .invm .tbl th:nth-child(3),.hcp .invm .tbl td:nth-child(3){width:186px}
  .hcp .invm .tbl th:nth-child(4),.hcp .invm .tbl td:nth-child(4){width:150px}
  .hcp .inv{grid-template-columns:1fr;grid-template-rows:auto minmax(0,1fr)}
  .hcp .facets{border-right:0;border-bottom:1px solid var(--rule);flex-direction:row;
    flex-wrap:wrap;align-items:flex-start;gap:14px;max-height:196px}
  .hcp .facet{flex:1 1 180px}
}

/* -- declaring, at either scope (3B.1 C4) ---------------------------------
   The write sits inside the disclosure that explains the value, so the reader
   has the answer before the control. Bordered off from the prose above it:
   everything above is a statement about what IS, everything inside is a
   proposal about what would be.
   ------------------------------------------------------------------------- */
.hcp .decl{margin-top:4px;padding-top:10px;border-top:1px solid var(--rule);
  display:flex;flex-direction:column;gap:9px}
.hcp .decl__g{display:flex;gap:var(--gut);flex-wrap:wrap}
.hcp .decl__f{display:flex;flex-direction:column;gap:4px;min-width:0;flex:1 1 15rem}
.hcp .decl__f .in{width:100%}
.hcp .decl__a{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.hcp .decl__n{font-size:12px;color:var(--dim)}
/* The reach, stated on the control rather than after it. */
.hcp .decl__w{margin:0;font-size:13px;line-height:1.6;color:var(--ink-2)}
.hcp .decl__w b{color:var(--ink);font-weight:700}
/* No .btn--sm here. It is already declared earlier in this file, and a second
   declaration at the same specificity would be the equal-specificity override
   this stylesheet has been bitten by before. The declaration controls use the
   established vocabulary: .btn .btn--inline .btn--sm, with .btn--quiet for the
   secondary. .btn--primary is NOT namespaced and would bleed legacy rules. */
