/* ============================================================================
   Dental Deals — Mobile Typography System
   ----------------------------------------------------------------------------
   SINGLE SOURCE OF TRUTH for size / weight / line-height / tracking, shared by
   BOTH stylesheet bundles:
     - the Tailwind app build  (@import-ed into tailwind/application.css), and
     - the Propshaft marketing / explore / onboarding pages
       (stylesheet_link_tag "typography" — those pages never load the Tailwind
       build, so this is how they get the scale).

   rem-based off a 16px root (1rem = 16px). The native OS font-scale is applied
   by `html.hotwire-native { zoom }` (see application/_head), so this fixed rem
   scale rides that zoom uniformly — do NOT reintroduce per-element scaling.

   Text does not get a size. It gets a ROLE. ~12 roles, 4 weights. Components
   reference `--type-*` (or a `.t-*` class), never a raw px. Full spec:
   docs/mobile-typography-system.md.

   The raw `--text-*` steps are ALSO declared in tailwind/application.css @theme
   so the `text-*` utilities regenerate at the compact sizes; the copy here is
   what feeds component `var(--text-*)` lookups and the marketing bundle.
   ============================================================================ */

:root {
  /* -- 1. RAW STEP SCALE (rem @ 16px root; px reference in comments) -------- */
  --text-2xs:  0.625rem;   /* 10px — non-text / micro glyph FLOOR (avatars, dots) */
  --text-xs:   0.6875rem;  /* 11px — caption, overline, table header */
  --text-sm:   0.75rem;    /* 12px — secondary / helper / label / chip */
  --text-base: 0.8125rem;  /* 13px — BODY ANCHOR (paragraphs, table cell, list) */
  --text-md:   0.875rem;   /* 14px — callout / input text / comfortable reading */
  --text-lg:   0.9375rem;  /* 15px — card title, form-section title, list-row title */
  --text-xl:   1.125rem;   /* 18px — section header, slideover title */
  --text-2xl:  1.375rem;   /* 22px — page/hero title, listing price, stat number */
  --text-3xl:  1.875rem;   /* 30px — display / big KPI number */
  --text-4xl:  3rem;       /* 48px — hero display (valuation VALUE, marketing hero) */

  /* -- 2. PRIMITIVES ------------------------------------------------------- */
  /* Weights — FOUR only. Kill 300 / 750 / 800 / the `bold` keyword. */
  --fw-regular:  400;
  --fw-medium:   500;
  --fw-semibold: 600;
  --fw-bold:     700;

  /* Line-heights — unitless, tokenized. */
  --lh-flat:     1;     /* big numbers / single-line stats */
  --lh-tight:    1.1;   /* display */
  --lh-snug:     1.25;  /* titles */
  --lh-heading:  1.35;  /* card / list titles, multi-line headings */
  --lh-body:     1.5;   /* body + secondary reading text */
  --lh-relaxed:  1.65;  /* dialog + empty-state prose (broker workspace) */

  /* Tracking — tokenized. */
  --tk-tight:   -0.02em;  /* display + titles */
  --tk-snug:    -0.01em;  /* card titles */
  --tk-normal:   0;       /* body, everything mid-scale */
  --tk-wide:     0.06em;  /* uppercase overline / eyebrow / table header */
  /* Broker workspace redesign — three tighter/wider rungs the ramp lacked. */
  --tk-panel:   -0.015em; /* panel + dialog titles, card money anchor */
  --tk-micro:   -0.005em; /* switcher tabs */
  --tk-th:       0.02em;  /* table header, tab count */
  --tk-eyebrow:  0.12em;  /* workspace uppercase eyebrow (wider than --tk-wide) */
  --tk-eyebrow-snug: 0.09em; /* inbox panel eyebrow + stream separators; 0.12em reads loose at 11px */

  /* -- 3. SEMANTIC ROLE TOKENS --------------------------------------------
     `font` shorthand = weight + size/line-height. Apply with:
        font: var(--type-body) var(--font-sans);
        letter-spacing: var(--tk-XXX);
     (tracking is a sibling token — it is not part of `font`). */
  --type-display:     var(--fw-bold)     var(--text-3xl)/var(--lh-tight);
  --type-title:       var(--fw-bold)     var(--text-2xl)/var(--lh-snug);
  --type-section:     var(--fw-bold)     var(--text-xl)/var(--lh-snug);
  --type-card-title:  var(--fw-semibold) var(--text-lg)/var(--lh-heading);
  --type-callout:     var(--fw-regular)  var(--text-md)/var(--lh-body);
  --type-body:        var(--fw-regular)  var(--text-base)/var(--lh-body);
  --type-body-strong: var(--fw-semibold) var(--text-base)/var(--lh-body);
  --type-secondary:   var(--fw-regular)  var(--text-sm)/var(--lh-body);
  /* 15px reading text: the seller listing editor's section lede, which the design
     sets at 15/1.55. --type-body is the 13px anchor and reads a size too small
     under a 30px heading. */
  --type-lede:        var(--fw-regular)  var(--text-lg)/var(--lh-body);
  --type-caption:     var(--fw-regular)  var(--text-xs)/var(--lh-heading);
  --type-label:       var(--fw-medium)   var(--text-sm)/var(--lh-snug);
  /* 14px form label. --type-label is 12px, which put the seller listing editor's
     labels THREE rungs under the 15px control they label: the question read
     smaller than its own answer, and smaller than its own chips. forms.css's
     `label` has been 14px/500 all along (L239-246), so this is that standard at
     the editor's own semibold. Same shape of addition as --type-lede above. */
  --type-field-label: var(--fw-semibold) var(--text-md)/var(--lh-heading);
  --type-overline:    var(--fw-semibold) var(--text-xs)/var(--lh-snug);
  --type-stat:        var(--fw-bold)     var(--text-2xl)/var(--lh-flat);

  /* Role-specific escape hatches (documented, finite — not free px). */
  --type-stat-lg:     var(--fw-bold)     var(--text-3xl)/var(--lh-flat);  /* metric-card value, listing price */
  --type-stat-hero:   var(--fw-bold)     var(--text-4xl)/var(--lh-flat);  /* valuation VALUE cell */

  /* -- BROKER PROFILE EDITOR ROLES (brokerage-profile redesign) ------------
     Three steps the main ramp does not carry, taken from the Claude Design
     artboard (Brokerage Profile.dc.html). Each is a real role on that surface,
     not a one-off size:
       bp-page-title — the workspace pane's h1 (24px; --type-title is 22)
       bp-rail-title — "Edit brokerage profile" in the rail (20px)
       bp-eyebrow    — the group eyebrow above the pane title (12px/700; the
                       shared --type-overline is 11px/600, which reads too light
                       against a 24px title) */
  --type-bp-page-title: var(--fw-bold) 24px/var(--lh-snug);
  --type-bp-rail-title: var(--fw-bold) 20px/var(--lh-snug);
  --type-bp-eyebrow:    var(--fw-bold) var(--text-sm)/var(--lh-snug);
  /* The profile-strength percentage. Same 20px as the rail title but --lh-flat,
     because it is a number and wants tight leading, not heading leading. */
  --type-bp-stat:       var(--fw-bold) 20px/var(--lh-flat);

  /* -- 4. BROKER WORKSPACE ROLES (dual-pipeline redesign) ------------------
     The Claude Design handoff specifies half-pixel steps — 11.5 / 12.5 / 13.5 /
     14.5px — and says to reproduce them: they are what give the dense board and
     table regions their calm. Our main ramp lands exactly 0.5px BELOW each of
     them, so these cannot just snap to it.

     The sizes are inlined here instead of becoming new --text-* steps on purpose.
     The raw ramp is ALSO declared in application.css @theme, so widening it would
     regenerate every `text-*` utility app-wide and shift the marketing bundle
     too — a global change to serve one surface. Custom-property definitions are
     exempt from `typography:check` by construction (it only matches font-size /
     font-weight / font: declarations), and workspace components consume ONLY
     these roles, never a raw px.

     Display roles take var(--font-display) (Plus Jakarta Sans); everything else
     takes var(--font-sans), which is already Inter — the handoff's body family.
     Source: design_handoff_dual_pipeline/06-design-tokens.md. */

  /* Display family — headings, titles, card titles, money anchors. */
  --type-ws-page-title:   var(--fw-bold)     1.625rem/var(--lh-tight);    /* 26px, sidebar variant h1 */
  --type-ws-empty-title:  var(--fw-bold)     1.4375rem/var(--lh-snug);    /* 23px */
  --type-ws-panel-title:  var(--fw-bold)     1.375rem/var(--lh-snug);     /* 22px */
  --type-ws-dialog-title: var(--fw-bold)     1.3125rem/var(--lh-snug);    /* 21px */
  --type-ws-money:        var(--fw-bold)     1.0625rem/var(--lh-flat);    /* 17px, card anchor */
  --type-ws-money-sm:     var(--fw-bold)     0.9375rem/var(--lh-flat);    /* 15px, panel value */
  --type-ws-rail-title:   var(--fw-semibold) 0.9375rem/var(--lh-snug);    /* 15px, sidebar item */
  --type-ws-tab:          var(--fw-semibold) 0.90625rem/var(--lh-snug);   /* 14.5px, switcher tab */
  --type-ws-card-title:   var(--fw-semibold) 0.875rem/var(--lh-heading);  /* 14px */
  /* 16px, broker Overview section head. Sits between --text-lg (15px) and --text-xl
     (18px) with no step of its own, which is why it was living as a raw `font-size:
     16px` in two components. Widening the raw ramp to reach it would regenerate every
     `text-*` utility app-wide and move the marketing bundle with it, so it goes here,
     alongside the other workspace-only literals, and is consumed as a role. */
  --type-ov-section:      var(--fw-bold)     1rem/var(--lh-snug);         /* 16px */
  /* 13px, broker Overview card-head "View all" link. Same story as --type-ov-section
     above: 13px semibold on a single line matches no existing role (--type-body-strong
     is the size and weight but carries --lh-body, which is reading leading on a
     one-line label), so it lands here as a role rather than a raw px in the theme. */
  --type-ov-viewall:      var(--fw-semibold) 0.8125rem/var(--lh-snug);     /* 13px */

  /* Broker Home v3. The summary-first Home is a page of few numbers read at a glance, so
     it is set a full step above the rest of the broker app: the greeting is 36px where the
     shared page header is 25px, and its body copy is 16px against the 13px anchor. That is
     deliberate and it is scoped -- these roles are consumed only by the .brokering-bh-*
     components, so the boards, the profile and the inbox are untouched. The FACE does not
     change with the size: Figtree stays the display face everywhere (themes/broker-v2.css),
     which is why these are roles and not a second font stack.

     Sized off the handoff's own scale so the shipped page and the prototype read alike;
     mapped onto rem here rather than copied as px, per the type rules. */
  --type-bh-greeting:     var(--fw-bold)     2.25rem/var(--lh-tight);     /* 36px */
  /* The greeting's phone size, a ROLE rather than a raw px inside the theme's media query.
     36px is a third of a 390px screen's width and has to come down; the size still belongs
     to the scale, so that retuning the display step here moves both widths together and so
     that it answers to the reader's own font-size setting, which a px does not. Worth
     knowing: `app/assets/tailwind/themes/**` is NOT scanned by `rake typography:*` (the
     KNOWN GAP in lib/tasks/typography.rake), so a px there is caught by nobody. */
  --type-bh-greeting-sm:  var(--fw-bold)     1.75rem/var(--lh-tight);     /* 28px */
  --type-bh-stat:         var(--fw-bold)     2.25rem/var(--lh-flat);      /* 36px */
  --type-bh-card:         var(--fw-bold)     1.375rem/var(--lh-snug);     /* 22px */
  --type-bh-section:      var(--fw-bold)     1.125rem/var(--lh-snug);     /* 18px */
  --type-bh-strip:        var(--fw-bold)     1.375rem/1.1;                /* 22px */
  --type-bh-body:         var(--fw-regular)  1rem/var(--lh-relaxed);      /* 16px */
  --type-bh-row:          var(--fw-regular)  0.875rem/var(--lh-snug);     /* 14px */
  --type-bh-row-strong:   var(--fw-semibold) 0.875rem/var(--lh-snug);     /* 14px */
  --type-bh-meta:         var(--fw-regular)  0.8125rem/var(--lh-body);    /* 13px */
  --type-ws-col-title:    var(--fw-semibold) 0.84375rem/var(--lh-snug);   /* 13.5px */

  /* -- 5. LEAD DETAIL MODAL ROLES (Lead Detail Modal v2 handoff) -----------
     The five steps that handoff sets the modal in. Its own scale collides with
     ours by NAME at different values -- its --text-sm is 14px where ours is
     12px, its --text-lg 22px where ours is 15px -- so the sizes are ported here
     as ROLES, which is the only way a component can consume the handoff's
     measure without a reader of the class list having to know which scale a bare
     `--text-sm` came from. Same reasoning as the --type-ws-* block above.

     Two of them (28px title, 16px field text) have no step on the shared ramp at
     all, and widening the ramp to reach them would regenerate every `text-*`
     utility app-wide and move the marketing bundle with it.

     Display roles take var(--font-display), which is FIGTREE here. The handoff
     draws Plus Jakarta Sans; see the note in application.css @theme for why this
     dashboard does not follow it -- the handoff's own readme calls its fonts
     Google-Fonts stand-ins for unconfirmed brand faces, and Figtree is the
     established display face of every other broker surface. Changing it is one
     line in themes/broker-v2.css. */
  --type-lm-title:        var(--fw-semibold) 1.75rem/1.15;                /* 28px, listing title */
  --type-lm-section:      var(--fw-semibold) 1.125rem/var(--lh-snug);     /* 18px, section heading */
  --type-lm-metric:       var(--fw-semibold) 1.375rem/1.27;               /* 22px, metric value */
  --type-lm-card-title:   var(--fw-semibold) 0.875rem/var(--lh-snug);     /* 14px, rail card + activity heading */
  /* 16px, the handoff's control text. The caret-height note further down applies:
     a 14px field gives a 17px caret and a 16px one 19.5px, and every control in
     this modal is set at the larger step. */
  /* 🚨 `/normal`, NOT a leading token. The handoff's Input and Select set no
     line-height, so a 16px field is 45-46px tall; ours inherited 1.5 from `body`
     and came out 51px, which walked the whole rail down by 5px a control. The
     textarea overrides it back to --lh-body, because it is the one control here
     whose text wraps. */
  --type-lm-field:        var(--fw-regular)  1rem/normal;                /* 16px, input / select / textarea */

  /* Body family. */
  --type-ws-empty-body:   var(--fw-regular)  0.9375rem/var(--lh-relaxed); /* 15px */
  --type-ws-dialog-body:  var(--fw-regular)  0.90625rem/1.6;              /* 14.5px */
  --type-ws-input:        var(--fw-regular)  0.875rem/var(--lh-body);     /* 14px, dialog input */
  /* 🚨 THE CARET'S HEIGHT COMES FROM THE FONT, NOT FROM line-height. Chrome sizes an
     <input>'s caret from the font's natural metrics (ascent + descent) and ignores an
     inflated CSS line-height entirely. So the way to a taller cursor is a bigger
     font-size, and a tall line box does the OPPOSITE of helping: it leaves the same short
     caret floating in dead space, which is what "cut off at the top and bottom" actually
     looks like. Measured on Inter: 14px gives a 17px caret, 16px gives 19.5px.
     A previous pass raised the line box to 1.85 and left 8.9px of dead space around an
     unchanged 17px caret, making it worse.
     var(--text-xl)/1.3 is therefore deliberate on both halves: 18px for a 21.8px caret,
     and a line box that HUGS it rather than leaving the cursor floating in dead space.
     A value at 1.5x its own label is also what the reference does, and anything at or
     over 16px stops iOS zooming a form on focus.

     🚨 HOW TO CHECK IT, because the caret is never composited into a screenshot in ANY
     browser here, headless or not, and four passes were lost to guessing at it. Put a
     zero-width space in a contenteditable carrying the same font, collapse a Range on it
     and read getBoundingClientRect().height. That rectangle IS a caret. Measured that
     way: 14px gives 16.8px whatever the line-height, 16px gives 19.3px, 18px gives
     21.8px. */
  --type-ws-field:        var(--fw-regular)  var(--text-xl)/1.3;          /* 18px, dialog field value */
  --type-ws-body:         var(--fw-regular)  0.84375rem/var(--lh-body);   /* 13.5px, table cell, panel field */
  --type-ws-body-strong:  var(--fw-medium)   0.84375rem/var(--lh-body);   /* 13.5px */
  --type-ws-bulk:         var(--fw-medium)   0.8125rem/var(--lh-snug);    /* 13px, bulk bar label */
  --type-ws-banner-body:  var(--fw-regular)  0.8125rem/var(--lh-body);    /* 13px */
  --type-ws-chip:         var(--fw-medium)   0.78125rem/var(--lh-snug);   /* 12.5px */
  --type-ws-chip-on:      var(--fw-semibold) 0.78125rem/var(--lh-snug);   /* 12.5px, active chip */
  --type-ws-subtitle:     var(--fw-regular)  0.78125rem/var(--lh-body);   /* 12.5px, card subtitle */
  --type-ws-meta:         var(--fw-regular)  0.75rem/var(--lh-body);      /* 12px, card meta, counts */
  --type-ws-action:       var(--fw-semibold) 0.75rem/var(--lh-snug);      /* 12px, card inline action */
  --type-ws-th:           var(--fw-semibold) 0.71875rem/var(--lh-snug);   /* 11.5px, table header, tab count */
  --type-ws-eyebrow:      var(--fw-semibold) 0.6875rem/var(--lh-snug);    /* 11px, uppercase */
  --type-ws-badge:        var(--fw-semibold) 0.6875rem/var(--lh-snug);    /* 11px, nav count badge */
  --type-ws-pill:         var(--fw-semibold) 0.625rem/var(--lh-snug);     /* 10px, "New" pill */
}

