easyfaa 0.20.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (207) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +131 -468
  3. data/README.md +49 -222
  4. data/app/assets/fonts/easy/outfit-latin-ext.woff2 +0 -0
  5. data/app/assets/fonts/easy/outfit-latin.woff2 +0 -0
  6. data/app/assets/images/easy/favicon.ico +0 -0
  7. data/app/assets/images/easy/favicon.svg +11 -0
  8. data/app/assets/images/easy/sprite.svg +52 -0
  9. data/app/assets/javascripts/easy/add_rows.js +38 -0
  10. data/app/assets/javascripts/easy/flyer.js +100 -0
  11. data/app/assets/javascripts/easy/highlight.js +54 -0
  12. data/app/assets/javascripts/easy/konami.js +73 -0
  13. data/app/assets/javascripts/easy/modal.js +49 -0
  14. data/app/assets/javascripts/easy/pin_code.js +43 -0
  15. data/app/assets/javascripts/easy/report_sort.js +57 -0
  16. data/app/assets/javascripts/easy/rotating_placeholder.js +35 -0
  17. data/app/assets/javascripts/easy/step_foot.js +17 -0
  18. data/app/assets/javascripts/easy/switches.js +96 -0
  19. data/app/assets/javascripts/easy/switches_address.js +39 -0
  20. data/app/assets/javascripts/easy/tabs.js +35 -0
  21. data/app/assets/javascripts/easy/theme.js +41 -0
  22. data/app/assets/stylesheets/easy/base.css +42 -0
  23. data/app/assets/stylesheets/easy/components.css +533 -0
  24. data/app/assets/stylesheets/easy/layout.css +47 -0
  25. data/app/assets/stylesheets/easy/tokens.css +11 -0
  26. data/app/controllers/easyfaa/errors_controller.rb +41 -0
  27. data/app/helpers/easyfaa/easy_helper.rb +58 -0
  28. data/app/models/aircraft_avatar.rb +61 -0
  29. data/app/views/easy/_ad_card.html.erb +16 -0
  30. data/app/views/easy/_ad_list.html.erb +11 -0
  31. data/app/views/easy/_flyer.html.erb +10 -0
  32. data/app/views/easy/_logo.html.erb +15 -0
  33. data/app/views/easy/_modal.html.erb +17 -0
  34. data/app/views/easy/_part_tabs.html.erb +24 -0
  35. data/app/views/easy/_pin_code.html.erb +10 -0
  36. data/app/views/easy/_report_head.html.erb +28 -0
  37. data/app/views/easy/mailer/_button.html.erb +10 -0
  38. data/app/views/easy/mailer/_card.html.erb +23 -0
  39. data/app/views/easy/mailer/_code.html.erb +28 -0
  40. data/app/views/easy/mailer/_code.text.erb +19 -0
  41. data/app/views/easy/mailer/_frame.html.erb +35 -0
  42. data/app/views/easy/mailer/_text.html.erb +7 -0
  43. data/app/views/easyfaa/errors/show.html.erb +17 -0
  44. data/app/views/layouts/easy/site.html.erb +55 -0
  45. data/app/views/layouts/easyfaa/errors.html.erb +30 -0
  46. data/config/aircraft_avatars.yml +26 -0
  47. data/lib/easyfaa/engine.rb +16 -43
  48. data/lib/easyfaa/version.rb +2 -2
  49. data/lib/easyfaa.rb +14 -35
  50. metadata +52 -181
  51. data/app/views/layouts/easyfaa.html.erb +0 -24
  52. data/app/views/recourses/_head.html.erb +0 -3
  53. data/art/autopilot.svg +0 -9
  54. data/art/cube.svg +0 -9
  55. data/art/design.svg +0 -8
  56. data/art/down.html.erb +0 -95
  57. data/art/easyfaa.svg +0 -7
  58. data/art/fountain.svg +0 -9
  59. data/art/goldrush.svg +0 -7
  60. data/art/houston.svg +0 -8
  61. data/art/icons.txt +0 -185
  62. data/art/index.html.erb +0 -157
  63. data/config/locales/easyfaa.en.yml +0 -7
  64. data/lib/easyfaa/copy.rb +0 -5
  65. data/lib/easyfaa/down.rb +0 -19
  66. data/lib/easyfaa/helpers/flows.rb +0 -53
  67. data/lib/easyfaa/helpers/heads.rb +0 -60
  68. data/lib/easyfaa/helpers/logos.rb +0 -43
  69. data/lib/easyfaa/helpers.rb +0 -11
  70. data/lib/easyfaa/marks.rb +0 -16
  71. data/public/404.html +0 -118
  72. data/public/_headers +0 -28
  73. data/public/bh/css/bh.css +0 -1
  74. data/public/bh/js/bh.js +0 -152
  75. data/public/bh/theme/bootstrap.css +0 -10
  76. data/public/bh/theme/dawn.css +0 -189
  77. data/public/bh/theme/dracula.css +0 -189
  78. data/public/bh/theme/gruvbox.css +0 -189
  79. data/public/bh/theme/monokai.css +0 -190
  80. data/public/bh/theme/nord.css +0 -189
  81. data/public/bh/theme/one_dark.css +0 -189
  82. data/public/bh/theme/solarized.css +0 -188
  83. data/public/bh/theme/tokyo_night.css +0 -189
  84. data/public/css/easyfaa.css +0 -1
  85. data/public/down/autopilot.html +0 -87
  86. data/public/down/cube.html +0 -87
  87. data/public/down/design.html +0 -87
  88. data/public/down/easyfaa.html +0 -84
  89. data/public/down/fountain.html +0 -87
  90. data/public/down/goldrush.html +0 -87
  91. data/public/down/houston.html +0 -87
  92. data/public/favicon/autopilot-180.png +0 -0
  93. data/public/favicon/autopilot-192.png +0 -0
  94. data/public/favicon/autopilot-512.png +0 -0
  95. data/public/favicon/autopilot-96.png +0 -0
  96. data/public/favicon/autopilot-dev.svg +0 -9
  97. data/public/favicon/autopilot.ico +0 -0
  98. data/public/favicon/autopilot.svg +0 -9
  99. data/public/favicon/autopilot.webmanifest +0 -12
  100. data/public/favicon/cube-180.png +0 -0
  101. data/public/favicon/cube-192.png +0 -0
  102. data/public/favicon/cube-512.png +0 -0
  103. data/public/favicon/cube-96.png +0 -0
  104. data/public/favicon/cube-dev.svg +0 -9
  105. data/public/favicon/cube.ico +0 -0
  106. data/public/favicon/cube.svg +0 -9
  107. data/public/favicon/cube.webmanifest +0 -12
  108. data/public/favicon/design-180.png +0 -0
  109. data/public/favicon/design-192.png +0 -0
  110. data/public/favicon/design-512.png +0 -0
  111. data/public/favicon/design-96.png +0 -0
  112. data/public/favicon/design-dev.svg +0 -8
  113. data/public/favicon/design.ico +0 -0
  114. data/public/favicon/design.svg +0 -8
  115. data/public/favicon/design.webmanifest +0 -12
  116. data/public/favicon/easyfaa-180.png +0 -0
  117. data/public/favicon/easyfaa-192.png +0 -0
  118. data/public/favicon/easyfaa-512.png +0 -0
  119. data/public/favicon/easyfaa-96.png +0 -0
  120. data/public/favicon/easyfaa-dev.svg +0 -7
  121. data/public/favicon/easyfaa.ico +0 -0
  122. data/public/favicon/easyfaa.svg +0 -7
  123. data/public/favicon/easyfaa.webmanifest +0 -12
  124. data/public/favicon/fountain-180.png +0 -0
  125. data/public/favicon/fountain-192.png +0 -0
  126. data/public/favicon/fountain-512.png +0 -0
  127. data/public/favicon/fountain-96.png +0 -0
  128. data/public/favicon/fountain-dev.svg +0 -9
  129. data/public/favicon/fountain.ico +0 -0
  130. data/public/favicon/fountain.svg +0 -9
  131. data/public/favicon/fountain.webmanifest +0 -12
  132. data/public/favicon/goldrush-180.png +0 -0
  133. data/public/favicon/goldrush-192.png +0 -0
  134. data/public/favicon/goldrush-512.png +0 -0
  135. data/public/favicon/goldrush-96.png +0 -0
  136. data/public/favicon/goldrush-dev.svg +0 -7
  137. data/public/favicon/goldrush.ico +0 -0
  138. data/public/favicon/goldrush.svg +0 -7
  139. data/public/favicon/goldrush.webmanifest +0 -12
  140. data/public/favicon/houston-180.png +0 -0
  141. data/public/favicon/houston-192.png +0 -0
  142. data/public/favicon/houston-512.png +0 -0
  143. data/public/favicon/houston-96.png +0 -0
  144. data/public/favicon/houston-dev.svg +0 -8
  145. data/public/favicon/houston.ico +0 -0
  146. data/public/favicon/houston.svg +0 -8
  147. data/public/favicon/houston.webmanifest +0 -12
  148. data/public/favicon.ico +0 -0
  149. data/public/font/bootstrap-icons-6LILWPE2.woff2 +0 -0
  150. data/public/font/bootstrap-icons-FRBPO3H7.woff2 +0 -0
  151. data/public/font/ibm-plex-sans-500-latin-LA7QXWWL.woff2 +0 -0
  152. data/public/font/ibm-plex-sans-500-latin-ext-X4QHZICY.woff2 +0 -0
  153. data/public/font/ibm-plex-sans-500-latin-ext.woff2 +0 -0
  154. data/public/font/ibm-plex-sans-500-latin.woff2 +0 -0
  155. data/public/font/ibm-plex-sans-500-vietnamese-24B6BSND.woff2 +0 -0
  156. data/public/font/ibm-plex-sans-500-vietnamese.woff2 +0 -0
  157. data/public/index.html +0 -165
  158. data/public/js/easyfaa.js +0 -1
  159. data/public/logo/autopilot.png +0 -0
  160. data/public/logo/autopilot.svg +0 -9
  161. data/public/logo/cube.png +0 -0
  162. data/public/logo/cube.svg +0 -9
  163. data/public/logo/design.png +0 -0
  164. data/public/logo/design.svg +0 -8
  165. data/public/logo/easyfaa.png +0 -0
  166. data/public/logo/easyfaa.svg +0 -7
  167. data/public/logo/fountain.png +0 -0
  168. data/public/logo/fountain.svg +0 -9
  169. data/public/logo/goldrush.png +0 -0
  170. data/public/logo/goldrush.svg +0 -7
  171. data/public/logo/houston.png +0 -0
  172. data/public/logo/houston.svg +0 -8
  173. data/public/page/400.html +0 -118
  174. data/public/page/404.html +0 -118
  175. data/public/page/406-unsupported-browser.html +0 -118
  176. data/public/page/422.html +0 -118
  177. data/public/page/500.html +0 -118
  178. data/public/site.webmanifest +0 -12
  179. data/public/theme/bootstrap.css +0 -10
  180. data/public/theme/dawn.css +0 -189
  181. data/public/theme/dracula.css +0 -189
  182. data/public/theme/gruvbox.css +0 -189
  183. data/public/theme/monokai.css +0 -190
  184. data/public/theme/nord.css +0 -189
  185. data/public/theme/one_dark.css +0 -189
  186. data/public/theme/solarized.css +0 -188
  187. data/public/theme/tokyo_night.css +0 -189
  188. data/public/v0.20.0/bh/css/bh.css +0 -1
  189. data/public/v0.20.0/bh/js/bh.js +0 -152
  190. data/public/v0.20.0/bh/theme/bootstrap.css +0 -10
  191. data/public/v0.20.0/bh/theme/dawn.css +0 -189
  192. data/public/v0.20.0/bh/theme/dracula.css +0 -189
  193. data/public/v0.20.0/bh/theme/gruvbox.css +0 -189
  194. data/public/v0.20.0/bh/theme/monokai.css +0 -190
  195. data/public/v0.20.0/bh/theme/nord.css +0 -189
  196. data/public/v0.20.0/bh/theme/one_dark.css +0 -189
  197. data/public/v0.20.0/bh/theme/solarized.css +0 -188
  198. data/public/v0.20.0/bh/theme/tokyo_night.css +0 -189
  199. data/public/v0.20.0/css/easyfaa.css +0 -1
  200. data/public/v0.20.0/font/bootstrap-icons-FRBPO3H7.woff2 +0 -0
  201. data/public/v0.20.0/font/ibm-plex-sans-500-latin-LA7QXWWL.woff2 +0 -0
  202. data/public/v0.20.0/font/ibm-plex-sans-500-latin-ext-X4QHZICY.woff2 +0 -0
  203. data/public/v0.20.0/font/ibm-plex-sans-500-latin-ext.woff2 +0 -0
  204. data/public/v0.20.0/font/ibm-plex-sans-500-latin.woff2 +0 -0
  205. data/public/v0.20.0/font/ibm-plex-sans-500-vietnamese-24B6BSND.woff2 +0 -0
  206. data/public/v0.20.0/font/ibm-plex-sans-500-vietnamese.woff2 +0 -0
  207. data/public/v0.20.0/js/easyfaa.js +0 -1
