/*
  BuildWorld — base stylesheet
  ═══════════════════════════════════════════════════════════════════════════

  One file, two halves, loaded before anything else on every page:

    1. TOKENS      — the three faces, the colour ramps, the semantic UI roles.
    2. TYPOGRAPHY  — a fluid root, then one `text-*` class per text style.

  Was tokens.css + typography.css; merged so a page has a single base to
  link and there is no load-order question between them.

  ── HOW TO USE ───────────────────────────────────────────────────────────
  Colour: reach for a semantic role (--text, --muted, --line, --accent)
  before a raw ramp step. Type: pick a `text-*` class and apply it to the
  element. Never assemble a text style out of loose properties — every one
  of the classes below already sets all six (family, size, weight, tracking,
  leading, case), so a class is always complete and never inherits a
  surprise.

  ── WHAT THIS REPLACED ───────────────────────────────────────────────────
  118 typography-bearing rules scattered across index.html's <style> block
  and designer.css, between them using 21 font-sizes, 16 letter-spacings and
  5 different resolutions of 3 family tokens — two of which were never
  actually loaded on the page that declared them.
*/

/* ═══════════════════════════════════════════════════════════════════════
   1 · TOKENS
   ═══════════════════════════════════════════════════════════════════════ */

:root {
  /* ── Fonts ───────────────────────────────────────────────── */
  --font-heading: "Newsreader", Georgia, "Times New Roman", serif;
  --font-body: "Figtree", system-ui, -apple-system, sans-serif;
  /* Not requested, but a real third role in index.html (nav/labels/buttons) — kept as a bonus alias. */
  --font-mono: "Geist Mono", ui-monospace, monospace;

  /* ── Font sizes ──────────────────────────────────────────────
     Font SIZES are not tokens. Every text style in the system is
     defined whole — family, size, weight, tracking, leading, case — as a
     semantic `text-*` class in part 2 below. Pick a class; don't
     assemble a style out of loose size tokens.

     Removed in that pass:
       --font-size-2xs/xs/sm/md/lg/xl/2xl/4xl  (the marketing px steps)
       --fs-1 … --fs-8                          (the dense-UI rem steps)
       --font-size-root: 13px                   (the Designer's root pin)

     The 13px root is worth calling out: it made `rem` mean 13px on that
     page, which quietly overrode whatever base font size the reader had
     set in their browser. Part 2 sizes against a fluid root that honours
     that preference instead — see the FLUID ROOT note there. The scale
     floors at 0.575rem / 9.2px. */

  /* ── Neutral ramp (ink → paper) — 00 darkest, 100 lightest ── */
  --color-neutral-00: #17160f; /* --ink, primary text */
  --color-neutral-00-alpha-05: #17160f0d;
  --color-neutral-00-alpha-10: #17160f1a;
  --color-neutral-00-alpha-75: #17160fbf; /* 0.75 × 255 = 191 = 0xbf */
  --shadow-panel:
    var(--color-neutral-00-alpha-05) 0px 6px 24px 0px,
    var(--color-neutral-00-alpha-10) 0px 0px 0px 1px;
  --shadow-sheet-inset:
    inset 0px 6px 24px 0px var(--color-neutral-00-alpha-05),
    inset 6px 0px 24px 0px var(--color-neutral-00-alpha-05),
    inset 0px 0px 0px 1px var(--color-neutral-00-alpha-10);
  --color-neutral-20: #72716c; /* --grey, muted text */
  --color-neutral-40: #acaaa6; /* --line2, stronger border */
  --color-neutral-60: #e3e1da;
  --color-neutral-80: #faf9f7; /* updated */
  --color-neutral-100: #f3f4f6; /* updated — note: slightly darker than 80, see file header */
  /* In-between shades that exist on the page but don't fit a 6-step ramp: */
  /* --ink-soft #34322A (sits between 00/20), --paper2 #ECEADF (sits between 60/80) */

  /* ── Primary ramp (indigo) — 00 darkest, 100 lightest ────── */
  --color-primary-00: #0f0050; /* interpolated — deep anchor */
  --color-primary-20: #15006c; /* interpolated */
  --color-primary-40: #1a0088; /* main accent — given value */
  --color-primary-60: #604fad; /* interpolated */
  --color-primary-80: #a59fd1; /* interpolated */
  --color-primary-100: #ebeef6; /* pale tint anchor */

  /* ── Semantic — UI roles ─────────────────────────────────── */
  /* Promoted from the Designer app's own theming layer (paper/film/ink/
     dimc/hairl/steel/steel-deep) so any page can share one semantic
     vocabulary — bg/surface/text/accent — instead of re-inventing it. */
  --bg: var(--color-neutral-80);
  --canvas: var(--color-neutral-80);
  --surface: var(--color-neutral-80);
  --text: var(--color-neutral-00);
  --muted: var(--color-neutral-20);
  --faint: var(--color-neutral-60);
  --line: var(--color-neutral-60);
  --accent: var(--color-primary-40);
  --accent-hover: var(--color-primary-20);
  --button-hover-border: var(--accent);
  --button-hover-bg: var(--color-primary-100);
  --button-primary-hover-border: var(--color-primary-00);
  --button-primary-hover-bg: var(--color-primary-00);
  --info: #fef4e1;
  --info-border: #e6c98e;

  /* ── Semantic — data states ──────────────────────────────── */
  /* Not present on the homepage today (no data/status UI) — new, tuned to the paper/ink palette. */
  --color-positive: #2e6b44;
  --color-negative: #b23b2e;

  /* ── Line height ─────────────────────────────────────────── */
  --line-height-xs: 1.06; /* h1, h2, h3 */
  --line-height-sm: 1.26; /* .thesis p */
  --line-height-md: 1.34; /* .shift p */
  --line-height-lg: 1.5; /* general body copy default */
  --line-height-xl: 1.6; /* body base, loosest */

  /* ── Letter spacing ──────────────────────────────────────── */
  --letter-spacing-2xs: -0.02em; /* tightest display tracking */
  --letter-spacing-xs: -0.01em; /* tight mono/display tracking */
  --letter-spacing-sm: 0em; /* paragraph default */
  --letter-spacing-md: 0.05em; /* .foot .meta, light label tracking */
  --letter-spacing-lg: 0.05em; /* .step .num, mono tag tracking */
  --letter-spacing-xl: 0.05em; /* .eyebrow, widest */
}