/* ---- Element defaults (headings map onto roles) --------------------------
   Unifies the app + marketing forks: h1–h6 now resolve identically in both. */
.font-display { font: var(--type-display) var(--font-sans); letter-spacing: var(--tk-tight); }

h1, .h1 { font: var(--type-title)       var(--font-sans); letter-spacing: var(--tk-tight); }
h2, .h2 { font: var(--type-section)     var(--font-sans); letter-spacing: var(--tk-tight); }
h3, .h3 { font: var(--type-card-title)  var(--font-sans); letter-spacing: var(--tk-snug); }
h4, .h4 { font: var(--type-body-strong) var(--font-sans); }
h5, .h5 { font: var(--type-label)       var(--font-sans); }
h6, .h6 { font-weight: var(--fw-semibold); }

/* Body default lives in each bundle's base:
   app -> tailwind/components/base.css; marketing -> marketing/colors_and_type.css. */

/* ---- Role utility classes (the lookup vocabulary) ------------------------ */
.t-display     { font: var(--type-display)     var(--font-sans); letter-spacing: var(--tk-tight); }
.t-title       { font: var(--type-title)       var(--font-sans); letter-spacing: var(--tk-tight); }
.t-section     { font: var(--type-section)     var(--font-sans); letter-spacing: var(--tk-tight); }
.t-card-title  { font: var(--type-card-title)  var(--font-sans); letter-spacing: var(--tk-snug); }
.t-callout     { font: var(--type-callout)     var(--font-sans); }
.t-body        { font: var(--type-body)        var(--font-sans); }
.t-body-strong { font: var(--type-body-strong) var(--font-sans); }
.t-secondary   { font: var(--type-secondary)   var(--font-sans); }
.t-caption     { font: var(--type-caption)     var(--font-sans); }
.t-label       { font: var(--type-label)       var(--font-sans); }
.t-field-label { font: var(--type-field-label) var(--font-sans); }
/* --type-lede has existed since the seller editor's section lede was added, but
   never got a utility, so markup could not reach 15px reading text. */