data/CHANGELOG.md CHANGED
@@ -5,554 +5,217 @@ All notable changes to this project will be documented in this file.
5
5
  For more information about changelogs, check [Keep a Changelog](http://keepachangelog.com) and
6
6
  [Vandamme](http://tech-angels.github.io/vandamme).
7
7
 
8
- ## [Unreleased]
8
+ ## 1.0.0 - 2026-11-12
9
9
 
10
- ## 0.20.0 - 2026-09-25
10
+ * [BREAKING] The gem is `easyfaa`, not `wordmark`, and its module is `EasyFAA`: an app's Gemfile
11
+ says `gem 'easyfaa', '~> 1.0'`, names its site with `EasyFAA.site` and routes a page of its own
12
+ to `easyfaa/errors#show`. The easy design system keeps every name an app links
13
+ * The site is at easyfaa.com/design, and design.easyfaa.com redirects there
11
14
 
12
- * [BREAKING] The gem is `easyfaa`, and so is everything in it
15
+ ## 0.36.1 - 2026-11-12
13
16
 
14
- `gem 'easyfaa'` replaces `gem 'houseaccount'`, and the module is `Easyfaa`. Every helper
15
- swaps its prefix — `easyfaa_logo`, `easyfaa_head_tags`, `easyfaa_layer`, `easyfaa_tags`,
16
- `easyfaa_icons` — the layout a host renders is `layouts/easyfaa`, the locale keys sit
17
- under `easyfaa.`, and the two files are `/css/easyfaa.css` and `/js/easyfaa.js`. The site
18
- is https://design.easyfaa.com, and every URL a page pinned there moves with it.
17
+ * A browser without `:focus-visible` rings what has focus, and shows a `has-tip` bubble on hover
19
18
 
20
- * [BREAKING] The house wears the horizon, in sky and midnight
19
+ ## 0.36.0 - 2026-11-12
21
20
 
22
- The house's mark is an attitude indicator: a level horizon, the ground below it filled,
23
- the aircraft symbol above. `easy` is set in the sky, `#5aa9e6`, and `faa` in midnight,
24
- `#0b1e3a` (`#cfe3f6` in the dark); every drawing is stroked in the sky, so the family
25
- stays one set. An app the family has no mark for, and every page's footer, wears it.
21
+ * `appliance-card`: a plane card about an appliance, its head gray as a part's and embossed with a radio and a
22
+ battery, a propeller and an oxygen bottle
26
23
 
27
- * [BREAKING] The cube is the `cube` app's
24
+ ## 0.35.0 - 2026-11-12
28
25
 
29
- It stays in the family under its own name — `easyfaa_logo app: :cube`, `/favicon/cube.svg`,
30
- `/down/cube.html` — and is the house's no longer.
26
+ * [BREAKING] `sky-band` is one size, the one `slim` drew, and `slim` is gone
31
27
 
32
- * [BREAKING] The lockup is set in IBM Plex Sans 500
28
+ * `add-rows`: things added together, a row at a time from "+ Add …", each with its Remove, and the button that counts
29
+ and saves them, drawn by `easy/add_rows`
33
30
 
34
- Quicksand is gone, and `.quicksand` with it: a heading beside a lockup says `.plex`. The
35
- face is served from `/font` in the same three ranges, and its ascender is Quicksand's
36
- 0.74em, so every mark keeps its size and nudge.
31
+ * `part-card`: a plane card about a part, its head gray and embossed with a wrench and a bolt, a gear and a hex nut
37
32
 
38
- ## 0.19.1 - 2026-09-20
33
+ ## 0.34.1 - 2026-11-12
39
34
 
40
- * [CHANGE] The bundle is not published to npm
35
+ * `step-foot` spans the window under a hairline, whatever holds it, and the `flow-card` it ends has no margin under it
41
36
 
42
- Nothing installed it from there: every app on this gem is a Rails app, and the two files a
43
- page off the gem links come from the site, which keeps every version under its own path.
44
- The package stays for what builds the bundle, and `private` is what says so.
37
+ ## 0.34.0 - 2026-11-12
45
38
 
46
- The README said the bundle carried bh's stylesheet and script inside it, which stopped
47
- being true in 0.18.0. It says what the two files hold now, and where bh's own go under them.
39
+ * [BREAKING] A link has no underline but inside a sentence and under the pointer, where its blue deepens; the footer's are underlined
48
40
 
49
- ## 0.19.0 - 2026-09-19
41
+ * [BREAKING] `pill` is one size, 36 tall, raised, and still under the pointer; `pill soft` is white with dark words, and `small` is gone
50
42
 
51
- * [FEATURE] The head of an admin screen is drawn here
43
+ `--color-primary-strong`, `--shadow-raise`, `--shadow-raise-hover` and `--shadow-sunk` are the tokens they are drawn with.
52
44
 
53
- recourse draws a `recourses/head` partial where a view path supplies one, and this gem
54
- supplies it: the house's two files and the icons a tab wears. An app on both gems keeps
55
- no partial of its own, and one wanting something else writes its own, which is found
56
- first.
45
+ * [BREAKING] `alert-cta` is the main button, large, and `alert-on` a green `removable`; `mini` is a field and a button apart
57
46
 
58
- ## 0.18.0 - 2026-09-19
47
+ * `removable`, `switch`, `plus-link`, `go-link` and `step-foot` (with `easy/step_foot`), each with its rule in the guide
59
48
 
60
- * [BREAKING] The bundle is the house's layer alone
49
+ * A field is sunk, the home search's border is gray until typed in, the step numbers are gray, and the recent pages are `removable`
61
50
 
62
- It carried bh's stylesheet and script inside it, so a page linking this one got Bootstrap
63
- and the house together in 378K. It carries neither now: a page links bh's files first and
64
- this one's after, which is what `houseaccount_layer` draws, and the house stylesheet is
65
- 12K. `houseaccount_tags` draws the house's two alone, for a page that already has bh's.
51
+ ## 0.33.4 - 2026-11-12
66
52
 
67
- * [BREAKING] `flow` is this gem's own
53
+ * The email carrying a code names it again in a plain sentence, "Type 123456 in the window you left open.", for Apple Mail to read
68
54
 
69
- It wrapped bh's with `super`, which took an `include` ordering between two engines to
70
- make work. bh no longer draws a signup page at all, so this one draws the whole of it.
71
- `footer:` is `links:`, and `header:` is gone -- the lockup and the wall are what a house
72
- flow is rather than options a caller passes. `logo:` is `href:`.
55
+ ## 0.33.3 - 2026-11-12
73
56
 
74
- * [BREAKING] `houseaccount_url` goes, with `HouseAccount.url` and `HouseAccount::URL`
57
+ * The email carrying a code calls it a "verification code", the words Apple Mail is known to offer a code to its field by
75
58
 
76
- Nothing called it. The static pages name the design site outright.
59
+ ## 0.33.2 - 2026-11-12
77
60
 
78
- * [BREAKING] The `recourses/head` partial goes
61
+ * A search leaves a row's forms out: `easy/switches` matches the words, and `easy/highlight` marks them, outside any `form`
79
62
 
80
- It was this gem reaching toward another by the name of its partial. An app that wants the
81
- house layer on the pages recourse draws writes those two lines itself, which is one file
82
- in the app that already knows about both.
63
+ ## 0.33.1 - 2026-11-12
83
64
 
65
+ * `mark.search-hit` takes no room of its own: no padding and no bold, so the words around it stay where they were;
66
+ in a flex or grid box, `easy/highlight` keeps the text one piece, so a mark no longer loses the space beside it
84
67
 
85
- ## 0.17.0 - 2026-09-18
68
+ ## 0.33.0 - 2026-11-12
86
69
 
87
- * [FEATURE] bh 6.6, which draws a picture in a bubble as a thumbnail
70
+ * `easy/highlight` marks the words of a search in the rows it leaves, as `mark.search-hit`
88
71
 
89
- At the height every other picture on these screens is drawn at. The note over a thread
90
- is opaque and centred with it: it had named a background variable this bundle does not
91
- define, and drew none.
72
+ `easy/report_head` links it with its search, and `easy/switches` calls it at each draw.
92
73
 
93
- ## 0.16.0 - 2026-09-18
74
+ * [BREAKING] `empty-state` is gone: an empty list and a list left empty by its switches both say so as `none-here`
94
75
 
95
- * [FEATURE] bh 6.5, which carries a picture in a bubble and a note over a thread
76
+ * [BREAKING] `easy/ad_list` takes `size:`: with no card it is the `none:` line alone, and a list left empty by its
77
+ switches says "Nothing matches the filters above."
96
78
 
97
- `Bh::Message` takes `photos`, drawn under the words in the same bubble, and `chat_with`
98
- takes a `note:` that holds the top while the thread scrolls under it.
79
+ * `easy/tabs` opens the tab whose panel holds what the address names, and brings it into view
99
80
 
100
- * [FIX] The shell fills the screen in whole pixels
81
+ * `easy/switches` draws again when asked, keeps a row, and hides a group left empty
101
82
 
102
- `100dvh` computes to a fraction on a scaled display, and the tenths over are a scrollbar
103
- the page cannot use beside the one its content already has.
83
+ A page that redraws its rows or its switches calls `window.easySwitches()`; a row carrying
84
+ `data-keep` shows whatever its switch says, until a switch is flipped or a word typed; a
85
+ `js-group` hides while no row inside it shows. The switches are read at each draw.
104
86
 
105
- ## 0.15.0 - 2026-09-18
87
+ * `easy/switches_address` keeps the switches and the search of a `js-switches` box carrying `data-address` in the address
106
88
 
107
- * [Breaking change] The nine palettes move to bh as well
89
+ ## 0.32.0 - 2026-11-12
108
90
 
109
- `dracula`, `nord`, `solarized` and the rest are editor colour schemes restating Bootstrap's
110
- own families — nothing in them is this house's, which is the test that moved everything
111
- else. They are bh's now, and the build copies them out of the gem to `public/theme/`, so
112
- every URL a host has ever linked answers exactly as before.
91
+ * `easy/part_tabs` draws the parts of an aircraft as tabs over a section each, and `easy/ad_list` a list of ADs
113
92
 
114
- * [Breaking change] Bootstrap 6 moves to the `bh` gem, which this one now depends on
93
+ Every page that lists ADs part by part hands `easy/part_tabs` its parts (`id:`, `name:`, `icon:`,
94
+ `count:`, `dot:`, `aside:`) and draws each section in its block; `easy/ad_list` is the list of
95
+ cards under its line for none (`none:`, `any:`). The tabs, the switches and the counts read that
96
+ one page.
115
97
 
116
- Most of what had grown here was not the house's: a combobox, a 6-digit code, a dialog, a
117
- toast, a thread of messages and twenty-two Stimulus controllers are Bootstrap 6 with the
118
- markup written once, and are worth the same to any Rails app. They live in `bh` now, along
119
- with the form builder, nine stylesheets and Bootstrap itself. This gem depends on it and
120
- bundles it, so `css/houseaccount.css` and `js/houseaccount.js` still carry everything they
121
- carried before and a host changes nothing.
98
+ * `easy/report_sort` flips every list `sort_list` names, and `easy/ad_card` carries its number as `data-sort`
122
99
 
123
- What a host does have to change is where it reaches for a name. `HouseAccount::Message` is
124
- `Bh::Message` and `HouseAccount::FormBuilder` is `Bh::FormBuilder` — both kept under the
125
- house's names, so neither breaks — but the locale keys moved: `houseaccount.all`,
126
- `.ask`, `.clear`, `.close`, `.more`, `.no_results`, `.okay`, `.search`, `.send`, `.typing`
127
- and `.ago` are now `bh.*`, and a host that overrode one overrides it there. The meta that
128
- words a confirmation's other button is `bh-cancel` rather than `houseaccount-cancel`.
100
+ ## 0.31.0 - 2026-11-11
129
101
 
130
- * [Breaking change] `flow` takes what the page stands on rather than assuming it
102
+ * `easy/mailer/frame` draws the page of any email, and `easy/mailer/card`, `text` and `button` what goes on it
131
103
 
132
- bh's `flow` knows nothing of a lockup or a wall. The house's still draws both — `flow logo:`
133
- is unchanged — but every other option is now the column's, so a page standing on something
134
- of its own names the controller that paints it.
104
+ The frame is the logo, what its block draws and the site; a card is white under a navy head
105
+ (`label:`, `title:`, `note:`), its block rows of `text` and a `button`. `easy_mailer_font` names the
106
+ fonts for a row an app writes itself. The email carrying a code is drawn with them, unchanged.
135
107
 
136
- * [Breaking change] The npm package ships the built tree alone
108
+ ## 0.30.0 - 2026-11-11
137
109
 
138
- It used to export `app/javascript` and `app/stylesheets` for a host that would rather
139
- bundle the sources itself. Those sources now reach for bh, which is a gem and cannot be
140
- resolved from `node_modules` — there is no npm package of bh and there will not be one —
141
- so the exports go and the package is `public/css`, `public/js`, `public/font` and
142
- `public/theme`: exactly what the CDN links in the README serve.
110
+ * `easy/ad_card` draws one AD of an `ad-card-list`, and `easy_level_chip` its level
143
111
 
144
- ## 0.14.2 - 2026-09-18
112
+ The card takes the AD as plain values (`number:`, `href:`, `subject:`, `title:`, `part:`, `level:`,
113
+ `kind:`, `tie:`, `effective:`, `data:`); rendered as a layout, its block is what the page says
114
+ under the heading: a `why-box`, what replaced it.
145
115
 
146
- * [Fix] A conversation reads at the house's own size wherever it is drawn
116
+ * [BREAKING] `easy/switches` reads one row of switches: `data-row` is gone, and so is `switches parts`
147
117
 
148
- A bubble took its type from the page around it, so a chat on a host that compacts its
149
- body for tables dense with figures came out smaller than the same chat on a page that
150
- does not. A sentence somebody typed is prose whatever the table beside it needs, so
151
- `.chat-bubble` and the field under it say their own size.
118
+ The parts of an aircraft are tabs (`part-tabs`), never switches.
152
119
 
153
- * [Fix] A bubble is read from its start inside a flow
120
+ ## 0.29.0 - 2026-11-11
154
121
 
155
- A flow centres a card's words, which suits a heading and a one-line answer and not an
156
- answer long enough to wrap: a paragraph is read down an edge rather than about a middle.
122
+ * `easy/switches` recounts a tab as its panel's rows show or hide
157
123
 
158
- * [Fix] A focus ring is not painted over by the link below it
124
+ Inside `js-switches`, a tab of a `js-tabs` whose number carries `js-count` counts the rows left
125
+ in its panel that carry `data-counted`: the ADs in force, not the ones that do not apply.
159
126
 
160
- The ring is an outline with an offset, drawn outside the box it rings and taking no room,
161
- so the next link's own background — the tint an active row wears — covered the half that
162
- overlapped. The focused link is lifted above its siblings, the way the navbar already is
163
- over the table under it.
127
+ ## 0.28.0 - 2026-11-11
164
128
 
165
- ## 0.14.1 - 2026-09-17
129
+ * `easy/switches` makes the counts of a `switches` row show or hide the rows of their state
166
130
 
167
- * [Fix] A confirm asks about the link that was clicked rather than whatever holds the focus
131
+ Inside `js-switches`, anything with a `data-state` is a row; a count with `data-off="true"`
132
+ starts off, words typed in the search narrow the rows too, and a `js-none` line shows when
133
+ nothing is left. `easy/report_head` loads it with its switches. A second row of switches named
134
+ by `data-row` reads that attribute instead, and the rows of switches narrow each other.
168
135
 
169
- * [Change] The showcase demonstrates the confirm without a bare dialog standing beside it
136
+ ## 0.27.0 - 2026-11-11
170
137
 
171
- ## 0.14.0 - 2026-09-17
138
+ * [BREAKING] `field-list` draws no line over each field: the space between them sets them apart
172
139
 
173
- * [Feature] A table's rows can be dragged into an order
140
+ * `empty-state`, `steps-bar`'s `is-done` and `show-keys`, `part-tabs-dot` and `level-chip due`, as
141
+ easyAnnual drew them on its own
174
142
 
175
- The `sortable` controller, which is what a recourse page with a grip beside each row
176
- names: a row is picked up by its grip and dropped somewhere else in the table, and the
177
- place it landed in is PATCHed to the URL that row carries. Only the row that moved is
178
- reported — the server shifts whatever it displaced, being the only one that knows how
179
- many rows stand behind this page — and nothing is rendered from the answer, since the
180
- row is already where it was dropped and redrawing the table under the cursor that
181
- dropped it is the thing to avoid. A move the server refuses reloads the enclosing
182
- frame, so a row never sits somewhere the database never agreed to, and a refresh
183
- broadcast arriving mid-drag is sat out the way the search form sits one out.
143
+ ## 0.26.0 - 2026-11-11
184
144
 
185
- SortableJS does the dragging, bundled like everything else here. Its own two classes
186
- are styled beside the table's: the space a row will land in wears the tint a kept row
187
- wears, and the grip is `grab`, then `grabbing` while it is held — the whole of the
188
- affordance, since the icon already says what it is. `touch-action` is taken off that
189
- square alone, a phone scrolling a table by dragging anywhere else on it.
145
+ * [BREAKING] The layout runs the theme itself, with `easy/theme`
190
146
 
191
- * [Fix] A question half typed survives an answer landing: the field is Turbo's to leave alone,
192
- and is emptied once the question it held has gone rather than by the morph
147
+ The header's button and any radio buttons inside `js-theme-choice` (`light`, `dark`,
148
+ `device`) pick the theme with no script of the app's. An app that ran its own on `js-theme`
149
+ removes it, or each click turns the theme twice.
193
150
 
194
- ## 0.13.3 - 2026-09-17
151
+ * `easy/tabs` shows one panel per tab of a `part-tabs` with `js-tabs`, and keeps the tab in the address
195
152
 
196
- * [Change] The showcase leads with the themes, and says less everywhere else
153
+ ## 0.25.0 - 2026-11-11
197
154
 
198
- The palette toggle repaints everything under it, so it stands first, and the section is
199
- Themes — the word the folder, the id and the files have always used. Its button names the
200
- mode it switches to and nothing else. Icons lost the last paragraph on the page that
201
- described what the thing under it draws, and on a phone the two card URLs show the path
202
- without the origin there is no room for.
155
+ * [BREAKING] `has-tip` is the one tooltip: a bubble over a control that is off, saying why
203
156
 
204
- * [Fix] The README pins a version a host can install
157
+ `tooltip`, `tooltip-trigger` and `tooltip-pop` are gone: easyfaa.com, their only user, writes
158
+ on each card what they said. `has-tip` takes its text from `data-tip` and needs no script.
205
159
 
206
- Three 0.13 releases went out while the README still taught `~> 0.12.0`, which stops short
207
- of 0.13: a pin that cannot resolve the gem it appears in. It pins `~> 0.13.0` now, every
208
- example URL names this release, and `package-lock.json`, left at 0.12.0 by the same three
209
- releases, carries the version its package does.
160
+ * What easyFAA's and easyAnnual's pages both drew on their own is shared: `logo`, `legal`,
161
+ `none-here`, `alert-cta` and `flow-hero` (with `free` and `pulse`)
210
162
 
211
- ## 0.13.2 - 2026-09-17
163
+ `render layout: "easy/logo"` draws the paper plane and "easy", and the app hands over the
164
+ letters of the rest of its name. The paper plane's `easy/favicon.svg` and `easy/favicon.ico`
165
+ are under `app/assets/images`.
212
166
 
213
- * [Fix] The cell a label wraps is `flow-field`; `form-field` is Bootstrap's, and its rules applied
167
+ * [BREAKING] Rollaway is Ramp, with a mark of its own: a launch ramp, in the slate telex wears
214
168
 
215
- ## 0.13.1 - 2026-09-17
169
+ `/logo/rollaway.*` and `/favicon/rollaway*` are gone from design.easyfaa.com.
216
170
 
217
- * [Fix] A card too short for what does not scroll scrolls whole, rather than spilling it
171
+ * A mark for telex, the app that reads the files mechanics send: a teleprinter, in slate
218
172
 
219
- * [Change] A ticked box sits beside its words with room between them, and counts as a field
173
+ ## 0.24.0 - 2026-11-10
220
174
 
221
- ## 0.13.0 - 2026-09-17
175
+ * [BREAKING] The easy design system is the one front end: the bh layer is gone
222
176
 
223
- * [Feature] The ascending sort glyph
177
+ `/css/easyfaa.css`, `/js/easyfaa.js`, the themes, the IBM Plex and Bootstrap Icons fonts,
178
+ `layouts/easyfaa`, the signup flow and its wall, `easyfaa_head_tags`, `easyfaa_tags`,
179
+ `easyfaa_icons`, `easyfaa_logo`, `Wordmark.app`, `Wordmark.one_time_code`,
180
+ `Wordmark::FormBuilder`, `Wordmark::Message`, `Wordmark::MARKS` and the `easyfaa` npm package
181
+ are gone, and so is the dependency on `bh`. The engine no longer serves `/css`, `/js`,
182
+ `/theme`, `/font`, `/logo`, `/favicon` or `/page`: an app draws with the easy design system
183
+ under `app/assets` and `app/views`, and answers its errors with `Wordmark::ErrorsController`.
224
184
 
225
- `bi-sort-up` joins `bi-sort-down` in the subset. A table heading says which way its column
226
- is sorted, and until now only one of the two directions had a glyph to say it with — the
227
- other drew an empty box, since a name the subset does not carry has no `content` rule and
228
- no code point in the font.
185
+ * design.easyfaa.com is the style guide, in the easy design system, and the marks
229
186
 
230
- `unicon` names the pair as `:sort_asc` and `:sort_desc` from 3.7.0, which is where recourse
231
- reads them from.
232
- * [Change] The card is as wide as what it holds, and a page asking one question says `30rem`
233
- * [Change] A legend wears nothing of ours
234
- * [Change] A form of more than one field reads its rows from where their words start
235
- * [Feature] `flow-middle` stands a card as tall as the rest and holds its content in the middle
236
- * [Feature] The builder dresses every kind of field, so a page writes no Bootstrap class
237
- * [Feature] `form.combobox` is a select the bundle searches, in the house's own words
238
- * [Change] A fieldset carries its own spacing and the gap between its controls
239
- * [Change] A rule inside the card is given room either side of it
240
- * [Feature] `form.check` is a box and the words beside it, which no page draws by hand now
241
- * [Feature] `form.label` with words and a block wraps the control, so a wide card takes two columns
242
- * [Feature] `flow-scroll` gives any long card the height, the inner scroll and the fixed foot a chat's card has
187
+ `rake pages` renders it from the dummy app's `/showcase`, with the site's not-found and down
188
+ pages, which are the apps' own.
243
189
 
244
- ## 0.12.0 - 2026-09-17
190
+ ## 0.23.0 - 2026-11-10
245
191
 
246
- * [Change] The showcase shows rather than describes
192
+ * [FEATURE] The easy design system, from `drive`: every easyFAA app's pages are drawn with it
247
193
 
248
- The page at design.houseaccount.com carried a paragraph over every component saying what
249
- the component below it was about to do. Each is gone: the thing itself is on the page, a
250
- few pixels under where the description stood, and it is the one that cannot go stale. What
251
- is left is the name of each component and, where a path is named, a link to the file.
194
+ `layouts/easy/site`, the stylesheets `easy/tokens`, `easy/base`, `easy/layout` and
195
+ `easy/components`, the Outfit font, the icon sprite, the scripts in `easy/` (modal, pin code,
196
+ flyer, konami, report sort, rotating placeholder), the partials `easy/pin_code`, `easy/modal`,
197
+ `easy/flyer`, `easy/report_head` and `easy/mailer/code`, `easy_icon`, `easy_icon_href`,
198
+ `easy_aircraft_avatar` and `AircraftAvatar`, all by the names drive gave them, and the style
199
+ guide at the dummy app's `/guide`.
252
200
 
253
- The page reads down the middle now, and its sections stand in the order somebody comes for
254
- them: Components — with Chat, Wall and Tables as subsections of it, which is what they
255
- always were — then Error pages, Palettes and Icons, which is Favicons with the drawing
256
- under `/logo` as its first column. The header says what the page is in one sentence: the
257
- components, error pages, palettes and icons shared by Fountain, Goldrush, Houston and
258
- Autopilot, each mark linking to its own host.
201
+ * [BREAKING] The error pages and `/down.html` are the easy ones, named by `Wordmark.site`
259
202
 
260
- ## 0.11.0 - 2026-09-16
203
+ A 400, 404, 422 or 500 is answered by `Wordmark::ErrorsController`, and `/down.html` by its
204
+ `down`, naming easyFAA or the site `Wordmark.site` names for the request. `Wordmark::Down`
205
+ is gone, and so is the `wordmark.down` initializer. The site keeps its pages under `/down/`.
261
206
 
262
- * [Feature] The built stylesheet and script are in the package, for a page that links them
207
+ * [BREAKING] Ruby 3.4 or later
263
208
 
264
- The package carried its sources alone, which a bundler can read and a browser cannot: the
265
- script opens on three bare specifiers nothing resolves without an import map, and the
266
- stylesheet is fourteen `@import` lines a browser would fetch one after another. So the
267
- built `css/`, `js/`, `theme/` and `font/` ship beside them, and a page on any host links
268
- one file from a CDN holding the package — `cdn.jsdelivr.net/npm/houseaccount@0.11.0/public/` —
269
- at a version that is owed those bytes for good, npm never letting one be written twice.
209
+ ## 0.22.0 - 2026-11-10
270
210
 
271
- * [Change] Every URL inside the stylesheet is relative
211
+ * The front end every easyFAA app shares, from one source tree: the `wordmark` gem, the site at
212
+ design.easyfaa.com and the `easyfaa` npm package
272
213
 
273
- It named the site's own root, `/font/…`, which is right in one place and wrong everywhere
274
- else: under a version prefix, or on a CDN, the font was asked for at a path no host had.
275
- `../font/…` resolves against wherever the stylesheet is read from, so one build serves the
276
- root, the versioned copy and the package alike — and the versioned copy, being the same
277
- bytes as the unversioned one, costs the repository nothing to keep.
214
+ A stylesheet and a script layered over bh, the layout and helpers that draw a page's head,
215
+ lockup, down page and one-time code, and a mark for each of easyFAA's apps: tower, hangar,
216
+ lens, rollaway, dataplate, data, refinery, stockroom, blackbox, drive, mirroring and
217
+ wordmark, beside the house's horizon, design's pencil and the cube. Each app's mark is
218
+ drawn at 36 on the 512 grid in a hue of its own from easyfaa.com's tokens, light and dark.
278
219
 
279
- ## 0.10.1 - 2026-09-16
280
-
281
- * [Fix] The package a host installs from npm can be bundled
282
-
283
- Every controller reaches Bootstrap's classes through the bare `bootstrap` specifier, which
284
- this repo's own build aliases to the bundle under `vendor/`. A host installing the package
285
- had neither: Bootstrap 6 is not on npm, and `exports` did not name the vendored bundle, so
286
- the alias that would have fixed it could not resolve either. The bundle is exported as
287
- `houseaccount/bootstrap`, and the README says which alias to point at it.
288
-
289
- ## 0.10.0 - 2026-09-14
290
-
291
- * [Fix] A page is as tall as the window a phone actually shows
292
-
293
- The body asked for `100vh`, which on a phone measures the window with the browser's own
294
- bars hidden — they are not, until somebody scrolls. So every flow page stood taller than
295
- what could be seen: a scrollbar where the content fit, and a foot resting below the fold
296
- that cost a scroll to reach. `100svh` is the window with the bars showing, and the body
297
- wears `house-page` for it rather than Bootstrap's `min-vh-100`.
298
-
299
- * [Change] A new set of trades on the wall, and the house's mark among them
300
-
301
- Thirteen drawings rather than fourteen: the roller, ladder, frame, plunger, can, hard hat,
302
- spray, lock, plug, broom, nut, level and the cube. The four apps' own marks are gone from
303
- it, and with them the grid that placed each one deliberately — every mark is dealt the
304
- same way now, the cube included.
305
-
306
- ## 0.9.0 - 2026-09-14
307
-
308
- * [Breaking change] A one-time code carries the line for the phone again
309
-
310
- 0.8.0 took `@host #code` out because it is plainly visible in the message that arrives.
311
- Visible is what it is for: it is Apple's own format, it tells a reader which site the code
312
- belongs to, and it binds the code to that domain so no other site can ask for it. Without
313
- it iOS falls back to guessing at the text, which it does not do reliably — the suggestion
314
- above the keyboard stopped appearing. `HouseAccount.one_time_code` takes `host:` again,
315
- defaulting to the application's own.
316
-
317
- * [Fix] A seventh digit leaves no bar behind in the first slot
318
-
319
- The real field lies transparently across all six slots, and its hidden text sits crammed
320
- against the left edge rather than under them. A keystroke iOS cannot place answers by
321
- selecting inside that field, and the grab handles it draws for a selection are its own to
322
- paint — so one surfaced over the first slot. The selection is collapsed back to the end
323
- once the code is whole.
324
-
325
- ## 0.8.1 - 2026-09-14
326
-
327
- * [Fix] The wall is drawn again after a page Turbo morphs
328
-
329
- A refresh in place is told what the server sent, and the server sends no wall, so the
330
- cyanotype came down on any page that redirected to itself — a form refused, say — and the
331
- controller, still connected, never heard of it.
332
-
333
- ## 0.8.0 - 2026-09-14
334
-
335
- * [Breaking change] A one-time code is the sentence alone, without the line for the phone
336
-
337
- `written` carried a second paragraph, `@host #code`, there for Safari and iOS to read and
338
- offer the code above the keyboard. It is plainly visible in the message that arrives, so it
339
- is gone: `written` is now the sentence `spoken` says, with its digits together, and
340
- `HouseAccount.one_time_code` no longer takes `host:`.
341
-
342
- ## 0.7.0 - 2026-09-14
343
-
344
- ## 0.6.0 - 2026-09-14
345
-
346
- * [Breaking change] `HouseAccount.one_time_code` answers the words in both voices
347
-
348
- It gave back the text a code is sent in; it gives back a `HouseAccount::Copy` now, whose
349
- `written` is that same text and whose `spoken` is the sentence alone with the digits one at
350
- a time, for an app reading a code out over a call. Every caller gains `.written`.
351
-
352
- ## 0.5.0 - 2026-09-14
353
-
354
- * [Feature] The `map` controller draws a page's rows on a Google map
355
-
356
- `data-controller='map'` on an element sized for it, with the host's key and map ID in
357
- `map-key-value` and `map-id-value`, draws the rows of a page: `map-places-value`, a list
358
- of Google place IDs, filled in as areas on the boundary layer `map-boundary-value` names —
359
- `POSTAL_CODE`, `ADMINISTRATIVE_AREA_LEVEL_2` — or pinned where no layer is named, and
360
- `map-points-value`, a list of `[latitude, longitude]` pairs, pinned as they are. The map
361
- is fitted round whatever it drew, and `.recourse-map` gives it the height a table takes.
362
- Recourse's `.map` pages are what name it.
363
-
364
- ## 0.4.0 - 2026-09-14
365
-
366
- * [Feature] `houseaccount_icons` names an app's icons on its own, and answers recourse's head
367
-
368
- The four icon links `houseaccount_head_tags` wrote are a helper of their own, for a head
369
- the host draws itself, taking another app of the family by name where a page should wear
370
- the house's cube rather than the app's. The gem also ships `recourses/_head.html.erb`
371
- calling it, so a host of recourse 5.1 wears its own cube on every admin tab with nothing
372
- written.
373
-
374
- * [Fix] The site answers a missing path with the not-found page, not the showcase
375
-
376
- Cloudflare Pages serves `index.html` at 200 for any path without a file unless a root
377
- `404.html` exists; a stylesheet asked for at a version the site did not carry came back
378
- as HTML. The branded not-found page now sits at the root as well.
379
-
380
- * [Fix] A chat's field takes focus without scrolling the page to it
381
-
382
- The showcase opened scrolled down to its chat, since the thread controller focused the
383
- field on load and the browser followed. Focus no longer scrolls; a chat page is sized to
384
- the window, so its field is in view regardless.
385
-
386
- ## 0.3.1 - 2026-09-14
387
-
388
- * [Fix] The gem ships its layout
389
-
390
- 0.3.0 left `app/views` out of the gem along with the sources the build compiles, so a
391
- host asking for `layout 'houseaccount'` found no template. The layout ships; the
392
- JavaScript, stylesheet and font sources still stay behind.
393
-
394
- ## 0.3.0 - 2026-09-14
395
-
396
- * [Fix] A chat scrolls inside its card, and the page stands still
397
-
398
- The flow holding a thread is a flex item of `main`, and `flex: 1` sized it to its content
399
- over the height it was given, so a long thread grew the page and the way out scrolled off.
400
- The column is `flex: none` at the window's height now, and only the thread scrolls.
401
-
402
- * [Fix] Sending a question keeps the reader where they were
403
-
404
- The ask form under a chat asks Turbo to `replace`, so the redirect back to the page it is
405
- on is a refresh — morphed in place, scroll kept — rather than a visit landing at the top.
406
-
407
- * [Fix] A Turbo refresh morphs the page and keeps the scroll
408
-
409
- The head tags now say `turbo-refresh-method: morph` and `turbo-refresh-scroll: preserve`,
410
- so an answer landing in a thread leaves the reader at the bottom where they typed, rather
411
- than at the top of a page drawn again. The layout also names `HouseAccount.app` by its
412
- current spelling where a page has no title of its own.
413
-
414
- * [Feature] `flow` draws the page of a signup flow around a card
415
-
416
- The mark over the wall, a title, a line, one card and the way out, from a host layout's
417
- one call. The view says its words in `content_for` — `:title`, `:subtitle` and `:width`,
418
- the card's, which is how a chat's page gets a wider card than a form's — and the layout
419
- passes `footer:`, pieces joined by a middot, and `logo:`. The column and the card are the
420
- gem's rules again, `.flow` and `.flow-card`.
421
-
422
- * [Fix] No gutter is kept for a scrollbar a page has not got
423
-
424
- Bootstrap 6 reserves the column on every page; a browser with classic scrollbars painted
425
- its empty track beside a page that fit. The gutter now appears with the scrollbar alone.
426
-
427
- * [Fix] The versioned copy follows the build until the version is tagged
428
-
429
- The head helper links `/v<version>/`, and that folder was written once and left, so a
430
- host reading the gem from a path kept the stylesheet of the day the folder was made.
431
- Every build now rewrites it until `v<version>` is tagged, and never after.
432
-
433
- * [Feature] `HouseAccount.one_time_code` is the text that carries a code
434
-
435
- Every app texting a 6-digit code sends the same two lines, the sentence and the
436
- `@host #code` Safari reads a code from, and reads them off the gem's locale file rather
437
- than keeping a copy of its own.
438
-
439
- * [Breaking change] The constant is `HouseAccount`
440
-
441
- `HouseAccount::Message`, `HouseAccount::Engine`, `HouseAccount.app`: the house's name
442
- as the house writes it. The gem and the npm package stay `houseaccount`, since a gem's
443
- name fixes only the file Bundler requires.
444
-
445
- * [Feature] A host's layout nests on the gem's
446
-
447
- A layout hands its page over as `content_for :content` and renders the gem's as a
448
- template; the bare layout's body now fills the window. The wall stays the gem's, from
449
- `data-controller='wall'`; what a host draws in front of it, a column and a card say, is
450
- the host's to style.
451
-
452
- * [Fix] Body text is Bootstrap's own, and a chat bubble has its sheen back
453
-
454
- The stylesheet set every page to Helvetica at 14px, a choice made for tables that came
455
- over with their rules; a page a customer reads on a phone wants Bootstrap's system face at
456
- 16px, and a host wanting another sets the two properties itself. A bubble wears
457
- `--bs-gradient` again, as a message thread's do.
458
-
459
- * [Feature] `dialog` draws a link and the dialog it opens
460
-
461
- Bootstrap's `<dialog>` with a heading, an X, the block and an `Okay`, and the link that
462
- opens it through the plugin's own `data-bs-toggle`, sharing an id made from the link's
463
- words — so no page writes the markup or invents a name, and the `dialog` controller
464
- carried here from fountain goes.
465
-
466
- * [Fix] A phone field refuses an eleventh digit rather than taking it and cutting it back
467
-
468
- A submit shut until the field is valid saw the eleven digits before the format cut them
469
- to ten, and stayed shut. The key is refused on a full field; a whole number pasted or
470
- autofilled is reshaped and the field says `input` again; and the country code a number
471
- arrives with is dropped, since no NANP area code starts with a 1 — which is what
472
- fountain's `national` controller did on its own.
473
-
474
- * [Feature] `notices` draws the flash as toasts
475
-
476
- Every message in the flash as a toast at the bottom right — green for a notice, red for
477
- an alert, neutral for a key of the host's own — visible at first paint, held while read
478
- and gone after a moment, the way recourse shows them. The gem's layout calls it, so a
479
- page it draws shows what a redirect had to say.
480
-
481
- * [Feature] `HouseAccount::FormBuilder` is the house's form, `pin_field` included
482
-
483
- Given as `builder:` or a controller's `default_form_builder`: `fieldset` is the one-column
484
- grid a form's controls sit in, with a legend where given, a label is a `form-label`, a
485
- text or phone field a large control, the phone one shaped by the `phone` controller as it
486
- is typed, a submit or a button the solid pill, a `type: :button` one the outlined pill, and a
487
- disabled one given a `title` says why on hover — `Available soon` — from a wrapper that
488
- hears the mouse for it. `pin_field` is one real field rendered by Bootstrap
489
- as six slots, with the `otp` controller from fountain: the slots drawn on a Turbo visit, a pasted or autofilled code sent on its own,
490
- a refused one kept with the caret at its end.
491
-
492
- * [Feature] A `<select data-controller='combobox'>` is Bootstrap's combobox, and any `data-turbo-confirm` asks through a dialog
493
-
494
- The bundle dresses a select — a toggle, a menu with a search box, a check per pick where
495
- it is `multiple`, an `All` row, a figure beside an option — and keeps the select as what
496
- the form submits, announcing a pick as its own `change`. Recourse and any app write a
497
- select and nothing more. The confirm dialog is built by the bundle on the first ask, so
498
- no page has to carry the markup, and its answer wears the words of the button that asked.
499
-
500
- * [Feature] Faster first paint: the icon font cut to the glyphs the house draws, Quicksand served from here, and a page's own version linked and kept for a year
501
-
502
- Bootstrap Icons shipped two thousand glyphs in 134 KB; `art/icons.txt` names the ones a
503
- HouseAccount page may draw and `rake icons` cuts the font and its stylesheet to those.
504
- Quicksand comes from `/font` rather than Google, so no page reaches another origin. The
505
- engine serves this version's copy under `/v<version>/`, cached immutable, and
506
- `houseaccount_head_tags` links it, so a returning reader fetches nothing.
507
-
508
- ## 0.2.0 - 2026-09-13
509
-
510
- * [Feature] The front end of every HouseAccount app, extracted from recourse and the apps
511
-
512
- One stylesheet and one script — Bootstrap 6 alpha, Bootstrap Icons, Turbo, Stimulus and the
513
- twenty controllers behind the house's pages — served by the engine at `/css/houseaccount.css`
514
- and `/js/houseaccount.js`, and published at https://design.houseaccount.com under the same
515
- paths for a page not on the gem. The nine palettes under `/theme`, every app's mark under
516
- `/logo` and `/favicon`, and the five error pages under `/page`, which the engine answers a
517
- failing request with.
518
-
519
- * [Feature] `houseaccount_head_tags`, `houseaccount_logo`, `chat_with` and `houseaccount_url`
520
-
521
- A head, a lockup and a thread of bubbles drawn the same way in every app. Which app a host
522
- is, the gem reads off the Rails application's name, and the head and the down page follow
523
- it; `houseaccount_logo app: :fountain` draws any of the family's marks seated by its own numbers beside its
524
- name. `chat_with url:, hints:, messages:` takes messages answering `side`, `text`, `sender`,
525
- `at`, `delivery` and `cost`, or `HouseAccount::Message`s, and the URL the next one posts to.
526
-
527
- * [Feature] A layout for a page recourse does not draw
528
-
529
- `layout 'houseaccount'` on a controller gives a page the shared head — charset, title,
530
- CSRF and CSP metas, the stylesheet, the script and the icons — then `yield :head`, then
531
- the page inside `<body>`. `content_for :title` names it; the app's own name stands in.
532
-
533
- * [Feature] The page an app shows while it is down
534
-
535
- Its own mark in the middle and the house's at the foot, rendered per app into `/down/<app>.html`
536
- and answered at `/down.html` by the engine for the app the host named. The design site
537
- has a mark of its own, a pencil, and wears it.
538
-
539
- * [Feature] Every release is kept at its own versioned URL
540
-
541
- `/v0.2.0/css/houseaccount.css` and its script, fonts and palettes stand beside the
542
- unversioned copies, whole on their own and cached for a year, so a page may pin a
543
- version and move when it chooses. `rake version` writes a folder once per release.
544
-
545
- * [Feature] The signup flow's wall of drifting tools, from one attribute
546
-
547
- `data-controller='wall'` on a page's shell draws the cyanotype of trades and the family's
548
- marks behind it, from geometry the bundle carries; `.flow-shell`, `.flow-main` and
549
- `.welcome-card` are the classes the page in front of it wears.
550
-
551
- * [Feature] A phone is formatted in the browser
552
-
553
- The server hands over ten digits and `data-controller='phone'`; the controller decides
554
- `555-555-5555` on a cell and on a field, and gives the field its pattern and placeholder.
555
-
556
- ## 0.1.0 - 2026-08-27
557
-
558
- * A library that loads and does not do anything yet.
220
+ `easyfaa_tags` links `/css/easyfaa.css` and `/js/easyfaa.js`, which a browser asks for again
221
+ on every full load and is answered 304 while they stand. A release is one build at the root.