/* ═══════════════════════════════════════════════════════════════════════
   2 · TYPOGRAPHY
   ═══════════════════════════════════════════════════════════════════════

   ONE definition per text style. Every class sets all six properties, so
   nothing is inherited by accident and no rule anywhere else needs to touch
   type. (font-style appears on the two italic classes only.)

   ── SCALE ──────────────────────────────────────────────────────────────
   Everything is rem, against a FLUID root that interpolates 14px -> 16px
   across a 360px -> 1280px viewport. The whole system breathes with the
   screen from one number, and no class needs its own media query.

   Sizes are quoted at the 16px (wide) end; multiply by 0.875 for the 14px
   (narrow) end — e.g. 0.575rem is 9.2px wide, ~8px narrow.

      0.5750rem =  9.2px the floor — text-ui-xs and everything smaller
      0.6250rem = 10px   text-ui-sm
      0.7500rem = 12px   text-ui
      0.8750rem = 14px   text-body-sm
      1.0000rem = 16px   text-quote, text-body
      display sizes are fluid clamps on top of that

      (the action/data/stamp mono families keep their own separate sizes
      — 15/13/12/10px — unaffected by the body/ui scale above)

   ── TRACKING ───────────────────────────────────────────────────────────
   Only six letter-spacing values exist anywhere in this file: -0.02em,
   -0.01em, 0, 0.01em, 0.02em, 0.05em. Within the tracked-uppercase mono
   families (label/section/action/data/stamp), tracking runs inverse to
   size — the smaller the type, the wider the spacing, since tight tracking
   on already-small caps hurts legibility:

      0.01em   15px   text-action-lg, text-data-lg
      0.02em   12-13px text-action, text-action-sm, text-data, text-stamp
      0.05em    9-10px text-label-*, text-section, text-data-sm

   No class re-floors or re-ceilings itself in px (e.g. `max(0.575rem, 9.2px)`) —
   that would fight the root and reintroduce a fixed pixel value into a
   system that's supposed to be rem all the way down. The FLOOR and CEILING
   of the whole scale are exactly one clamp, on `html`, below — if the
   smallest tier needs a harder floor than the root currently gives it,
   raise the root's own minimum there, not per class.

   line-height and letter-spacing are both em — relative to each class's own
   font-size, so a class stays internally proportional at any root size.
   (Caveat: unlike a unitless line-height, an em line-height inherits as a
   fixed length. Harmless here because every text-* class sets font-size and
   line-height together — but if you add a class that sets only one, set both.)

   ── THE THREE FACES ────────────────────────────────────────────────────
   --font-heading  Newsreader   display only. Headlines and pull-quotes.
                                Weight 500, negative tracking, never caps.
   --font-body     Figtree      running copy and interface text.
   --font-mono     Geist Mono   everything tracked-out and uppercase: labels,
                                actions, and the drafting-sheet data readouts.

   Case lives in CSS, not in markup. If a class says uppercase, write the
   markup in sentence case and let the class shout.

   ── THE CLASSES ────────────────────────────────────────────────────────
   text-display-1..4     fluid serif headlines
   text-heading-1..2     fixed serif headings
   text-quote            serif italic pull-quote
   text-body-lg/-/-sm    running copy
   text-ui/-sm/-xs       interface text (controls, inputs, menus)
   text-note             smallest explanatory copy
   text-label-lg..xs     tracked uppercase labels, 11 -> 8px
   text-section          panel / section header (label weight 700, widest track)
   text-action-lg/-/-sm  buttons and card titles
   text-data-lg/-/-sm    numeric + title-block readouts
   text-stamp            the drawing-sheet issue stamp

   Legacy component selectors are joined onto each class rather than
   redeclared, so JS-generated nodes (plans list, floor rows, BOQ body, SVG
   canvas annotation) share the exact same definition without needing a
   class attribute threaded through their templates.
   ═══════════════════════════════════════════════════════════════════════ */

