# Quality House

The 14 WHATs × 14 HOWs House of Quality. The roof carries function-vs-
function correlations; the basement carries v0.1 targets (mirrored from
[`qfd.md`](qfd.md) §2) plus the weighted-vote sums
(`Σ = Σ(W weight × cell strength)`) and rounded relative weights. The
narrative reading of these numbers lives in `qfd.md` §3 (priority list)
and §4 (conflict list).

This file is the authoritative source for the matrix cells, the roof
correlations, and the basement Σ + relative weights. WHATs (§1) and HOWs
(§2) are mirrored here from `qfd.md`; if those diverge, trust `qfd.md`.

Out of scope here: §5 component mapping (would need a second house),
§6 critical performance budget (already a curated rank), §7 tradeoffs
(narrative), §8 inconsistencies (history).

For a blank version of the same chassis (WHATs, HOWs, importance, and
v0.1 targets kept; relations + roof + Σ basement left empty for practice),
see [`quality-house-empty.md`](quality-house-empty.md).

The perception zone scores five products against the WHATs on a 0–5 scale.
**These are educated guesses, not measurements** — see the
[scoring rationale](#perception-scores-guessed) below for what each cell
is based on. Useful for self-positioning ("where do we land vs the
market"), not as a fair head-to-head buyer's guide.

```tikz
% =====================================================================
% QFD "House of Quality" preamble
% =====================================================================
\usetikzlibrary{arrows.meta, positioning, shapes.geometric, shapes.misc, calc, fit, backgrounds}

\newif\ifqfdshowroof          \qfdshowrooftrue
\newif\ifqfdshowbasement      \qfdshowbasementtrue
\newif\ifqfdshowcompetitive   \qfdshowcompetitivetrue
\newif\ifqfdshowlegend        \qfdshowlegendtrue
\newif\ifqfdshowimportance    \qfdshowimportancetrue
\newif\ifqfdshowcorrlegend    \qfdshowcorrlegendtrue
\newif\ifqfdshowevallegend    \qfdshowevallegendtrue

\def\qfdNW{5}
\def\qfdNH{5}
\def\qfdWhatW{4.0}
\def\qfdImpW{0.9}
\def\qfdCmpW{3}
\def\qfdHdrH{2.6}
\def\qfdBasementN{4}

\def\qfdWhatsTitle{Customer needs}
\def\qfdImpTitle{Imp.\ \%}
\def\qfdPerceptionTitle{Comparative evaluation}
\def\qfdPoorLabel{poor}
\def\qfdExcellentLabel{excellent}
\def\qfdAltOneLabel{Typoena}
\def\qfdAltTwoLabel{Competitor A}
\def\qfdAltThreeLabel{Competitor B}
\def\qfdRelTitle{Relation}
\def\qfdCorrTitle{Correlation}
\def\qfdEvalTitle{Evaluation}

\tikzset{
  qfdthin/.style ={line width=0.35pt},
  qfdmed/.style  ={line width=0.7pt},
  qfdstrong/.style={circle, draw, fill=black,
                    minimum size=7pt, inner sep=0pt},
  qfdmod/.style  ={circle, draw,
                    minimum size=7pt, inner sep=0pt, line width=0.8pt},
  qfdweak/.style ={regular polygon, regular polygon sides=3, draw,
                    minimum size=8.5pt, inner sep=0pt, line width=0.7pt},
  qfdrel/.is choice,
  qfdrel/S/.style={qfdstrong},
  qfdrel/M/.style={qfdmod},
  qfdrel/W/.style={qfdweak},
  qfdalt1mk/.style={circle, draw, fill=black,
                    minimum size=6pt, inner sep=0pt, line width=1pt},
  qfdalt1ln/.style={line width=1.2pt},
  qfdalt2mk/.style={regular polygon, regular polygon sides=3, draw,
                    fill=black, minimum size=6pt, inner sep=0pt,
                    line width=0.7pt},
  qfdalt2ln/.style={line width=0.7pt, dashed},
  qfdalt3mk/.style={rectangle, draw, fill=black,
                    minimum size=5pt, inner sep=0pt, line width=0.7pt},
  qfdalt3ln/.style={line width=0.7pt, dotted},
}

\newcommand{\qfdDrawGrid}{%
  \foreach \c in {1,...,\qfdNHm} \draw[qfdthin] (\c, 0) -- (\c, -\qfdNW);
  \foreach \r in {1,...,\qfdNWm} \draw[qfdthin] (0, -\r) -- (\qfdNH, -\r);
  \foreach \r in {1,...,\qfdNWm}
    \draw[qfdthin] (\qfdLeftEdge, -\r) -- (0, -\r);
  \ifqfdshowroof
    \foreach \c in {1,...,\qfdNHm}
      \draw[qfdthin] (\c, 0) -- (\c, \qfdHdrH);
  \fi
  \ifqfdshowcompetitive
    \foreach \r in {1,...,\qfdNWm}
      \draw[qfdthin] (\qfdNH, -\r) -- (\qfdNH+\qfdCmpW, -\r);
  \fi
  \ifqfdshowbasement
    \foreach \r in {1,...,\qfdBasementN}
      \draw[qfdthin] (0, -\qfdNW-\r) -- (\qfdNH, -\qfdNW-\r);
    \foreach \c in {1,...,\qfdNHm}
      \draw[qfdthin] (\c, -\qfdNW) -- (\c, -\qfdNW-\qfdBasementN);
  \fi
}

\newcommand{\qfdDrawRoof}{%
  \ifqfdshowroof
    \foreach \k in {1,...,\qfdNHm} {%
      \pgfmathsetmacro{\rx}{(\k+\qfdNH)/2}
      \pgfmathsetmacro{\ry}{\qfdHdrH + (\qfdNH-\k)/2}
      \pgfmathsetmacro{\lx}{\k/2}
      \pgfmathsetmacro{\ly}{\qfdHdrH + \k/2}
      \draw[qfdthin] (\k, \qfdHdrH) -- (\rx, \ry);
      \draw[qfdthin] (\k, \qfdHdrH) -- (\lx, \ly);
    }%
    \draw[qfdmed] (0, \qfdHdrH)
       -- (\qfdNH/2, \qfdApexY) -- (\qfdNH, \qfdHdrH);
    \foreach \i in {1,...,\qfdNH}
      \foreach \k in {1,...,\qfdNH} {%
        \pgfmathtruncatemacro{\jj}{\i+\k}
        \ifnum\jj>\qfdNH\relax\else
          \pgfmathsetmacro{\xx}{\i + \k/2 - 0.5}
          \pgfmathsetmacro{\yy}{\qfdHdrH + \k/2}
          \coordinate (C-\i-\jj) at (\xx, \yy);
        \fi
      }%
  \fi
}

\newcommand{\qfdDrawScale}{%
  \ifqfdshowcompetitive
    \foreach \tk in {0,1,2,3,4,5} {%
      \pgfmathsetmacro{\tx}{\qfdNH + (\tk+0.5)*\qfdCmpW/6}
      \node[anchor=south, font=\scriptsize] at (\tx, 0.02) {\tk};
    }%
    \node[anchor=south, font=\scriptsize\bfseries, align=center,
          text width=\qfdCmpW cm]
         at ({\qfdNH + \qfdCmpW/2}, 0.7) {\qfdPerceptionTitle};
    \node[anchor=north, font=\scriptsize\itshape]
         at ({\qfdNH + 0.45}, -\qfdNW) {\qfdPoorLabel};
    \node[anchor=north, font=\scriptsize\itshape]
         at ({\qfdNH + \qfdCmpW - 0.45}, -\qfdNW) {\qfdExcellentLabel};
  \fi
}

\newcommand{\qfdDrawZoneTitles}{%
  \ifqfdshowimportance
    \node[rotate=90, anchor=west, font=\footnotesize\bfseries]
         at ({-\qfdImpW/2}, 0.12) {\qfdImpTitle};
  \fi
  \node[font=\scriptsize\bfseries, align=center, text width=\qfdWhatW cm]
       at ({\qfdLeftEdge + \qfdWhatW/2},
           {\ifqfdshowroof \qfdHdrH/2 \else 0.6 \fi}) {\qfdWhatsTitle};
}

\newcommand{\qfdDrawFrames}{%
  \begin{scope}[qfdmed]
    \draw (\qfdLeftEdge, 0) rectangle (\qfdNH, -\qfdNW);
    \ifqfdshowimportance \draw (-\qfdImpW, 0) -- (-\qfdImpW, -\qfdNW); \fi
    \draw (0, 0) -- (0, -\qfdNW);
    \ifqfdshowroof
      \draw (0, 0) rectangle (\qfdNH, \qfdHdrH); \fi
    \ifqfdshowbasement
      \draw (0, -\qfdNW) rectangle (\qfdNH, -\qfdNW-\qfdBasementN); \fi
    \ifqfdshowcompetitive
      \draw (\qfdNH, 0) rectangle (\qfdNH+\qfdCmpW, -\qfdNW); \fi
  \end{scope}
}

\newcommand{\qfdDrawLegend}{%
  \ifqfdshowlegend
    \pgfmathsetmacro{\qfdLegX}{%
      \qfdNH + \ifqfdshowcompetitive \qfdCmpW + 0.7 \else 0.7 \fi}
    \pgfmathsetmacro{\qfdLegBottom}{%
      -2.05
      \ifqfdshowroof    \ifqfdshowcorrlegend - 2.55 \fi \fi
      \ifqfdshowcompetitive \ifqfdshowevallegend - 2.20 \fi \fi}
    \pgfmathsetmacro{\qfdLegY}{\qfdHdrH - 0.4}
    \begin{scope}[shift={(\qfdLegX, \qfdLegY)}]
      \draw[qfdmed, rounded corners=2pt]
        (-0.15, 0.4) rectangle (4.5, \qfdLegBottom);
      \node[anchor=west, font=\footnotesize\bfseries] at (0, 0.1)
        {\qfdRelTitle};
      \draw[qfdthin] (0, -0.15) -- (4.35, -0.15);
      \node[qfdstrong] at (0.22, -0.5)  {};
        \node[anchor=west] at (0.5, -0.5)  {Strong (9)};
      \node[qfdmod]    at (0.22, -0.95) {};
        \node[anchor=west] at (0.5, -0.95) {Medium (3)};
      \node[qfdweak]   at (0.22, -1.4)  {};
        \node[anchor=west] at (0.5, -1.4)  {Weak (1)};
      \ifqfdshowroof \ifqfdshowcorrlegend
        \node[anchor=west, font=\footnotesize\bfseries] at (0, -2.10)
          {\qfdCorrTitle};
        \draw[qfdthin] (0, -2.35) -- (4.35, -2.35);
        \node[anchor=west] at (0, -2.70) {{$+\!+$}\quad very positive};
        \node[anchor=west] at (0, -3.05) {{$+$\phantom{$+$}}\quad positive};
        \node[anchor=west] at (0, -3.40) {{$-$\phantom{$-$}}\quad negative};
        \node[anchor=west] at (0, -3.75) {{$-\!-$}\quad very negative};
      \fi \fi
      \ifqfdshowcompetitive \ifqfdshowevallegend
        \pgfmathsetmacro{\qfdEvalTop}{%
          -2.10 \ifqfdshowroof\ifqfdshowcorrlegend - 2.55 \fi\fi}
        \node[anchor=west, font=\footnotesize\bfseries]
          at (0, \qfdEvalTop) {\qfdEvalTitle};
        \pgfmathsetmacro{\qfdEvalSep}{\qfdEvalTop - 0.25}
        \draw[qfdthin] (0, \qfdEvalSep) -- (4.35, \qfdEvalSep);
        \pgfmathsetmacro{\qfdLegA}{\qfdEvalTop - 0.55}
        \draw[qfdalt1ln] (0.05, \qfdLegA) -- (0.45, \qfdLegA);
          \node[qfdalt1mk] at (0.25, \qfdLegA) {};
          \node[anchor=west, font=\bfseries] at (0.55, \qfdLegA)
            {\qfdAltOneLabel};
        \pgfmathsetmacro{\qfdLegB}{\qfdEvalTop - 0.95}
        \draw[qfdalt2ln] (0.05, \qfdLegB) -- (0.45, \qfdLegB);
          \node[qfdalt2mk] at (0.25, \qfdLegB) {};
          \node[anchor=west] at (0.55, \qfdLegB) {\qfdAltTwoLabel};
        \pgfmathsetmacro{\qfdLegC}{\qfdEvalTop - 1.35}
        \draw[qfdalt3ln] (0.05, \qfdLegC) -- (0.45, \qfdLegC);
          \node[qfdalt3mk] at (0.25, \qfdLegC) {};
          \node[anchor=west] at (0.55, \qfdLegC) {\qfdAltThreeLabel};
      \fi \fi
    \end{scope}
  \fi
}

\newenvironment{qfdhouse}{%
  \begin{tikzpicture}[x=1cm, y=1cm, font=\scriptsize,
                      line cap=round, line join=round]
  \ifqfdshowimportance
    \pgfmathsetmacro{\qfdLeftEdge}{-\qfdWhatW-\qfdImpW}
  \else
    \pgfmathsetmacro{\qfdLeftEdge}{-\qfdWhatW}
  \fi
  \pgfmathsetmacro{\qfdApexY}{\qfdHdrH + \qfdNH/2}
  \pgfmathtruncatemacro{\qfdNHm}{\qfdNH - 1}
  \pgfmathtruncatemacro{\qfdNWm}{\qfdNW - 1}
  \qfdDrawGrid
  \qfdDrawRoof
  \qfdDrawScale
  \qfdDrawZoneTitles
}{%
  \qfdDrawFrames
  \qfdDrawLegend
  \end{tikzpicture}%
}

% --- Dimensions tuned for the typewriter QFD (14 W x 15 H) ---
\def\qfdNW{14}
\def\qfdNH{14}
\def\qfdWhatW{4.6}
\def\qfdImpW{0.7}
\def\qfdHdrH{5.0}
\def\qfdBasementN{3}
\def\qfdCmpW{3.4}
\qfdshowlegendfalse                 % we draw a 4-alternative legend manually

\def\qfdWhatsTitle{User-facing requirements (W)}
\def\qfdImpTitle{Weight}
\def\qfdPerceptionTitle{Competitive perception\\(0–5, guessed)}
\def\qfdPoorLabel{poor}
\def\qfdExcellentLabel{excellent}

% Perception-zone markers: shape + colour-blind-safe colour per product.
% Palette is Okabe-Ito (blue, vermillion, bluish green, reddish purple).
% Light fills + saturated outlines keep stacked markers legible.
\definecolor{qfdcTypoena}{RGB}{0,114,178}
\definecolor{qfdcRem}{RGB}{213,94,0}
\definecolor{qfdcFrw}{RGB}{0,158,115}
\definecolor{qfdcPom}{RGB}{204,121,167}
\definecolor{qfdcFrwS}{RGB}{86,180,233}

\tikzset{
  qfdalt1mk/.style={circle, draw=qfdcTypoena, fill=qfdcTypoena!55!white,
                    minimum size=6.5pt, inner sep=0pt, line width=1.1pt},
  qfdalt1ln/.style={line width=1.2pt, qfdcTypoena},
  qfdalt2mk/.style={regular polygon, regular polygon sides=3,
                    draw=qfdcRem, fill=qfdcRem!55!white,
                    minimum size=7pt, inner sep=0pt, line width=0.9pt},
  qfdalt2ln/.style={line width=0.8pt, dashed, qfdcRem},
  qfdalt3mk/.style={rectangle, draw=qfdcFrw, fill=qfdcFrw!55!white,
                    minimum size=5.5pt, inner sep=0pt, line width=0.9pt},
  qfdalt3ln/.style={line width=0.8pt, dotted, qfdcFrw},
  qfdalt4mk/.style={diamond, aspect=1, draw=qfdcPom,
                    fill=qfdcPom!50!white,
                    minimum size=7pt, inner sep=0pt, line width=1.0pt},
  qfdalt4ln/.style={line width=0.8pt, dash dot, qfdcPom},
  qfdalt5mk/.style={regular polygon, regular polygon sides=5,
                    draw=qfdcFrwS, fill=qfdcFrwS!40!white,
                    minimum size=5.5pt, inner sep=0pt, line width=0.8pt},
  qfdalt5ln/.style={line width=0.7pt, dash dot dot, qfdcFrwS},
}

\begin{document}
\begin{qfdhouse}

  % ---------- WHATs (left column) ----------
  % Box width is 0.2 cm narrower than the column so labels have 0.1 cm
  % clearance on each side and don't bleed into the Weight column.
  \pgfmathsetmacro{\qfdWhatTextW}{\qfdWhatW - 0.2}
  \foreach \r/\t in {%
    1/{W1 Sub-second visible response to typing},
    2/{W2 Publishing is one deliberate action away},
    3/{W3 Pulling power never corrupts the file},
    4/{W4 Provisioning never interrupts a writing session},
    5/{W5 Quick boot to a writing cursor},
    6/{W6 Long sessions without crash, lag, drift},
    7/{W7 Nothing on the device competes with prose},
    8/{W8 The UI never moves except when I move it},
    9/{W9 Codebase absorbs the planned roadmap},
    10/{W10 I can repair or fork it with hobbyist tools},
    11/{W11 Multi-day battery life (v0.8 onward)},
    12/{W12 Local-only files coexist with git scope (v0.5+)},
    13/{W13 Typography sets a writing-tool tone},
    14/{W14 I can carry the device and write away from a desk}%
  }
    \node[anchor=west, font=\scriptsize,
          text width=\qfdWhatTextW cm, align=left]
      at ({\qfdLeftEdge + 0.1}, {-\r + 0.5}) {\t};

  % ---------- Importance (raw 1-10 weight) ----------
  \foreach \r/\w in {1/10, 2/9, 3/10, 4/7, 5/6, 6/9, 7/8, 8/7,
                     9/8, 10/5, 11/4, 12/5, 13/7, 14/8}
    \node[font=\scriptsize] at ({-\qfdImpW/2}, {-\r + 0.5}) {\w};

  % ---------- HOWs (rotated column titles) ----------
  \foreach \c/\t in {%
    1/{H1 Type latency},
    2/{H2 Refresh area per keystroke},
    3/{H3 Full-refresh cadence},
    4/{H4 Boot latency (cold)},
    5/{H5 Continuous-typing endurance},
    6/{H6 Publish reliability},
    7/{H7 Publish latency},
    8/{H8 Save durability},
    9/{H9 PSRAM heap headroom},
    10/{H10 Firmware binary size},
    11/{H11 Total stack budget},
    12/{H12 Network reconnect time},
    13/{H13 Idle / typing / push current},
    14/{H15 Clean release build time}%
  }
    \node[rotate=90, anchor=west, font=\scriptsize]
      at ({\c - 0.5}, 0.15) {\t};

  % ---------- Relation matrix (S=9, M=3, W=1) ----------
  % W1 row 1: H1S H2S H3M H5M H9W H11W
  \node[qfdrel/S] at ({1 - 0.5},  {-1 + 0.5}) {};
  \node[qfdrel/S] at ({2 - 0.5},  {-1 + 0.5}) {};
  \node[qfdrel/M] at ({3 - 0.5},  {-1 + 0.5}) {};
  \node[qfdrel/M] at ({5 - 0.5},  {-1 + 0.5}) {};
  \node[qfdrel/W] at ({9 - 0.5},  {-1 + 0.5}) {};
  \node[qfdrel/W] at ({11 - 0.5}, {-1 + 0.5}) {};

  % W2 row 2: H6S H7M H9S H12S
  \node[qfdrel/S] at ({6 - 0.5},  {-2 + 0.5}) {};
  \node[qfdrel/M] at ({7 - 0.5},  {-2 + 0.5}) {};
  \node[qfdrel/S] at ({9 - 0.5},  {-2 + 0.5}) {};
  \node[qfdrel/S] at ({12 - 0.5}, {-2 + 0.5}) {};

  % W3 row 3: H8S
  \node[qfdrel/S] at ({8 - 0.5},  {-3 + 0.5}) {};

  % W4 row 4: H6M H12M
  \node[qfdrel/M] at ({6 - 0.5},  {-4 + 0.5}) {};
  \node[qfdrel/M] at ({12 - 0.5}, {-4 + 0.5}) {};

  % W5 row 5: H4S H10M
  \node[qfdrel/S] at ({4 - 0.5},  {-5 + 0.5}) {};
  \node[qfdrel/M] at ({10 - 0.5}, {-5 + 0.5}) {};

  % W6 row 6: H1M H3M H5S H6M H8M H9S H11M H12M
  \node[qfdrel/M] at ({1 - 0.5},  {-6 + 0.5}) {};
  \node[qfdrel/M] at ({3 - 0.5},  {-6 + 0.5}) {};
  \node[qfdrel/S] at ({5 - 0.5},  {-6 + 0.5}) {};
  \node[qfdrel/M] at ({6 - 0.5},  {-6 + 0.5}) {};
  \node[qfdrel/M] at ({8 - 0.5},  {-6 + 0.5}) {};
  \node[qfdrel/S] at ({9 - 0.5},  {-6 + 0.5}) {};
  \node[qfdrel/M] at ({11 - 0.5}, {-6 + 0.5}) {};
  \node[qfdrel/M] at ({12 - 0.5}, {-6 + 0.5}) {};

  % W7 row 7: H1M H2M H3M H13M
  \node[qfdrel/M] at ({1 - 0.5},  {-7 + 0.5}) {};
  \node[qfdrel/M] at ({2 - 0.5},  {-7 + 0.5}) {};
  \node[qfdrel/M] at ({3 - 0.5},  {-7 + 0.5}) {};
  \node[qfdrel/M] at ({13 - 0.5}, {-7 + 0.5}) {};

  % W8 row 8: H1W H2S H3S
  \node[qfdrel/W] at ({1 - 0.5},  {-8 + 0.5}) {};
  \node[qfdrel/S] at ({2 - 0.5},  {-8 + 0.5}) {};
  \node[qfdrel/S] at ({3 - 0.5},  {-8 + 0.5}) {};

  % W9 row 9: H10W H11W H15M
  \node[qfdrel/W] at ({10 - 0.5}, {-9 + 0.5}) {};
  \node[qfdrel/W] at ({11 - 0.5}, {-9 + 0.5}) {};
  \node[qfdrel/M] at ({14 - 0.5}, {-9 + 0.5}) {};

  % W10 row 10: H10M H13W H15W
  \node[qfdrel/M] at ({10 - 0.5}, {-10 + 0.5}) {};
  \node[qfdrel/W] at ({13 - 0.5}, {-10 + 0.5}) {};
  \node[qfdrel/W] at ({14 - 0.5}, {-10 + 0.5}) {};

  % W11 row 11: H13S
  \node[qfdrel/S] at ({13 - 0.5}, {-11 + 0.5}) {};

  % W12 row 12: H6W H8M
  \node[qfdrel/W] at ({6 - 0.5},  {-12 + 0.5}) {};
  \node[qfdrel/M] at ({8 - 0.5},  {-12 + 0.5}) {};

  % W13 row 13: H9M
  \node[qfdrel/M] at ({9 - 0.5},  {-13 + 0.5}) {};

  % W14 row 14: H4W H8M H12M H13S
  \node[qfdrel/W] at ({4 - 0.5},  {-14 + 0.5}) {};
  \node[qfdrel/M] at ({8 - 0.5},  {-14 + 0.5}) {};
  \node[qfdrel/M] at ({12 - 0.5}, {-14 + 0.5}) {};
  \node[qfdrel/S] at ({13 - 0.5}, {-14 + 0.5}) {};

  % ---------- Roof correlations ----------
  \node[font=\scriptsize] at (C-1-2)   {$+\!+$};   % H1-H2 strong reinforce
  \node[font=\scriptsize] at (C-1-3)   {$-$};      % H1-H3 mild conflict
  \node[font=\scriptsize] at (C-1-5)   {$+$};      % H1-H5 mild reinforce
  \node[font=\scriptsize] at (C-1-13)  {$-$};      % H1-H13 mild conflict
  \node[font=\scriptsize] at (C-2-3)   {$+\!+$};   % H2-H3 strong reinforce
  \node[font=\scriptsize] at (C-2-13)  {$+$};      % H2-H13
  \node[font=\scriptsize] at (C-3-13)  {$+$};      % H3-H13
  \node[font=\scriptsize] at (C-4-10)  {$-$};      % H4-H10 boot vs binary
  \node[font=\scriptsize] at (C-5-6)   {$+$};      % H5-H6
  \node[font=\scriptsize] at (C-5-8)   {$+$};      % H5-H8
  \node[font=\scriptsize] at (C-5-9)   {$-\!-$};   % H5-H9 soak vs heap
  \node[font=\scriptsize] at (C-6-7)   {$+$};      % H6-H7
  \node[font=\scriptsize] at (C-6-9)   {$-\!-$};   % H6-H9 push vs heap
  \node[font=\scriptsize] at (C-6-12)  {$+\!+$};   % H6-H12
  \node[font=\scriptsize] at (C-7-9)   {$-$};      % H7-H9
  \node[font=\scriptsize] at (C-7-12)  {$+\!+$};   % H7-H12
  \node[font=\scriptsize] at (C-9-10)  {$-\!-$};   % H9-H10 heap vs binary
  \node[font=\scriptsize] at (C-10-14) {$-\!-$};   % H10-H15 binary vs build
  \node[font=\scriptsize] at (C-11-13) {$-$};      % H11-H13

  % ---------- Basement: target / abs weight / rel weight % ----------
  \foreach \c/\tgt/\abs/\rel in {%
    1/{$\leq$200\,ms}/148/10,
    2/{$\leq$1 line}/177/11,
    3/{1 : 64}/144/9,
    4/{$\leq$5\,s}/62/4,
    5/{$\geq$1\,h}/111/7,
    6/{$\geq$95\,\%}/134/9,
    7/{$\leq$30\,s}/27/2,
    8/{100\,\%}/156/10,
    9/{$\geq$1\,MB}/193/12,
    10/{$\leq$2\,MB}/41/3,
    11/{$\leq$80\,KB}/45/3,
    12/{$\leq$30\,s}/153/10,
    13/{obs.}/137/9,
    14/{$\leq$7\,min}/29/2%
  } {
    \node[font=\scriptsize] at ({\c - 0.5}, {-\qfdNW - 0.5}) {\tgt};
    \node[font=\scriptsize] at ({\c - 0.5}, {-\qfdNW - 1.5}) {\abs};
    \node[font=\scriptsize\bfseries]
      at ({\c - 0.5}, {-\qfdNW - 2.5}) {\rel};
  }

  % ---------- Basement row labels (in the margin below WHATs) ----------
  \foreach \k/\lbl in {1/{Target (v0.1)}, 2/{$\Sigma$ abs}, 3/{Rel.\ \%}}
    \node[anchor=east, font=\scriptsize\itshape]
      at ({-0.1}, {-\qfdNW - \k + 0.5}) {\lbl};

  % ---------- Perception zone: 5 products x 14 WHATs (0-5 scores) ----------
  % Columns: \so=Typoena target, \st=reMarkable 2 + Type Folio,
  %          \sf=Freewrite Traveler, \sg=Pomera DM250,
  %          \sh=Freewrite Smart Typewriter.
  % Pass 1: stash each score as a named coordinate so the profile lines
  % below can reuse it without recomputing.
  \foreach \r/\so/\st/\sf/\sg/\sh in {%
    1/4/1/4/5/3,
    2/5/4/4/2/4,
    3/4/4/2/2/2,
    4/5/2/2/5/2,
    5/4/3/4/5/4,
    6/3/3/4/5/4,
    7/5/2/5/5/5,
    8/4/3/4/5/4,
    9/4/3/2/1/2,
    10/5/4/2/1/2,
    11/1/5/5/4/5,
    12/3/1/2/3/2,
    13/3/5/2/2/2,
    14/2/4/5/2/5%
  } {
    \pgfmathsetmacro{\xo}{\qfdNH + (\so + 0.5)*\qfdCmpW/6}
    \pgfmathsetmacro{\xt}{\qfdNH + (\st + 0.5)*\qfdCmpW/6}
    \pgfmathsetmacro{\xf}{\qfdNH + (\sf + 0.5)*\qfdCmpW/6}
    \pgfmathsetmacro{\xg}{\qfdNH + (\sg + 0.5)*\qfdCmpW/6}
    \pgfmathsetmacro{\xs}{\qfdNH + (\sh + 0.5)*\qfdCmpW/6}
    \coordinate (po-\r) at (\xo, {-\r + 0.5});
    \coordinate (pr-\r) at (\xt, {-\r + 0.5});
    \coordinate (pf-\r) at (\xf, {-\r + 0.5});
    \coordinate (pp-\r) at (\xg, {-\r + 0.5});
    \coordinate (ps-\r) at (\xs, {-\r + 0.5});
  }

  % Pass 2: profile lines per alternative. Drawn before markers so the
  % dots sit on top of (not under) the line endpoints.
  \draw[qfdalt1ln] (po-1) \foreach \r in {2,...,\qfdNW} { -- (po-\r) };
  \draw[qfdalt2ln] (pr-1) \foreach \r in {2,...,\qfdNW} { -- (pr-\r) };
  \draw[qfdalt3ln] (pf-1) \foreach \r in {2,...,\qfdNW} { -- (pf-\r) };
  \draw[qfdalt4ln] (pp-1) \foreach \r in {2,...,\qfdNW} { -- (pp-\r) };
  \draw[qfdalt5ln] (ps-1) \foreach \r in {2,...,\qfdNW} { -- (ps-\r) };

  % Pass 3: markers on top of the lines.
  \foreach \r in {1,...,\qfdNW} {
    \node[qfdalt1mk] at (po-\r) {};
    \node[qfdalt2mk] at (pr-\r) {};
    \node[qfdalt3mk] at (pf-\r) {};
    \node[qfdalt4mk] at (pp-\r) {};
    \node[qfdalt5mk] at (ps-\r) {};
  }

  % ---------- Manual legend (5 alternatives, placed right of zones) ----------
  \pgfmathsetmacro{\qfdLegX}{\qfdNH + \qfdCmpW + 0.7}
  \begin{scope}[shift={(\qfdLegX, \qfdHdrH - 0.4)}]
    \draw[qfdmed, rounded corners=2pt]
      (-0.15, 0.4) rectangle (5.1, -7.50);
    % Relations
    \node[anchor=west, font=\footnotesize\bfseries] at (0, 0.1)
      {Relation};
    \draw[qfdthin] (0, -0.15) -- (4.95, -0.15);
    \node[qfdstrong] at (0.22, -0.5)  {};
      \node[anchor=west] at (0.5, -0.5)  {Strong (9)};
    \node[qfdmod]    at (0.22, -0.95) {};
      \node[anchor=west] at (0.5, -0.95) {Medium (3)};
    \node[qfdweak]   at (0.22, -1.4)  {};
      \node[anchor=west] at (0.5, -1.4)  {Weak (1)};
    % Correlation
    \node[anchor=west, font=\footnotesize\bfseries] at (0, -2.10)
      {Correlation};
    \draw[qfdthin] (0, -2.35) -- (4.95, -2.35);
    \node[anchor=west] at (0, -2.70) {{$+\!+$}\quad very positive};
    \node[anchor=west] at (0, -3.05) {{$+$\phantom{$+$}}\quad positive};
    \node[anchor=west] at (0, -3.40) {{$-$\phantom{$-$}}\quad negative};
    \node[anchor=west] at (0, -3.75) {{$-\!-$}\quad very negative};
    % Perception
    \node[anchor=west, font=\footnotesize\bfseries] at (0, -4.20)
      {Perception};
    \draw[qfdthin] (0, -4.45) -- (4.95, -4.45);
    \draw[qfdalt1ln] (0.05, -4.80) -- (0.45, -4.80);
      \node[qfdalt1mk] at (0.25, -4.80) {};
      \node[anchor=west, font=\bfseries] at (0.55, -4.80)
        {Typoena (v0.1 target)};
    \draw[qfdalt2ln] (0.05, -5.25) -- (0.45, -5.25);
      \node[qfdalt2mk] at (0.25, -5.25) {};
      \node[anchor=west] at (0.55, -5.25) {reMarkable 2 + Type Folio};
    \draw[qfdalt3ln] (0.05, -5.70) -- (0.45, -5.70);
      \node[qfdalt3mk] at (0.25, -5.70) {};
      \node[anchor=west] at (0.55, -5.70) {Freewrite Traveler};
    \draw[qfdalt5ln] (0.05, -6.15) -- (0.45, -6.15);
      \node[qfdalt5mk] at (0.25, -6.15) {};
      \node[anchor=west] at (0.55, -6.15) {Freewrite Smart Typewriter};
    \draw[qfdalt4ln] (0.05, -6.60) -- (0.45, -6.60);
      \node[qfdalt4mk] at (0.25, -6.60) {};
      \node[anchor=west] at (0.55, -6.60) {Pomera DM250};
    \node[anchor=west, font=\scriptsize\itshape] at (0, -7.15)
      {0 = poor, 5 = excellent};
  \end{scope}

\end{qfdhouse}
\end{document}
```

## Perception scores (guessed)

Five products on the 0–5 scale, scored against each WHAT. Reference
configurations: **reMarkable 2 + Type Folio**, **Freewrite Traveler**,
**Freewrite Smart Typewriter**, **Pomera DM250** (DM250 has a reflective
monochrome LCD, not e-ink — flagged in W1 / W8). "Typoena" is the v0.1
target from `qfd.md` §2, not measured yet.

Freewrite Traveler scores assume the
[Sailfish firmware](https://getfreewrite.com/blogs/writing-success/freewrite-sailfish-firmware)
(released 2025-11-19), which rewrote the OS in Rust, cut keystroke latency
40–100 %, and trimmed power draw −30 % typing / −50 % idle on both
Traveler and Smart Typewriter Gen 3. Three rows rescored upward as a
result: W1 Traveler 3→4 / Smart 2→3 (Smart's larger panel still trails
Traveler by one notch), W5 both 3→4 (boot accelerated, no published
number), W9 both 1→2 (Rust rewrite explicitly unblocked features that
JS could not carry; still closed so neither reaches reMarkable's
hackable-Linux 3).

| ID  | WHAT (truncated)                                  | Typoena | reM. | Frw.T | Frw.S | Pom. | Rationale (shortest defensible)                                                                                                                                                                                                                                            |
| --- | ------------------------------------------------- | :-----: | :--: | :---: | :---: | :--: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| W1  | Sub-second response to typing                     |    4    |  1   |   4   |   3   |  5   | Typoena targets ≤200 ms; reMarkable e-ink visibly laggy on a typing-focused device — tested less responsive than Smart Typewriter, and latency is so load-bearing for W1 that it earns a 1 not a 2; both Freewrites post-Sailfish trimmed latency 40–100 % (Frw.T plausibly inside 200 ms; Frw.S still trails by one notch on larger panel); Pomera LCD ~zero. |
| W2  | Publishing is one deliberate action away          |    5    |  4   |   4   |   4   |  2   | Ctrl-G atomic; reMarkable + Freewrite cloud-sync is one-tap but not git; Pomera = USB/SD copy or QR transfer.                                                                                                                                                              |
| W3  | Pulling power never corrupts the file             |    4    |  4   |   2   |   2   |  2   | Typoena: atomic-rename + fsync. reMarkable journals. Freewrite + Pomera: forum reports of corruption on yank.                                                                                                                                                              |
| W4  | Provisioning never interrupts writing             |    5    |  2   |   2   |   2   |  5   | Typoena v0.1: build-time config (dev-only). reM/Frw need Wi-Fi + account. Pomera: literally none.                                                                                                                                                                          |
| W5  | Quick boot to a writing cursor                    |    4    |  3   |   4   |   4   |  5   | Typoena target ≤5 s. reMarkable cold-boots ~20 s (great from sleep). Both Freewrites accelerated post-Sailfish (no published number; were ~10–15 s e-ink wake). Pomera ~3 s.                                                                                               |
| W6  | Long sessions without crash / lag / drift         |    3    |  3   |   4   |   4   |  5   | Typoena unproven (1 h target). Freewrite famously stable (both variants). Pomera firmware is decades-mature.                                                                                                                                                               |
| W7  | Nothing on the device competes with prose         |    5    |  2   |   5   |   5   |  5   | reMarkable has apps, menus, drawing, PDFs. Freewrite + Pomera are single-purpose; Typoena by design.                                                                                                                                                                       |
| W8  | The UI never moves except when I move it          |    4    |  3   |   4   |   4   |  5   | reMarkable animates more; Typoena uses dirty-rects; Freewrites minimal motion; Pomera near-static LCD.                                                                                                                                                                     |
| W9  | Codebase absorbs the planned roadmap              |    4    |  3   |   2   |   2   |  1   | Modular Rust Typoena; reMarkable is hackable Linux; both Freewrites carry Sailfish (Rust rewrite explicitly unblocked features JS could not carry) but closed; Pomera closed firmware.                                                                                     |
| W10 | I can repair or fork it with hobbyist tools       |    5    |  4   |   2   |   2   |  1   | Typoena: open BOM + ESP32. reMarkable: rooted Linux + community ROMs. Freewrite + Pomera: closed.                                                                                                                                                                          |
| W11 | Multi-day battery life (v0.8 onward)              |    1    |  5   |   5   |   5   |  4   | Typoena v0.1 = wall-powered (battery deferred). reMarkable + both Freewrites legendary (~4 weeks; Sailfish trimmed −30 % typing / −50 % idle). Pomera ~24 h.                                                                                                               |
| W12 | Local-only files coexist with git scope           |    3    |  1   |   2   |   2   |  3   | Typoena v0.5+ design. reMarkable cloud-only. Freewrites have local + Postbox but no VCS. Pomera = pure local.                                                                                                                                                              |
| W13 | Typography sets a writing-tool tone               |    3    |  5   |   2   |   2   |  2   | Typoena v0.1: single mono (serif option in v1.0). reMarkable: rich type rendering. Freewrite + Pomera: utilitarian.                                                                                                                                                        |
| W14 | I can carry the device and write away from a desk |    2    |  4   |   5   |   1   |  5   | Typoena v0.1 wall-powered (ADR-008), no enclosure spec yet — desk-bound by design. reMarkable + Type Folio bag-friendly with bulk. Freewrite Traveler is the form-factor reference (~1.6 lb, folds). Smart Typewriter ~5 lb, desk-bound. Pomera DM250 pocketable foldable. |

**Totals** (sum across 14 WHATs, no weighting): Typoena 52, Pomera 50,
Freewrite Traveler 47, reMarkable 44, Freewrite Smart Typewriter 42
(Traveler pre-Sailfish 44; Smart pre-Sailfish 39; reMarkable W1 dropped
3→2→1 across two rounds of author testing — first to 2 after firsthand
typing, then to 1 once latency was recognised as the dominant W1
signal). Pomera closing to within 2 of
Typoena is W14 doing what W14 should — surfacing the dimension on
which v0.1's tethered MVP loses ground that v0.8 is expected to
recover. The "Pomera + Wi-Fi + git + hackable BOM" framing from
`README.md` still holds and reads stronger.

Weighted totals (Σ score × W weight) tell the same story with more
contrast — left as exercise; the unweighted view is enough to read the
picture.

### Caveats

- **Single-rater bias.** All thirteen rows are scored from the project
  author's POV. A reMarkable buyer would weight W11 (battery) at 10 and
  W12 (git) at 1, flipping the totals.
- **Configuration matters.** Freewrite Smart Typewriter and Traveler are
  both tracked; they diverge most on W1 / W5 because of display tech
  (Smart's larger panel is slower to refresh). Traveler is still the
  more direct competitor on form factor.
- **W3 / W6 Freewrite scores are anecdotal.** Forum reports, not bench
  data. Treat the 2 / 4 as "we'd need to test this" rather than fact.
- **No price column.** Typoena-as-BOM is materially cheaper than the
  competitors but cost is not a WHAT in `qfd.md` §1, so it's absent here.
  Worth a row if a v0.x WHAT ever calls it out.

## Reading the house

- **Importance (left column)** is the raw 1–10 weight from `qfd.md` §1, not
  a normalised %, so adding stays cheap when a WHAT shifts. Sum of weights
  is 103; treat each unit as ~0.97 % if you want a percentage view.
- **Roof** carries the §4 symbols translated into classical QFD glyphs:
  `++` strong reinforcement (`◎`), `+` mild reinforcement (`○`), `−` mild
  conflict (`×`), `−−` strong conflict (`⊗`).
- **Basement rows** are: v0.1 target → §3 column sum (`Σ` of
  `weight × strength`) → relative weight as integer % of total (1557).
  Relative weights round to 100.
- **H7, H10, H15** (Publish latency, binary size, build time) sit at the bottom
  of the basement — knowingly-paid costs per `qfd.md` §7, not signals to
  optimise harder.

## Regenerating

The matrix cells (`\node[qfdrel/{S,M,W}]`), roof symbols (`C-i-j` slots),
and basement Σ + Rel% are native to this file — re-score directly in the
TikZ source, then update the §3 priority list and §4 conflict list in
`qfd.md` to match the new picture.

When `qfd.md` §1 or §2 changes:

1. Importance column → §1 weight column.
2. HOW titles + v0.1 targets → §2 target column.
3. Recompute basement Σ for any HOW whose column changed: per-cell
   contribution = `(W weight) × (cell strength: 9 / 3 / 1 / 0)`.
4. Recompute relative weight: each Σ ÷ total Σ × 100, rounded to integer
   percent.

Perception scores are **not** derived from `qfd.md` — they live only in
this file. Update them when (a) a competitor ships a relevant change,
(b) measurement replaces a guess, or (c) a WHAT is added/removed in §1.
Each score keeps its one-line rationale in the table above.

If a renderer rejects the `tikz` fence, the file is still readable as
source — the placement comments name each WHAT, HOW, and cell. The
perception-scores table above is the human-readable fallback for the
right-hand zone of the diagram.