.t-lede        { font: var(--type-lede)        var(--font-sans); }

/* Overline / eyebrow — uppercase + wide tracking baked in. `.section-label`
   is kept as an alias so existing markup keeps working. */
.t-overline,
.section-label {
  font: var(--type-overline) var(--font-sans);
  letter-spacing: var(--tk-wide);
  text-transform: uppercase;
  color: var(--base-text-tertiary);
}

/* Numbers — tabular figures so columns of stats align. */
.t-stat,
.t-stat-lg,
.t-stat-hero {
  font-variant-numeric: tabular-nums;
  letter-spacing: var(--tk-tight);
}
.t-stat      { font: var(--type-stat)      var(--font-sans); }
.t-stat-lg   { font: var(--type-stat-lg)   var(--font-sans); }
.t-stat-hero { font: var(--type-stat-hero) var(--font-sans); }

/* ---- Preserved helpers ---------------------------------------------------- */
.text-muted { color: var(--text-muted); }

.with-border {
  border-color: var(--divider-color);
  border-bottom-width: 1px;
  border-bottom-style: var(--tw-border-style);
  margin-block: calc(var(--spacing) * 4);
  padding-bottom: calc(var(--spacing) * 2);
}

.link {
  color: var(--text-primary);
  text-decoration-line: underline;
  &:hover,
  &:focus { color: var(--text-primary-hover); }
}

code {
  font: var(--type-secondary) var(--font-mono);
  background: var(--bg-disabled);
  border-radius: var(--radius-md);
  color: var(--base-text);
  padding-inline: calc(var(--spacing) * 1.5);
  white-space: nowrap;
}
pre code { display: block; padding: 0.5rem 0.75rem; white-space: pre-wrap; }
kbd { font: var(--type-caption) var(--font-mono); }

/* Feature section-labels (.brokering-listing-section-label, etc.) need the dark
   tertiary anchor (carried from #164; the base .section-label already flips). */
.dark [class$="-section-label"] { color: var(--base-text-tertiary); }