/* ═══ FLUID ROOT ═════════════════════════════════════════════════════
   One number drives the whole scale: 14px on a 360px-wide screen, ramping
   linearly to 16px at 1280px, clamped flat outside that range.

   Stated in rem, deliberately. On the root element `rem` resolves against
   font-size's INITIAL value — i.e. whatever the reader set as their browser
   default — so this stays fluid AND still honours that preference. A px
   clamp here would look identical but would silently override it, which is
   the bug the old `html { font-size: 13px }` pin used to cause.

     min   0.875rem   = 14px   @ ≤360px viewport
     max   1rem       = 16px   @ ≥1280px viewport
     slope 0.2174vw   = (16-14) / (1280-360) × 100
     y-int 0.8261rem  = 14px − 0.2174vw × 360px                            */

html {
  font-size: clamp(0.875rem, 0.8261rem + 0.2174vw, 1rem);
}

input:focus,
input:focus-visible,
select:focus,
select:focus-visible,
textarea:focus,
textarea:focus-visible,
[contenteditable="true"]:focus,
[contenteditable="true"]:focus-visible {
  outline: none !important;
}

/* ═══ DISPLAY — Newsreader, weight 500, negative tracking, never caps ═══ */

.text-display-1 {
  font-family: var(--font-heading);
  font-size: clamp(2.375rem, 6.4vw, 5.125rem); /* 38 → 82px */
  font-weight: 500;
  letter-spacing: -0.02em;
  line-height: 1.06em;
  text-transform: none;
}

.text-display-2 {
  font-family: var(--font-heading);
  font-size: clamp(1.6875rem, 4vw, 2.75rem); /* 27 → 44px */
  font-weight: 500;
  letter-spacing: -0.01em;
  line-height: 1.06em;
  text-transform: none;
}

.text-display-3 {
  font-family: var(--font-heading);
  font-size: clamp(1.375rem, 3.4vw, 2.375rem); /* 22 → 38px */
  font-weight: 500;
  letter-spacing: -0.01em;
  line-height: 1.26em;
  text-transform: none;
}

.text-display-4 {
  font-family: var(--font-heading);
  font-size: clamp(1.25rem, 2.7vw, 1.875rem); /* 20 → 30px */
  font-weight: 500;
  letter-spacing: -0.01em;
  line-height: 1.34em;
  text-transform: none;
}

.text-heading-1 {
  font-family: var(--font-heading);
  font-size: 1.625rem; /* 26px */
  font-weight: 500;
  letter-spacing: -0.01em;
  line-height: 1.1em;
  text-transform: none;
}

/* absorbs the old 23px .step h3 and 22px .foot .mk — one step, not three */
.text-heading-2 {
  font-family: var(--font-heading);
  font-size: 1.375rem; /* 22px */
  font-weight: 500;
  letter-spacing: -0.01em;
  line-height: 1.1em;
  text-transform: none;
}

.text-quote {
  font-family: var(--font-heading);
  font-size: 1rem; /* 16px */
  font-weight: 400;
  font-style: italic;
  letter-spacing: 0;
  line-height: 1.4em;
  text-transform: none;
}

/* ═══ BODY — Figtree ═════════════════════════════════════════════════ */

.text-body-lg {
  font-family: var(--font-body);
  font-size: clamp(1.0625rem, 2.1vw, 1.3125rem); /* 17 → 21px */
  font-weight: 400;
  letter-spacing: 0;
  line-height: 1.5em;
  text-transform: none;
}

.text-body {
  font-family: var(--font-body);
  font-size: 1rem; /* 16px */
  font-weight: 400;
  letter-spacing: 0;
  line-height: 1.6em;
  text-transform: none;
}

/* absorbs the old 15px / 15.5px pair (.step p, .spec .v, .aud p) */
.text-body-sm {
  font-family: var(--font-body);
  font-size: 0.875rem; /* 14px */
  font-weight: 400;
  letter-spacing: 0;
  line-height: 1.5em;
  text-transform: none;
}

/* the interface default: buttons, menu items, inputs, nav links.
   absorbs index's 13.5px nav/textlink and the Designer's 13px + 14px tiers */
.text-ui,
.menu-item,
.inspector-value,
.inspector input,
#room-popover select,
#wall-popover select,
#bw-plans-menu .bw-plan-actions button {
  font-family: var(--font-body);
  font-size: 0.75rem; /* 12px */
  font-weight: 400;
  letter-spacing: 0.01em;
  line-height: 1.5em;
  text-transform: none;
}
.cbtn,
.cbtn .label,
.menu-item,
#bw-plans-menu .bw-plan-actions button,
#bw-site-panel .brg-row button {
  font-family: var(--font-mono);
}

/* also the default inherited size inside every Designer step panel — plain
   text and inputs in there land on this without needing their own class */
.text-ui-sm,
.inspector-label,
.placement-item,
.d3-layer,
.d3-controls .label,
#bw-panel,
#bw-tools-panel,
#bw-site-panel,
#ref-panel,
.bw-plans-inner,
#bw-plans-list .del {
  font-family: var(--font-body);
  font-size: 0.625rem; /* 10px */
  font-weight: 500;
  letter-spacing: 0;
  line-height: 1.4em;
  text-transform: none;
}

.text-ui-xs,
.menu-item .hint,
.inspector .unit,
#ref-panel button,
#bw-plans-menu .cloud {
  font-family: var(--font-body);
  font-size: 0.575rem; /* 9.2px */
  font-weight: 400;
  letter-spacing: 0;
  line-height: 1.4em;
  text-transform: none;
}

.text-note,
#bw-panel .note,
#bw-site-panel .note,
.bw-cards .d,
.bw-devtype-body .d {
  font-family: var(--font-body);
  font-size: 0.575rem; /* 9.2px */
  font-weight: 400;
  letter-spacing: 0;
  line-height: 1.45em;
  text-transform: none;
}

/* ═══ LABEL — Geist Mono, tracked, uppercase ═════════════════════════ */

/* eyebrows, section tags, spec keys, bylines */
.text-label-lg,
.d3-layers-title {
  font-family: var(--font-mono);
  font-size: 0.575rem; /* 9.2px */
  font-weight: 500;
  letter-spacing: 0.05em;
  line-height: 1.3em;
  text-transform: uppercase;
}

/* The SITE→PRESENT rail. Body face at 0.75rem rather than the tracked mono
   the other tab strips use — it is the app's top-level navigation, not
   chrome on a tool, and it is already outside the two BUTTON sizes below
   for the same reason its icon-over-label box is. */
#bw-rail .nm {
  font-family: var(--font-body);
  font-size: 0.75rem; /* 12px */
  font-weight: 400;
  letter-spacing: 0.05em;
  line-height: 1.3em;
  text-transform: uppercase;
}

.text-label,
.bw-seg button,
.bw-detached-control,
#bw-site-panel .lk,
#bw-site-panel .status,
#bw-plans-list .empty,
.status .item .key {
  font-family: var(--font-mono);
  font-size: 0.575rem; /* 9.2px */
  font-weight: 500;
  letter-spacing: 0.05em;
  line-height: 1.3em;
  text-transform: uppercase;
}

/* tool-palette labels, floor rows, sheet tabs — tracking eases off here so
   two-word labels ("Wall ext", "Trace plan") still fit a 3-column grid. */
.text-label-sm,
.bw-tools button,
.bw-tools label.bw-tool-button,
#bw-sheets button {
  font-family: var(--font-mono);
  font-size: 0.575rem; /* 9.2px */
  font-weight: 500;
  letter-spacing: 0.05em;
  line-height: 1.3em;
  text-transform: uppercase;
}

/* The floor of the system — title-block keys and setback field labels. */
.text-label-xs,
#bw-tblock .k,
#bw-site-panel .sb-grid label,
#bw-site-panel .sb-grid em,
.bw-field-label,
.bw-addr-edit {
  font-family: var(--font-mono);
  font-size: 0.575rem; /* 9.2px */
  font-weight: 500;
  letter-spacing: 0.05em;
  line-height: 1.3em;
  text-transform: uppercase;
}

/* Shared section headers across every panel. */
.text-section,
#bw-panel .hd,
#bw-site-panel .hd,
.tool-section-hd,
#bw-plans-menu .lh {
  font-family: var(--font-body);
  font-size: 0.625rem;
  font-weight: 800;
  letter-spacing: 0.05em;
  line-height: 1.5em;
  color: var(--color-neutral-00);
  text-transform: uppercase;
}

/* ═══ ACTION — Geist Mono, bold. Buttons and card titles. ════════════
   These were Newsreader 700/800 until now. The serif is display-only in
   this system, so they moved onto the mono face they sit beside anyway. */

.text-action-lg {
  font-family: var(--font-mono);
  font-size: 0.9375rem; /* 15px */
  font-weight: 700;
  letter-spacing: 0.01em;
  line-height: 1.2em;
  text-transform: uppercase;
}

/* Card / dev-type title: the main label of a two-line button, so it takes
   the button's own size rather than a size of its own (see BUTTON below). */
.bw-cards .t,
.bw-devtype-body .t,
.bw-floor-label {
  font-family: var(--font-mono);
  font-size: inherit;
  letter-spacing: 0.01em;
  line-height: 1.2em;
  text-transform: uppercase;
}

.text-action,
.bw-act button,
.bw-act label,
#bw-tblock .brand .b1 {
  font-family: var(--font-mono);
  font-size: 0.8125rem; /* 13px */
  font-weight: 700;
  letter-spacing: 0.02em;
  line-height: 1.2em;
  text-transform: uppercase;
}

/* absorbs index's .btn / .nav-cta / .aud .arrow (12.5px, weight 500) and the
   Designer's .go / #bw-plan-view-all / 2D-3D toggle — all one role */
.text-action-sm,
#bw-plan-view-all,
#bw-site-panel .go,
#bw-view button {
  font-family: var(--font-mono);
  font-size: 0.75rem; /* 12px */
  font-weight: 600;
  letter-spacing: 0.02em;
  line-height: 1.2em;
  text-transform: uppercase;
}

.text-action-xs {
  font-family: var(--font-mono);
  font-size: 0.625rem; /* 10px */
  font-weight: 600;
  letter-spacing: 0.02em;
  line-height: 1.2em;
  text-transform: uppercase;
}

/* Checkbox / radio label. The one control label that stays in the body
   face and in sentence case — it is a sentence the user reads and agrees
   with ("This site has setbacks"), not a tracked-out spec key. */
.text-checkbox-label,
.bw-sb-label,
#bw-site-panel .sb-row label {
  font-family: var(--font-body);
  font-size: 0.875rem; /* 14px */
  font-weight: 400;
  letter-spacing: 0;
  line-height: 1.4em;
  text-transform: none;
}

/* ═══ BUTTON — one geometry, two sizes ═══════════════════════════════
   Every button and segmented button takes 0.75em 1em on its ROOT. It is
   em, not px, so the box tracks whichever of the two text sizes the
   button carries — and the main label is exactly one of:

     0.875rem   btn-action — anything pressed to DO something
     0.625rem   btn-label  — dense tool / tab / segment / rail chrome

   Nothing in between. The sizes that used to sit between the pair
   (0.575, 0.6875, 0.75, 0.8125, 0.9375 and 1rem) were rounded to the
   nearer of the two; the 0.75rem exact ties were broken by role, which
   is the same thing the two sizes encode.

   A second line under the main label (.btn-sub — the `.d` descriptor on
   card and dev-type rows) is 0.625em of its OWN button's root, so it
   stays proportional whichever size the button took, tracked 0.01em. It
   is neutral-20 at rest and primary-60 both on hover and while the
   button is active/selected.

   Exclusions, all deliberate: icon-only squares (.cbtn.icon-only, the
   title-block/undo-redo/floor-act icon buttons, .bw-help-ic) keep their
   own square padding — there is no label for 1em to sit beside; the
   SITE→PRESENT rail keeps `1em 1em 3px` because its icon and label
   stack vertically; .bw-tool-palette buttons keep padding 0 because the
   bordered box there is the icon tile, not the button.             */

.btn-action,
.bw-act button,
.bw-act label,
.bw-btn,
.bw-cards button,
.bw-floor-row,
.bw-devtype-row,
.bw-addr-box,
.bw-import-plan-loaded button,
.bw-addr-dialog__suggestions button,
.bw-dialog__actions button,
.cbtn,
#bw-view button,
#bw-site-panel .go,
#bw-plan-view-all,
#bw-import-plan-btn,
#bw-plans-menu .bw-plan-actions button,
#ref-panel button {
  font-size: 0.875rem; /* 14px */
}

.btn-label,
.bw-seg button,
.bw-seg select,
.bw-tools button,
.bw-tools label.bw-tool-button,
.bw-tool-palette button,
.bw-tool-palette label.bw-tool-button,
.bw-detached-control,
.mode-tabs .cbtn,
.level-switch .lvl-btn,
.cbtn-copy,
.cbtn-subtle-sm,
#bw-sheets button {
  font-size: 0.625rem; /* 10px */
}

/* The shared box. Same list as the two above, minus the exclusions
   named in the header comment. */
.btn-action,
.btn-label,
.bw-act button,
.bw-act label,
.bw-btn,
.bw-cards button,
.bw-floor-row,
.bw-devtype-row,
.bw-addr-box,
.bw-seg button,
.bw-seg select,
.bw-tools button,
.bw-tools label.bw-tool-button,
.bw-addr-dialog__suggestions button,
.bw-dialog__actions button,
.cbtn:not(.icon-only),
#bw-view button,
#bw-site-panel .go,
#bw-sheets button,
#bw-import-plan-btn,
#bw-plans-menu .bw-plan-actions button,
#ref-panel button {
  padding: 0.75em 1em;
}

/* ── primary ──────────────────────────────────────────────────────────
   The one affirmative action in a group: solid accent at rest — plate,
   border and label colour together — where every other button in the
   system is an outline. Hover darkens through the primary-hover list
   below; disabled falls through to the shared grey plate, which is right
   here precisely because a primary IS a plate (the opposite of ghost).

   The dialog confirm is qualified with `button` for the same reason its
   hover is: bare `.bw-dialog__confirm` is (0,1,0) and loses to the generic
   `.bw-dialog__actions button` at (0,1,1) that sets the outline look — so
   the confirm button has been rendering as a plain secondary all along. */
.btn-primary,
.bw-dialog__actions button.bw-dialog__confirm {
  background: var(--accent);
  border: 1px solid var(--accent);
  color: var(--color-neutral-100);
}

/* Primary, disabled. It needs its own rule rather than falling through to
   the shared plate at the foot of designer.css: that is `button:disabled` at
   (0,1,1), while the fill above is (0,1,0)/(0,2,1) — so on the dialog confirm
   the accent won and a disabled primary rendered as a live one.

   The :hover twins are not redundant either. `.btn-primary:disabled` is
   (0,2,0) and loses to `button:disabled:hover` at (0,2,1) the moment the
   pointer crosses it; (0,3,0) settles it. Same declaration both ways —
   a disabled button has no hover state. */
.btn-primary:disabled,
.btn-primary:disabled:hover,
.btn-primary.is-disabled,
.btn-primary.is-disabled:hover,
.bw-dialog__actions button.bw-dialog__confirm:disabled,
.bw-dialog__actions button.bw-dialog__confirm:disabled:hover,
.bw-dialog__actions button.bw-dialog__confirm.is-disabled,
.bw-dialog__actions button.bw-dialog__confirm.is-disabled:hover {
  background: var(--color-neutral-40);
  border: 1px solid var(--color-neutral-40);
  color: var(--color-neutral-60);
  cursor: not-allowed;
}

/* ── ghost ────────────────────────────────────────────────────────────
   A button with no box. Transparent at every state — including disabled,
   which is the whole point of the token: the shared disabled treatment
   fills a grey plate, and on a bare text button that plate reads as a
   broken control rather than as an inactive label. Here only the text
   colour moves, accent → neutral-40. */
.btn-ghost,
.bw-floor-add {
  padding: 0;
  background: none;
  border: none;
  color: var(--accent);
}
.btn-ghost:hover:not(:disabled):not(.is-disabled),
.bw-floor-add:hover:not(:disabled):not(.is-disabled) {
  background: none;
  border-color: transparent;
  color: var(--accent-hover);
}
/* (0,2,0) — outranks the `button:disabled` plate at (0,1,1) below. */
/* The :hover pairs are the same declaration as the resting state — a
   disabled ghost must not pick up the global disabled plate from
   `button:disabled:hover`, which at (0,2,1) would otherwise outrank the
   (0,2,0) resting rule the moment the pointer crossed it. */
.btn-ghost:disabled,
.btn-ghost:disabled:hover,
.btn-ghost.is-disabled,
.btn-ghost.is-disabled:hover,
.bw-floor-add:disabled,
.bw-floor-add:disabled:hover,
.bw-floor-add.is-disabled,
.bw-floor-add.is-disabled:hover {
  background: none;
  border-color: transparent;
  color: var(--color-neutral-40);
  cursor: not-allowed;
}

/* ── primary hover ────────────────────────────────────────────────────
   The darkening a SELECTED solid button takes when hovered. Deliberately
   an explicit list rather than a shared class, because two families must
   never receive it:

     ghost buttons — there is no plate to darken; .btn-ghost above keeps
       every state transparent and moves only the text colour.
     tool buttons  — `.bw-tools button`, which #bw-build-seg also carries
       via .bw-tool-palette. The bordered, filled box in a tool button is
       the .tool-icon tile INSIDE it, so filling the container paints a
       second plate around the tile.

   The confirm selector is qualified with `button` on purpose: unqualified
   it is (0,3,0) and loses to the generic `.bw-dialog__actions button:hover`
   at (0,3,1) sitting right above it. */
.btn-primary:hover:not(:disabled):not(.is-disabled),
.bw-dialog__actions button.bw-dialog__confirm:hover:not(:disabled):not(.is-disabled),
.bw-seg button.on:hover:not(:disabled):not(.is-disabled),
.cbtn.active:hover:not(:disabled):not(.is-disabled),
#bw-view button.on:hover:not(:disabled):not(.is-disabled),
#bw-sheets button.on:hover:not(:disabled):not(.is-disabled) {
  border-color: var(--button-primary-hover-border);
  background: var(--button-primary-hover-bg);
  color: var(--color-primary-100);
}

.btn-sub,
.bw-cards .d,
.bw-devtype-body .d {
  font-size: 0.625em;
  letter-spacing: 0.01em;
}

/* Sub-text answers to its button's state, not its own — hovering or
   selecting the button lifts the descriptor with it. */
.btn-action:hover:not(:disabled):not(.is-disabled) .btn-sub,
.btn-label:hover:not(:disabled):not(.is-disabled) .btn-sub,
.btn-action.on .btn-sub,
.btn-label.on .btn-sub,
.bw-cards button:hover:not(:disabled):not(.is-disabled) .d,
.bw-cards button.on .d {
  color: var(--color-primary-60);
}

button,
[role="button"],
label.bw-tool-button {
  font-family: var(--font-mono);
  text-transform: uppercase;
}

/* Reusable in-page alert / confirm / prompt shell. Visual styling stays
   intentionally restrained until the component direction is approved. */
.bw-dialog {
  position: fixed;
  inset: 0;
  width: min(28rem, calc(100vw - 2rem));
  max-height: calc(100dvh - 2rem);
  margin: auto;
  padding: 0;
  overflow: auto;
  background: var(--color-neutral-80);
  border: 1px solid var(--color-neutral-20);
  color: var(--color-neutral-00);
  transform-origin: center;
}
.bw-dialog[open] {
  animation: bw-dialog-in 180ms cubic-bezier(0.2, 0.8, 0.2, 1) both;
}
.bw-dialog[open].is-closing {
  animation: bw-dialog-out 150ms cubic-bezier(0.4, 0, 1, 1) both;
}
.bw-dialog::backdrop {
  background: rgb(23 22 15 / 28%);
}
.bw-dialog[open]::backdrop {
  animation: bw-dialog-backdrop-in 180ms ease-out both;
}
.bw-dialog[open].is-closing::backdrop {
  animation: bw-dialog-backdrop-out 150ms ease-in both;
}
@keyframes bw-dialog-in {
  from {
    opacity: 0;
    transform: scale(0.96);
  }
  to {
    opacity: 1;
    transform: scale(1);
  }
}
@keyframes bw-dialog-out {
  from {
    opacity: 1;
    transform: scale(1);
  }
  to {
    opacity: 0;
    transform: scale(0.96);
  }
}
@keyframes bw-dialog-backdrop-in {
  from { background: rgb(23 22 15 / 0%); }
  to { background: rgb(23 22 15 / 28%); }
}
@keyframes bw-dialog-backdrop-out {
  from { background: rgb(23 22 15 / 28%); }
  to { background: rgb(23 22 15 / 0%); }
}
@media (prefers-reduced-motion: reduce) {
  .bw-dialog[open],
  .bw-dialog[open]::backdrop {
    animation-duration: 1ms;
  }
}
.bw-dialog__surface {
  display: grid;
  gap: 1rem;
  padding: 1rem;
}
.bw-dialog__header,
.bw-dialog__actions {
  display: flex;
  align-items: center;
}
.bw-dialog__title {
  margin: 0;
  color: var(--color-neutral-00);
  font-family: var(--font-body);
  font-size: 1.5rem;
  font-weight: 600;
  letter-spacing: 0;
  line-height: 1.5em;
  text-transform: none;
}
.bw-dialog__message {
  color: var(--color-neutral-20);
  white-space: pre-line;
}
.bw-dialog__field {
  display: grid;
  gap: 0.375rem;
}
.bw-dialog__field[hidden] {
  display: none;
}
.bw-dialog__input {
  width: 100%;
  box-sizing: border-box;
  padding: 0.625rem;
  background: var(--color-neutral-100);
  border: 1px solid var(--color-neutral-40);
  color: var(--color-neutral-00);
}
.bw-dialog__actions {
  justify-content: flex-end;
  gap: 0.5rem;
}
.bw-dialog__actions button {
  background: transparent;
  border: 1px solid var(--color-neutral-40);
  color: var(--color-neutral-20);
  cursor: pointer;
}
.bw-dialog__actions button:hover:not(:disabled):not(.is-disabled) {
  color: var(--accent);
  border-color: var(--button-hover-border);
  background: var(--button-hover-bg);
}
button:disabled,
button.is-disabled,
[role="button"][aria-disabled="true"] {
  background: var(--color-neutral-60);
  border-color: var(--color-neutral-40);
  color: var(--color-neutral-40);
  cursor: not-allowed;
}

/* In-app hover tooltip — replaces native title="" (slow OS delay, unstyled). */
.bw-tooltip {
  position: fixed;
  z-index: 10000;
  top: 0;
  left: 0;
  max-width: 22rem;
  padding: 0.375rem 0.5rem;
  background: var(--color-neutral-00);
  color: var(--color-neutral-100);
  font-family: var(--font-body);
  font-size: 0.75rem;
  font-weight: 500;
  line-height: 1.35em;
  letter-spacing: 0;
  text-transform: none;
  white-space: pre-line;
  pointer-events: none;
  opacity: 0;
  transform: translateY(2px);
  transition: opacity 90ms ease-out, transform 90ms ease-out;
}
.bw-tooltip.is-visible {
  opacity: 1;
  transform: translateY(0);
}
@media (prefers-reduced-motion: reduce) {
  .bw-tooltip {
    transition-duration: 1ms;
  }
}
/* Arrow points down at the target by default (tooltip sits above it);
   .bw-tooltip--below flips it to point up when the tooltip falls below. */
.bw-tooltip::after {
  content: "";
  position: absolute;
  left: var(--arrow-left, 50%);
  bottom: -4px;
  width: 8px;
  height: 8px;
  background: var(--color-neutral-00);
  transform: translateX(-50%) rotate(45deg);
}
.bw-tooltip--below::after {
  top: -4px;
  bottom: auto;
}

/* ═══ DATA — Geist Mono, low tracking. Title block + status readouts. ═══ */

/* Top of the data scale — the title block's project name, the one field that
   names the whole file. Tracking runs to 0 here: the family's inverse
   size/tracking rule (see TRACKING above) tightens as the type grows.
   The inline rename input matches so clicking to edit doesn't jump. */
.text-data-xl,
#bw-tblock #bwtb-proj,
/* input.… , not .… — the rename field ships with class="v proj-edit-input",
   so it also matches #bw-tblock .v in the .text-data group below. That ties on
   specificity and, being later, would win and shrink the field to 12px the
   moment you clicked to rename. The type selector breaks the tie. */
#bw-tblock input.proj-edit-input {
  font-family: var(--font-mono);
  font-size: 1rem; /* 16px */
  font-weight: 600;
  letter-spacing: 0em;
  line-height: 1.2em;
  text-transform: uppercase;
}

.text-data-lg,
#bw-tblock .cost .v,
#bw-tblock .cost .k,
#bw-plan-current-name,
.bw-plan-current-input {
  font-family: var(--font-mono);
  font-size: 0.9375rem; /* 15px */
  font-weight: 600;
  letter-spacing: 0.01em;
  line-height: 1.2em;
  text-transform: uppercase;
}

.text-data,
.status .item,
.status .pill,
#bw-tblock .v,
#bw-site-panel .sb-grid input,
#bw-plans-list .nm b {
  font-family: var(--font-mono);
  font-size: 0.75rem; /* 12px */
  font-weight: 500;
  letter-spacing: 0.02em;
  line-height: 1.4em;
  text-transform: uppercase;
}

/* the one data tier that is NOT uppercased — the BOQ body carries
   descriptive line items, and timestamps read better as written */
.text-data-sm,
#bw-tblock #boq-display,
#bw-plans-list .nm i {
  font-family: var(--font-mono);
  font-size: 0.575rem; /* 9.2px */
  font-weight: 400;
  letter-spacing: 0.05em;
  line-height: 1.5em;
  text-transform: none;
}

/* ═══ STAMP — the drawing-sheet issue mark ═══════════════════════════ */

.text-stamp,
#bw-placard {
  font-family: var(--font-mono);
  font-size: 0.75rem; /* 12px */
  font-weight: 400;
  letter-spacing: 0.02em;
  line-height: 1.3em;
  text-transform: uppercase;
}

/* ═══ SVG CANVAS ANNOTATION ══════════════════════════════════════════
   Drawing annotation on the 2D sheet. font-size is set per-element from JS
   (it scales with the viewBox), so these carry every property EXCEPT size —
   the one deliberate exception in this file. */

.room-label,
.space-name {
  font-family: var(--font-mono);
  font-weight: 700;
  letter-spacing: 0.05em;
  line-height: 1em;
  text-transform: uppercase;
}

.room-area,
.dim-text,
.deck-label,
.pave-label,
.concrete-label,
.space-dims {
  font-family: var(--font-mono);
  font-weight: 400;
  font-style: normal;
  letter-spacing: 0.05em;
  line-height: 1em;
  text-transform: none;
}
