├── .editorconfig ├── .eslintrc ├── .github └── workflows │ └── CI.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── docs ├── .gitignore ├── package.json └── src │ ├── images │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ └── micromodal.jpg │ ├── index.html │ ├── scripts │ ├── index.js │ ├── micromodal.js │ └── prism.js │ └── styles │ ├── index.css │ ├── modal.css │ ├── prism.css │ └── tachyons.css ├── lib ├── .babelrc ├── .browserslistrc ├── README.md ├── package.json ├── rollup.config.js └── src │ └── index.js ├── package.json ├── tests ├── assets │ ├── modal.css │ ├── modal.js │ └── test.css ├── cypress.json ├── cypress │ ├── plugins │ │ └── index.js │ └── support │ │ ├── commands.js │ │ └── index.js ├── examples │ ├── basic.html │ ├── index.html │ └── programmatic.html ├── package.json └── specs │ ├── basic.spec.js │ └── programmatic.spec.js └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "standard", 3 | "rules": { 4 | "template-curly-spacing": [ 5 | "error", 6 | "always" 7 | ], 8 | "quotes": [2, "single", { "avoidEscape": true }] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /.github/workflows/CI.yml: -------------------------------------------------------------------------------- 1 | name: Build and Test 2 | 3 | on: 4 | push: 5 | branches: [ next, master ] 6 | pull_request: 7 | branches: [ next, master ] 8 | 9 | 10 | jobs: 11 | # Build the library and site 12 | build: 13 | name: Build 14 | runs-on: ubuntu-latest 15 | steps: 16 | 17 | - uses: actions/checkout@v2 18 | with: 19 | cmd: yarn install && yarn build 20 | 21 | # Run the test suite 22 | test: 23 | name: Test 24 | runs-on: ubuntu-latest 25 | 26 | steps: 27 | - uses: actions/checkout@v2 28 | - uses: actions/setup-node@v1 29 | with: 30 | node-version: '16.x' 31 | - uses: cypress-io/github-action@v2 32 | with: 33 | build: yarn build 34 | runTests: false # just build site 35 | - uses: cypress-io/github-action@v2 36 | with: 37 | install: false 38 | working-directory: tests 39 | start: yarn start 40 | wait-on: http://localhost:1234 41 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /node_modules 3 | */node_modules 4 | package-lock.json 5 | yarn-error.log 6 | */.cache 7 | */dist 8 | */screenshots 9 | .parcel-cache 10 | 11 | .vercel 12 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## Release History 2 | * **0.6.1** 3 | * 🐞 `BUGFIX` Add ability to pass an element to Micromodal.close() 4 | * 🌀 `ENHANCEMENT` Updated documentation for show and close methods 5 | * **0.6.0** 6 | * 💡 `FEATURE` Added ability to pass an element to Micromodal 7 | * **0.5.2** 8 | * 🐞 `BUGFIX` Updated dependencies 9 | * **0.4.10** 10 | * 🐞 `BUGFIX` Reverted passive listener to enable event methods 11 | * **0.4.9** 12 | * 🐞 `BUGFIX` Correctly closes modal when clicking on nested close elements 13 | * **0.4.8** 14 | * 🐞 `BUGFIX` Fixed issue where clicking on a input field would close the modal 15 | * **0.4.7** 16 | * 🐞 `BUGFIX` Correctly disable scroll on iOS devices 17 | * 🐞 `BUGFIX` Fixed issue where 'window' would be undefined 18 | * 🐞 `BUGFIX` Close button works even if there are nested elements within 19 | * 🐞 `BUGFIX` Marks event handler as 'passive' to make the page more responsive 20 | * 🐞 `BUGFIX` Prevents click handlers from triggering underlying elements 21 | * **0.4.6** 22 | * 🐞 `BUGFIX` Removed focus error when no focusable element exists in the modal 23 | * **0.4.5** 24 | * 🐞 `BUGFIX` On open, correctly focuses on non close triggers when possible 25 | * 🐞 `BUGFIX` Custom open class is now properly removed on modal close 26 | * **0.4.4** 27 | * 💡 `FEATURE` Added ability to customize open class name 28 | * **0.4.3** 29 | * 🌀 `ENHANCEMENT` Finds a focusable element which is not the close button on modal open 30 | * 🌀 `ENHANCEMENT` Handle events cleanup if modals are not closed properly 31 | * 🌀 `ENHANCEMENT` The original trigger event is now passed to the onShow and onClose methods 32 | * 🌀 `ENHANCEMENT` Added engines property to package.json 33 | * 🐞 `BUGFIX` Fixed callbacks for programmatically toggling modal 34 | * 🐞 `BUGFIX` No longer intercept click events on open and close to prevent default action 35 | * 🐞 `BUGFIX` No longer throws error if modal has no focusable elements 36 | * 🐞 `BUGFIX` Setting `disableScroll` no longger changes the height of the body 37 | * 🐞 `BUGFIX` Fixed issue where focus trap would leak if a hidden element exists within modal 38 | * 🐞 `BUGFIX` Fixed issue where active element was not being passed to the onClose method 39 | * **0.4.2** 40 | * 🐞 `BUGFIX` Fixed broken CDN link 41 | * **0.4.1** 42 | * 💡 `FEATURE` A flag to `awaitOpenAnimation` before focusing on element in modal 43 | * 💡 `FEATURE` Passing actual node as second argument to `onShow` 44 | * 🐞 `BUGFIX` Fixed issue where active element was `undefined` 45 | * 🐞 `BUGFIX` Fixed issue where an opened modal could not be closed by `id` 46 | * **0.4.0** 47 | * 💡 `FEATURE` Added abilty to close modals by ID - #113 @roebuk 48 | * 🐞 `BUGFIX` Fixed bug where micromodal would error on initialization - #106 @stoicsquirrel 49 | * 🐞 `BUGFIX` Fixed bug where IE crashed due to null reference - #171 @wcarson 50 | * 🐞 `BUGFIX` Fixed bug which didn't lock modal overlay in IE 51 | * **0.3.2** 52 | * 🐞 `BUGFIX` Fixed bundling for es and umd builds 53 | * **0.3.1** 54 | * 💡 `FEATURE` **Breaking** Renamed `hasAnimation` to `awaitCloseAnimation` 55 | * 🐞 `BUGFIX` Updated correct version of modal in dist 56 | * **0.3.0** 57 | * 💡 `FEATURE` **Breaking** Added flag to await close animation end before destroying modal 58 | * 💡 `FEATURE` Added flag to disable focus on first element 59 | * 💡 `FEATURE` Added ability to pass custom data-attributes for open and close 60 | * 🐞 `BUGFIX` Fixed modal not working without animations 61 | * 🐞 `BUGFIX` Not focusing on last element in modal in case of file inputs 62 | * **0.2.0** 63 | * 💡 `FEATURE` Added api to programmatically close modal 64 | * 💡 `FEATURE` Added abilty to disable scroll on modal open 65 | * 💡 `FEATURE` Added hooks for open/close animations 66 | * 💡 `FEATURE` Added flag for toggling debug logs in console 67 | * 🌀 `ENHANCEMENT` Added ability to pass config to `show` method 68 | * 🌀 `ENHANCEMENT` Cleaned up `aria` tags for accessibilty 69 | * 🌀 `ENHANCEMENT` Added test suite for browser tests 70 | * 🐞 `BUGFIX` Fixed native form events not firing in modal 71 | * 🐞 `BUGFIX` Fixed modal blocking custom event listeners 72 | * **0.1.1** 73 | * 🐞 `BUGFIX` Fixed issue where validation was not firing 74 | * **0.1.0** 75 | * 🌀 `ENHANCEMENT` Released first minor version 😊 76 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Indrashish Ghosh 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 |

5 | Micromodal.js 6 |

7 | 8 |

9 | 10 | Made with love 11 | 12 | 13 | License 14 | 15 | 16 | Package version 17 | 18 |

19 | 20 |

21 | Tiny, dependency-free javascript library for creating accessible modal dialogs 22 |

23 | 24 | --- 25 | 26 | 27 | 28 | The aim of this library is to make modal dialogs accessible and easy to include in your project with minimum configuration. It's only ~1.8kb minified and gzipped - A tiny library for big change. 29 | 30 | **[Demo and documentation](https://micromodal.now.sh/)** 31 | 32 | **[Codepen example](https://codepen.io/pen?template=LEYmYWy)** 33 | 34 |   35 | 36 | ## Features 37 | ✔ Toggles relevant aria attributes on open and close 38 | 39 | ✔ Closes modal on overlay click 40 | 41 | ✔ Closes modal on pressing the `esc` key 42 | 43 | ✔ Traps tab focus within the modal 44 | 45 | ✔ Focuses on the first focusable element within the modal 46 | 47 | ✔ Retains the focused element state after closing the modal 48 | 49 |   50 | 51 | ## Installation 52 | 53 | **via npm** 54 | ```shell 55 | npm install micromodal --save 56 | ``` 57 | 58 | **via yarn** 59 | ```shell 60 | yarn add micromodal 61 | ``` 62 | 63 | **via CDN direct link** 64 | ```html 65 | 66 | 67 | 68 | ``` 69 | 70 | **direct download** 71 | ```shell 72 | curl -O -L https://unpkg.com/micromodal/dist/micromodal.min.js 73 | ``` 74 | 75 |   76 | 77 | ## IE 11 and below 78 | 79 | Please use this pollyfill suggested [here](https://github.com/ghosh/Micromodal/issues/49#issuecomment-424213347). 80 | 81 |   82 | 83 | ## Changelog 84 | 85 | Find the latest changelog [here](https://github.com/ghosh/micromodal/blob/master/CHANGELOG.md). 86 | 87 |   88 | 89 | ## Contributing 90 | 91 | We are always open and invite developers to contribute to Micromodal. We have kept the guidelines and process dead simple, so you invest more time in making modals accessible to all. 92 | 93 | Micromodal follows the [standardjs](https://standardjs.com/) coding standard and is part of our `package.json` file. It will help us to maintain consistency in the code base. 94 | 95 | #### Development setup 96 | 1. Clone Github repo `$ git clone https://github.com/ghosh/micromodal.git` 97 | 2. Install `yarn` package manager (Read [installation guide](https://yarnpkg.com/en/docs/install#mac-tab)) 98 | 3. Run `yarn install` in the root folder to install all dependencies 99 | 4. Run `yarn dev` to start a dev server. This serves the example directory and live reloads when any files are changed 100 | 5. [Optional] Run `yarn build` to build the files for distribution. This is run automatically as a pre-commit hook as well. 101 | 6. Send us pull request and chill 102 | 103 | #### Pushing a new version 104 | 105 | First, you must be authorized on npmjs.com. Then: 106 | 107 | 1. Update the npm package: 108 | - Update the version in `lib/package.json` 109 | - `yarn deploy:npm` 110 | 111 | 2. Update the changelog. 112 | 113 | 3. Commit and push changes 114 | 115 | 4. Tag the version in git: 116 | - `git tag -a X.Y.Z` 117 | - Add the same text as the changelog to the tag description 118 | - `git push origin X.Y.Z` 119 | 120 | 5. Create a new release in Github: https://github.com/micromodal/micromodal/releases 121 | 122 |   123 | 124 | ## Want to be a core maintainer? 125 | 126 | We are looking for more maintainers for Micromodal. If you are interested, and you have at least some free time to spend on this, reach out to @dkniffin. 127 | 128 |   129 | 130 | ## Licensing 131 | This project is licensed under [MIT license](https://opensource.org/licenses/MIT). 132 | 133 |   134 | 135 | ## Related 136 | - [Microtip](https://github.com/ghosh/microtip) - Modern, lightweight, accessible css tooltip library. Just 1kb. 137 | 138 |   139 | 140 | ## Created and maintained by 141 | 142 | Derek Kniffin – [@dkniffin](https://github.com/dkniffin) 🇺🇸 143 | 144 | Indrashish Ghosh – [@_ighosh](https://twitter.com/_ighosh) 🇮🇳 145 | 146 | Kalpesh Singh - [@knowkalpesh](https://twitter.com/knowkalpesh) 🇮🇳 147 | 148 | Darpan Kakadia - [@kakadiadarpan](https://twitter.com/kakadiadarpan) 🇩🇪 149 | 150 | Contributors - [list](https://github.com/ghosh/micromodal/graphs/contributors) 🌐 151 | 152 | You? - Open a PR to get started! 153 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | .now 2 | 3 | .vercel 4 | -------------------------------------------------------------------------------- /docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@micromodal/docs", 3 | "version": "1.0.0", 4 | "description": "", 5 | "private": true, 6 | "workspaces": [ 7 | "lib", 8 | "docs", 9 | "tests" 10 | ], 11 | "source": "src/index.html", 12 | "scripts": { 13 | "dev": "parcel ./src/index.html", 14 | "build": "parcel build ./src/index.html --detailed-report", 15 | "deploy": "now --prod", 16 | "sync": "cp ../lib/dist/micromodal.js ./src/scripts/", 17 | "test": "echo \"Error: no test specified\" && exit 1" 18 | }, 19 | "repository": { 20 | "type": "git", 21 | "url": "git+https://github.com/ghosh/micromodal.git" 22 | }, 23 | "author": "Indrashish Ghosh", 24 | "license": "MIT", 25 | "bugs": { 26 | "url": "https://github.com/ghosh/micromodal/issues" 27 | }, 28 | "homepage": "https://github.com/ghosh/micromodal#readme", 29 | "devDependencies": { 30 | "parcel": "^2.0.1" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /docs/src/images/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micromodal/Micromodal/a922122accfa28c48a72747a44e0214996e671e2/docs/src/images/favicon-16x16.png -------------------------------------------------------------------------------- /docs/src/images/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micromodal/Micromodal/a922122accfa28c48a72747a44e0214996e671e2/docs/src/images/favicon-32x32.png -------------------------------------------------------------------------------- /docs/src/images/micromodal.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micromodal/Micromodal/a922122accfa28c48a72747a44e0214996e671e2/docs/src/images/micromodal.jpg -------------------------------------------------------------------------------- /docs/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Micromodal.js - Tiny javascript library for creating accessible modal dialogs 8 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 25 | 26 | 27 | 28 | 29 | 30 | 32 | 33 | 34 | 35 | 36 | 37 | 43 | 44 | 45 | 46 | 47 | 48 |
49 | 50 |
51 | 60 | 61 | 71 | 72 | 81 | 82 |
83 | 84 |
85 | 86 | 105 | 106 |
107 |

108 | Introduction 109 |

110 | 111 |

112 | Micromodal.js is a lightweight, configurable and a11y-enabled modal library written in pure 113 | JavaScript 114 |

115 | 116 |

117 | It enables you to create WAI-ARIA guidelines compliant modal dialogs, 119 | with confidence and with minimal configuration. At just 1.9kb minified and gzipped, its a tiny library for big 120 | change. 121 |

122 | 123 | 124 |
125 |
126 | 127 | 131 | 132 |
133 |
134 | 135 |

136 | Following are some of the interactions handled by the library:- 137 |

138 | 139 |
    140 |
  • Closing modal on overlay click
  • 141 |
  • Closing modal on esc button press
  • 142 |
  • Toggling aria-hidden attribute on modal
  • 143 |
  • Trapping tab focus within the modal
  • 144 |
  • Maintaining focus position before and after toggling modal
  • 145 |
  • Focusing on the first focusable element within the modal
  • 146 |
147 | 148 | 149 | 150 |

151 | Installation 152 |

153 | 154 |

155 | Micromodal is available on npm and can be installed from the command line via npm or yarn 156 |

157 | 158 |

159 | npm install micromodal --save // via npm
160 | yarn add micromodal --save // via yarn
161 |         
162 | 163 |

164 | You can also download or link to the latest compiled version using the CDN. 165 |

166 | 167 |

168 | https://unpkg.com/micromodal/dist/micromodal.min.js
169 |         
170 | 171 | 172 | 173 |

174 | Usage 175 |

176 | 177 |

178 | Designed to be easy to use, it does most of the heavy lifting behind the scenes and exposes a simple api to 179 | interact with the dom. 180 |

181 | 182 |

183 | Typically modals have an overlay which cover the rest of the content. To achieve this, it is normal to put the 184 | modal code just before the closing body tag, so that the modal overlay is relative to the body 185 | and covers the whole screen. 186 |

187 | 188 |

189 | 1. Add the modal markup 190 |

191 | 192 |

193 | The following html structure is expected for the modal to work. It can of course be extended to suit your 194 | needs. As an example of the customization, see the source code of the demo modal here. 197 |

198 | 199 |

200 | <!-- [1] -->
201 | <div id="modal-1" aria-hidden="true">
202 | 
203 |   <!-- [2] -->
204 |   <div tabindex="-1" data-micromodal-close>
205 | 
206 |     <!-- [3] -->
207 |     <div role="dialog" aria-modal="true" aria-labelledby="modal-1-title" >
208 | 
209 | 
210 |       <header>
211 |         <h2 id="modal-1-title">
212 |           Modal Title
213 |         </h2>
214 | 
215 |         <!-- [4] -->
216 |         <button aria-label="Close modal" data-micromodal-close></button>
217 |       </header>
218 | 
219 |       <div id="modal-1-content">
220 |         Modal Content
221 |       </div>
222 | 
223 |     </div>
224 |   </div>
225 | </div>
226 |         
227 | 228 |
    229 |
  • 230 | This is the outermost container of the modal. Its job is to toggle the display of the modal. It is 231 | important that every modal have a unique id. By default the aria-hidden will be 232 | true. Micromodal takes care of toggling the value when required. 233 |
  • 234 |
  • 235 | This is the div which acts as the overlay for the modal. Notice the 236 | data-micromodal-close on it. This is a special attribute which indicates that the element that 237 | it is on should trigger the close of the modal on click. If we remove that attribute, clicking on the 238 | overlay will not close the modal anymore. 239 |
  • 240 |
  • 241 | The role="dialog" attribute is used to inform assistive technologies that content within is 242 | separate from the rest of the page. Additionally, the aria-labelledby="modal-1-title" attribute 243 | points to the id of the modal title. This is to help identify the purpose of the modal. 244 |
  • 245 |
  • 246 | Ensuring that all buttons have a aria-label attribute which defines the action of the button. 247 | Notice the data-micromodal-close attribute is used on the button since we want to close the 248 | modal on press. 249 |
  • 250 |
251 | 252 | 253 | 254 |

255 | 2. Add micromodal.js 256 |

257 | 258 |

259 | If you included the compiled file from the CDN into your project, you will have access to a 260 | MicroModal global variable, which you can use to instantiate the module. 261 |

262 | 263 |

264 | In cases with a modular workflow, you can directly import the module into your project. 265 |

266 | 267 |

268 | import MicroModal from 'micromodal';  // es6 module
269 | var MicroModal = require('micromodal'); // commonjs module
270 |         
271 | 272 |

273 | 3. Use with data attributes 274 |

275 | 276 |

277 | Set data-micromodal-trigger="modal-1" on an element, like a button or link, on whose click you 278 | want to show the modal. The value of the attribute, in this case modal-1 should correspond to the 279 | id of the modal you want to toggle. 280 |

281 | 282 |

283 | Then instantiate the MicroModal module, so that it takes care of all the bindings for you. 284 |

285 | 286 |

287 | MicroModal.init();
288 |         
289 | 290 | 291 |

292 | Example:- 293 |

294 | 295 |
296 |
297 | 298 | 299 | Trigger Modal 300 | 301 | 302 |
303 |
304 | 305 |

306 | 3.1. Custom data attributes 307 |

308 | 309 |

310 | You can also specify custom attributes to open and close modals. Set data-custom-open="modal-1" 311 | to any element on the page and pass it in init method as parameter of openTrigger. 312 |

313 | 314 |

315 | The working and usage is same as data-micromodal-trigger, but with your own defined data 316 | attribute, in this case it's data-custom-open 317 |

318 | 319 |

320 | Similarly, you can also define custom close attribute. Example:- 321 |

322 | 323 |

324 | <button data-custom-close="modal-1">close</button>
325 |         
326 | 327 |

328 | 4. Use with javascript 329 |

330 | 331 |

332 | You can also trigger and close modals programmatically using the show and close 333 | methods on the MicroModal object. Example: 334 |

335 | 336 |
337 |           
338 | MicroModal.show('modal-id'); // [1]
339 | MicroModal.close('modal-id'); // [2]
340 | 
341 | MicroModal.show(modalElement); // [3]
342 | MicroModal.close(modalElement); // [4]
343 | 
344 | // [5]
345 | MicroModal.show(modalElement, {
346 |   onShow: modal => console.info(`${modal.id} is shown`),
347 |   onClose: modal => console.info(`${modal.id} is hidden`),
348 | });
349 |           
350 |         
351 | 352 |
    353 |
  • 354 | If the argument passed to the show method is a string, it corresponds to the id of the modal to be open. 355 |
  • 356 |
  • 357 | If the argument passed to the close method is a string, it corresponds to the id of the modal to be closed. 358 |
  • 359 |
  • 360 | If you pass in an element to the show method, it will be used as the modal to be open. 361 |
  • 362 |
  • 363 | If you pass in an element to the close method, it will be used as the modal to be closed. 364 |
  • 365 |
  • 366 | If you pass in a config object to the show or close methods, it will apply only to this 367 | modal. 368 |
  • 369 |
370 | 371 |

372 | Configuration 373 |

374 |

375 | The init and show methods accept an optional configuration object. This allows you 376 | to set custom callbacks and control behaviour of the modal. Example:- 377 |

378 | 379 |

380 | MicroModal.init({
381 |   onShow: modal => console.info(`${modal.id} is shown`), // [1]
382 |   onClose: modal => console.info(`${modal.id} is hidden`), // [2]
383 |   openTrigger: 'data-custom-open', // [3]
384 |   closeTrigger: 'data-custom-close', // [4]
385 |   openClass: 'is-open', // [5]
386 |   disableScroll: true, // [6]
387 |   disableFocus: false, // [7]
388 |   awaitOpenAnimation: false, // [8]
389 |   awaitCloseAnimation: false, // [9]
390 |   debugMode: true // [10]
391 | });
392 |         
393 | 394 |
    395 |
  • 396 | onShow function 397 |

    398 | This is fired when the modal is opening. The function receives the modal object as the first parameter and 399 | the trigger element as second parameter 400 |

    401 |
  • 402 |
  • 403 | onClose function 404 |

    405 | This is fired when the modal is closing. The function receives the modal object as the first parameter and 406 | the trigger element as second parameter 407 |

    408 |
  • 409 |
  • 410 | openTrigger string 411 |

    412 | Custom data attribute to open modal. Default is data-micromodal-trigger 413 |

    414 |
  • 415 |
  • 416 | closeTrigger string 417 |

    418 | Custom data attribute to close modal. Default is data-micromodal-close 419 |

    420 |
  • 421 |
  • 422 | openClass string 423 |

    424 | Custom class to be applied when modal is open. Default class is is-open 425 |

    426 |
  • 427 |
  • 428 | disableScroll boolean 429 |

    430 | This disables scrolling on the page while the modal is open. The default value is false 431 |

    432 |
  • 433 |
  • 434 | disableFocus boolean 435 |

    436 | Disable auto focus on first focusable element. Default is false 437 |

    438 |
  • 439 |
  • 440 | awaitOpenAnimation boolean 441 |

    442 | Set this to true if using css animations to open the modal. This allows it to wait for the 443 | animation to finish before focusing on an element inside the modal. Default is false 444 |

    445 |
  • 446 |
  • 447 | awaitCloseAnimation boolean 448 |

    449 | Set this to true if using css animations to hide the modal. This allows it to wait for the 450 | animation to finish before 451 | removing it from the DOM. Default is false 452 |

    453 |
  • 454 |
  • 455 | debugMode boolean 456 |

    457 | This option suppresses the console warnings if passed as true. The default value is 458 | false 459 |

    460 |
  • 461 |
462 | 463 |

464 | Styling 465 |

466 | 467 |

468 | Micromodal does not make any stylistic choices about your modal and hence comes with no styling at all. It 469 | does not even toggle the visibility of the modal. You are free to style the modal in anyway you wish. 470 |

471 | 472 |

473 | At the very least, we recommend the following bit of css to toggle the modal. 474 |

475 | 476 |

477 | .modal {
478 |   display: none;
479 | }
480 | 
481 | .modal.is-open {
482 |   display: block;
483 | }
484 |         
485 | 486 |

487 | In case you do want some default styles to get started quickly, you can refer to the styles and the 488 | corresponding markup of the demo modal here:- 489 |

490 | 491 |

492 | Demo markup and styles. 494 |

495 |
496 |
497 | 498 | 499 | 508 | 509 |
510 | 511 | 512 | 538 | 539 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | -------------------------------------------------------------------------------- /docs/src/scripts/index.js: -------------------------------------------------------------------------------- 1 | import MicroModal from './micromodal' 2 | import './prism' 3 | 4 | // Initial config for setting up modals 5 | MicroModal.init({ 6 | openTrigger: 'data-custom-open', 7 | disableScroll: false, 8 | awaitCloseAnimation: true 9 | }) 10 | 11 | // Programmatically show modal 12 | document.querySelector('.js-modal-trigger').addEventListener('click', function (event) { 13 | MicroModal.show('modal-2', { 14 | debugMode: true, 15 | disableScroll: true, 16 | onShow: function (modal) { document.querySelector('.js-body').classList.add(modal.id) }, 17 | onClose: function (modal) { document.querySelector('.js-body').classList.remove(modal.id) }, 18 | closeTrigger: 'data-custom-close', 19 | awaitCloseAnimation: true 20 | }) 21 | }) 22 | 23 | document.querySelector('.js-modal-close-trigger').addEventListener('click', function (event) { 24 | event.preventDefault() 25 | MicroModal.close('modal-2') 26 | }) 27 | 28 | // Scrollspy 29 | let section = document.querySelectorAll('.heading') 30 | const sections = {} 31 | 32 | Array.prototype.forEach.call(section, function (e) { 33 | sections[e.id] = e.offsetTop 34 | }) 35 | 36 | window.onscroll = function () { 37 | const scrollPosition = document.documentElement.scrollTop || document.body.scrollTop 38 | 39 | for (section in sections) { 40 | if (sections[section] <= scrollPosition) { 41 | document.querySelector('.active').classList.remove('blue', 'fw6', 'active') 42 | document.querySelector('a[href*=' + section + ']').classList.add('blue', 'fw6', 'active') 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /docs/src/scripts/micromodal.js: -------------------------------------------------------------------------------- 1 | !(function (e, t) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = t() : typeof define === 'function' && define.amd ? define(t) : (e = typeof globalThis !== 'undefined' ? globalThis : e || self).MicroModal = t() }(this, function () { 'use strict'; function e (e, t) { for (let o = 0; o < t.length; o++) { const n = t[o]; n.enumerable = n.enumerable || !1, n.configurable = !0, 'value' in n && (n.writable = !0), Object.defineProperty(e, n.key, n) } } function t (e) { return (function (e) { if (Array.isArray(e)) return o(e) }(e)) || (function (e) { if (typeof Symbol !== 'undefined' && Symbol.iterator in Object(e)) return Array.from(e) }(e)) || (function (e, t) { if (!e) return; if (typeof e === 'string') return o(e, t); let n = Object.prototype.toString.call(e).slice(8, -1); n === 'Object' && e.constructor && (n = e.constructor.name); if (n === 'Map' || n === 'Set') return Array.from(e); if (n === 'Arguments' || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return o(e, t) }(e)) || (function () { throw new TypeError('Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.') }()) } function o (e, t) { (t == null || t > e.length) && (t = e.length); for (var o = 0, n = new Array(t); o < t; o++)n[o] = e[o]; return n } let n; let i; let a; let r; let s; const l = (n = ['a[href]', 'area[href]', 'input:not([disabled]):not([type="hidden"]):not([aria-hidden])', 'select:not([disabled]):not([aria-hidden])', 'textarea:not([disabled]):not([aria-hidden])', 'button:not([disabled]):not([aria-hidden])', 'iframe', 'object', 'embed', '[contenteditable]', '[tabindex]:not([tabindex^="-"])'], i = (function () { function o (e) { const n = e.targetModal; const i = e.triggers; const a = void 0 === i ? [] : i; const r = e.onShow; const s = void 0 === r ? function () { } : r; const l = e.onClose; const c = void 0 === l ? function () { } : l; const d = e.openTrigger; const u = void 0 === d ? 'data-micromodal-trigger' : d; const f = e.closeTrigger; const h = void 0 === f ? 'data-micromodal-close' : f; const v = e.openClass; const g = void 0 === v ? 'is-open' : v; const m = e.disableScroll; const b = void 0 !== m && m; const y = e.disableFocus; const p = void 0 !== y && y; const w = e.awaitCloseAnimation; const E = void 0 !== w && w; const k = e.awaitOpenAnimation; const M = void 0 !== k && k; const A = e.debugMode; const C = void 0 !== A && A; !(function (e, t) { if (!(e instanceof t)) throw new TypeError('Cannot call a class as a function') }(this, o)), this.modal = document.getElementById(n), this.config = { debugMode: C, disableScroll: b, openTrigger: u, closeTrigger: h, openClass: g, onShow: s, onClose: c, awaitCloseAnimation: E, awaitOpenAnimation: M, disableFocus: p }, a.length > 0 && this.registerTriggers.apply(this, t(a)), this.onClick = this.onClick.bind(this), this.onKeydown = this.onKeydown.bind(this) } let i, a, r; return i = o, (a = [{ key: 'registerTriggers', value: function () { for (var e = this, t = arguments.length, o = new Array(t), n = 0; n < t; n++)o[n] = arguments[n]; o.filter(Boolean).forEach(function (t) { t.addEventListener('click', function (t) { return e.showModal(t) }) }) } }, { key: 'showModal', value: function () { const e = this; const t = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : null; if (this.activeElement = document.activeElement, this.modal.setAttribute('aria-hidden', 'false'), this.modal.classList.add(this.config.openClass), this.scrollBehaviour('disable'), this.addEventListeners(), this.config.awaitOpenAnimation) { const o = function t () { e.modal.removeEventListener('animationend', t, !1), e.setFocusToFirstNode() }; this.modal.addEventListener('animationend', o, !1) } else this.setFocusToFirstNode(); this.config.onShow(this.modal, this.activeElement, t) } }, { key: 'closeModal', value: function () { const e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : null; const t = this.modal; if (this.modal.setAttribute('aria-hidden', 'true'), this.removeEventListeners(), this.scrollBehaviour('enable'), this.activeElement && this.activeElement.focus && this.activeElement.focus(), this.config.onClose(this.modal, this.activeElement, e), this.config.awaitCloseAnimation) { const o = this.config.openClass; this.modal.addEventListener('animationend', function e () { t.classList.remove(o), t.removeEventListener('animationend', e, !1) }, !1) } else t.classList.remove(this.config.openClass) } }, { key: 'closeModalById', value: function (e) { this.modal = document.getElementById(e), this.modal && this.closeModal() } }, { key: 'scrollBehaviour', value: function (e) { if (this.config.disableScroll) { const t = document.querySelector('body'); switch (e) { case 'enable': Object.assign(t.style, { overflow: '' }); break; case 'disable': Object.assign(t.style, { overflow: 'hidden' }) } } } }, { key: 'addEventListeners', value: function () { this.modal.addEventListener('touchstart', this.onClick), this.modal.addEventListener('click', this.onClick), document.addEventListener('keydown', this.onKeydown) } }, { key: 'removeEventListeners', value: function () { this.modal.removeEventListener('touchstart', this.onClick), this.modal.removeEventListener('click', this.onClick), document.removeEventListener('keydown', this.onKeydown) } }, { key: 'onClick', value: function (e) { (e.target.hasAttribute(this.config.closeTrigger) || e.target.parentNode.hasAttribute(this.config.closeTrigger)) && (e.preventDefault(), e.stopPropagation(), this.closeModal(e)) } }, { key: 'onKeydown', value: function (e) { e.keyCode === 27 && this.closeModal(e), e.keyCode === 9 && this.retainFocus(e) } }, { key: 'getFocusableNodes', value: function () { const e = this.modal.querySelectorAll(n); return Array.apply(void 0, t(e)) } }, { key: 'setFocusToFirstNode', value: function () { const e = this; if (!this.config.disableFocus) { const t = this.getFocusableNodes(); if (t.length !== 0) { const o = t.filter(function (t) { return !t.hasAttribute(e.config.closeTrigger) }); o.length > 0 && o[0].focus(), o.length === 0 && t[0].focus() } } } }, { key: 'retainFocus', value: function (e) { let t = this.getFocusableNodes(); if (t.length !== 0) if (t = t.filter(function (e) { return e.offsetParent !== null }), this.modal.contains(document.activeElement)) { const o = t.indexOf(document.activeElement); e.shiftKey && o === 0 && (t[t.length - 1].focus(), e.preventDefault()), !e.shiftKey && t.length > 0 && o === t.length - 1 && (t[0].focus(), e.preventDefault()) } else t[0].focus() } }]) && e(i.prototype, a), r && e(i, r), o }()), a = null, r = function (e) { if (!document.getElementById(e)) return console.warn("MicroModal: ❗Seems like you have missed %c'".concat(e, "'"), 'background-color: #f8f9fa;color: #50596c;font-weight: bold;', 'ID somewhere in your code. Refer example below to resolve it.'), console.warn('%cExample:', 'background-color: #f8f9fa;color: #50596c;font-weight: bold;', '')), !1 }, s = function (e, t) { if ((function (e) { e.length <= 0 && (console.warn("MicroModal: ❗Please specify at least one %c'micromodal-trigger'", 'background-color: #f8f9fa;color: #50596c;font-weight: bold;', 'data attribute.'), console.warn('%cExample:', 'background-color: #f8f9fa;color: #50596c;font-weight: bold;', '')) }(e)), !t) return !0; for (const o in t) r(o); return !0 }, { init: function (e) { const o = Object.assign({}, { openTrigger: 'data-micromodal-trigger' }, e); const n = t(document.querySelectorAll('['.concat(o.openTrigger, ']'))); const r = (function (e, t) { const o = []; return e.forEach(function (e) { const n = e.attributes[t].value; void 0 === o[n] && (o[n] = []), o[n].push(e) }), o }(n, o.openTrigger)); if (!0 !== o.debugMode || !1 !== s(n, r)) for (const l in r) { const c = r[l]; o.targetModal = l, o.triggers = t(c), a = new i(o) } }, show: function (e, t) { const o = t || {}; o.targetModal = e, !0 === o.debugMode && !1 === r(e) || (a && a.removeEventListeners(), (a = new i(o)).showModal()) }, close: function (e) { e ? a.closeModalById(e) : a.closeModal() } }); return typeof window !== 'undefined' && (window.MicroModal = l), l })) 2 | -------------------------------------------------------------------------------- /docs/src/scripts/prism.js: -------------------------------------------------------------------------------- 1 | /* http://prismjs.com/download.html?themes=prism&languages=markup+css+clike+javascript */ 2 | var _self = typeof window !== 'undefined' ? window : typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope ? self : {}; var Prism = (function () { var e = /\blang(?:uage)?-(\w+)\b/i; var t = 0; var n = _self.Prism = { manual: _self.Prism && _self.Prism.manual, util: { encode: function (e) { return e instanceof a ? new a(e.type, n.util.encode(e.content), e.alias) : n.util.type(e) === 'Array' ? e.map(n.util.encode) : e.replace(/&/g, '&').replace(/ e.length) return; if (!(w instanceof s)) { h.lastIndex = 0; var _ = h.exec(w); var P = 1; if (!_ && m && b != t.length - 1) { if (h.lastIndex = k, _ = h.exec(e), !_) break; for (var A = _.index + (d ? _[1].length : 0), j = _.index + _[0].length, x = b, O = k, S = t.length; S > x && (j > O || !t[x].type && !t[x - 1].greedy); ++x)O += t[x].length, A >= O && (++b, k = O); if (t[b] instanceof s || t[x - 1].greedy) continue; P = x - b, w = e.slice(k, O), _.index -= k } if (_) { d && (p = _[1].length); var A = _.index + p; var _ = _[0].slice(p); var j = A + _.length; var N = w.slice(0, A); var C = w.slice(j); var E = [b, P]; N && (++b, k += N.length, E.push(N)); var I = new s(u, f ? n.tokenize(_, f) : _, y, _, m); if (E.push(I), C && E.push(C), Array.prototype.splice.apply(t, E), P != 1 && n.matchGrammar(e, t, a, b, k, !0, u), l) break } else if (l) break } } } } }, tokenize: function (e, t) { var a = [e]; var r = t.rest; if (r) { for (var i in r) t[i] = r[i]; delete t.rest } return n.matchGrammar(e, a, t, 0, 0, !1), a }, hooks: { all: {}, add: function (e, t) { var a = n.hooks.all; a[e] = a[e] || [], a[e].push(t) }, run: function (e, t) { var a = n.hooks.all[e]; if (a && a.length) for (var r, i = 0; r = a[i++];)r(t) } } }; var a = n.Token = function (e, t, n, a, r) { this.type = e, this.content = t, this.alias = n, this.length = 0 | (a || '').length, this.greedy = !!r }; if (a.stringify = function (e, t, r) { if (typeof e === 'string') return e; if (n.util.type(e) === 'Array') return e.map(function (n) { return a.stringify(n, t, e) }).join(''); var i = { type: e.type, content: a.stringify(e.content, t, r), tag: 'span', classes: ['token', e.type], attributes: {}, language: t, parent: r }; if (i.type == 'comment' && (i.attributes.spellcheck = 'true'), e.alias) { var l = n.util.type(e.alias) === 'Array' ? e.alias : [e.alias]; Array.prototype.push.apply(i.classes, l) } n.hooks.run('wrap', i); var o = Object.keys(i.attributes).map(function (e) { return e + '="' + (i.attributes[e] || '').replace(/"/g, '"') + '"' }).join(' '); return '<' + i.tag + ' class="' + i.classes.join(' ') + '"' + (o ? ' ' + o : '') + '>' + i.content + '' }, !_self.document) return _self.addEventListener ? (_self.addEventListener('message', function (e) { var t = JSON.parse(e.data); var a = t.language; var r = t.code; var i = t.immediateClose; _self.postMessage(n.highlight(r, n.languages[a], a)), i && _self.close() }, !1), _self.Prism) : _self.Prism; var r = document.currentScript || [].slice.call(document.getElementsByTagName('script')).pop(); return r && (n.filename = r.src, n.manual || r.hasAttribute('data-manual') || (document.readyState !== 'loading' ? window.requestAnimationFrame ? window.requestAnimationFrame(n.highlightAll) : window.setTimeout(n.highlightAll, 16) : document.addEventListener('DOMContentLoaded', n.highlightAll))), _self.Prism }()); typeof module !== 'undefined' && module.exports && (module.exports = Prism), typeof global !== 'undefined' && (global.Prism = Prism) 3 | Prism.languages.markup = { comment: //, prolog: /<\?[\s\S]+?\?>/, doctype: //i, cdata: //i, tag: { pattern: /<\/?(?!\d)[^\s>\/=$<]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\\1|\\?(?!\1)[\s\S])*\1|[^\s'">=]+))?)*\s*\/?>/i, inside: { tag: { pattern: /^<\/?[^\s>\/]+/i, inside: { punctuation: /^<\/?/, namespace: /^[^\s>\/:]+:/ } }, 'attr-value': { pattern: /=(?:('|")[\s\S]*?(\1)|[^\s>]+)/i, inside: { punctuation: /[=>"']/ } }, punctuation: /\/?>/, 'attr-name': { pattern: /[^\s>\/]+/, inside: { namespace: /^[^\s>\/:]+:/ } } } }, entity: /&#?[\da-z]{1,8};/i }, Prism.languages.markup.tag.inside['attr-value'].inside.entity = Prism.languages.markup.entity, Prism.hooks.add('wrap', function (a) { a.type === 'entity' && (a.attributes.title = a.content.replace(/&/, '&')) }), Prism.languages.xml = Prism.languages.markup, Prism.languages.html = Prism.languages.markup, Prism.languages.mathml = Prism.languages.markup, Prism.languages.svg = Prism.languages.markup 4 | Prism.languages.css = { comment: /\/\*[\s\S]*?\*\//, atrule: { pattern: /@[\w-]+?.*?(;|(?=\s*\{))/i, inside: { rule: /@[\w-]+/ } }, url: /url\((?:(["'])(\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1|.*?)\)/i, selector: /[^\{\}\s][^\{\};]*?(?=\s*\{)/, string: { pattern: /("|')(\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/, greedy: !0 }, property: /(\b|\B)[\w-]+(?=\s*:)/i, important: /\B!important\b/i, 'function': /[-a-z0-9]+(?=\()/i, punctuation: /[(){};:]/ }, Prism.languages.css.atrule.inside.rest = Prism.util.clone(Prism.languages.css), Prism.languages.markup && (Prism.languages.insertBefore('markup', 'tag', { style: { pattern: /()[\s\S]*?(?=<\/style>)/i, lookbehind: !0, inside: Prism.languages.css, alias: 'language-css' } }), Prism.languages.insertBefore('inside', 'attr-value', { 'style-attr': { pattern: /\s*style=("|').*?\1/i, inside: { 'attr-name': { pattern: /^\s*style/i, inside: Prism.languages.markup.tag.inside }, punctuation: /^\s*=\s*['"]|['"]\s*$/, 'attr-value': { pattern: /.+/i, inside: Prism.languages.css } }, alias: 'language-css' } }, Prism.languages.markup.tag)) 5 | Prism.languages.clike = { comment: [{ pattern: /(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/, lookbehind: !0 }, { pattern: /(^|[^\\:])\/\/.*/, lookbehind: !0 }], string: { pattern: /(["'])(\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/, greedy: !0 }, 'class-name': { pattern: /((?:\b(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[a-z0-9_\.\\]+/i, lookbehind: !0, inside: { punctuation: /(\.|\\)/ } }, keyword: /\b(if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/, 'boolean': /\b(true|false)\b/, 'function': /[a-z0-9_]+(?=\()/i, number: /\b-?(?:0x[\da-f]+|\d*\.?\d+(?:e[+-]?\d+)?)\b/i, operator: /--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&?|\|\|?|\?|\*|\/|~|\^|%/, punctuation: /[{}[\];(),.:]/ } 6 | Prism.languages.javascript = Prism.languages.extend('clike', { keyword: /\b(as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|var|void|while|with|yield)\b/, number: /\b-?(0[xX][\dA-Fa-f]+|0[bB][01]+|0[oO][0-7]+|\d*\.?\d+([Ee][+-]?\d+)?|NaN|Infinity)\b/, 'function': /[_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*(?=\()/i, operator: /-[-=]?|\+[+=]?|!=?=?|<>?>?=?|=(?:==?|>)?|&[&=]?|\|[|=]?|\*\*?=?|\/=?|~|\^=?|%=?|\?|\.{3}/ }), Prism.languages.insertBefore('javascript', 'keyword', { regex: { pattern: /(^|[^\/])\/(?!\/)(\[[^\]\r\n]+]|\\.|[^\/\\\[\r\n])+\/[gimyu]{0,5}(?=\s*($|[\r\n,.;})]))/, lookbehind: !0, greedy: !0 } }), Prism.languages.insertBefore('javascript', 'string', { 'template-string': { pattern: /`(?:\\\\|\\?[^\\])*?`/, greedy: !0, inside: { interpolation: { pattern: /\$\{[^}]+\}/, inside: { 'interpolation-punctuation': { pattern: /^\$\{|\}$/, alias: 'punctuation' }, rest: Prism.languages.javascript } }, string: /[\s\S]+/ } } }), Prism.languages.markup && Prism.languages.insertBefore('markup', 'tag', { script: { pattern: /()[\s\S]*?(?=<\/script>)/i, lookbehind: !0, inside: Prism.languages.javascript, alias: 'language-javascript' } }), Prism.languages.js = Prism.languages.javascript 7 | -------------------------------------------------------------------------------- /docs/src/styles/index.css: -------------------------------------------------------------------------------- 1 | @import './tachyons.css'; 2 | @import './modal.css'; 3 | @import './prism.css'; 4 | 5 | 6 | /**************************\ 7 | Page Styles 8 | \**************************/ 9 | 10 | button { cursor: pointer; } 11 | 12 | .underline { 13 | text-decoration-skip: ink; 14 | } 15 | .no-underline-hover:hover { 16 | text-decoration: none; 17 | } 18 | 19 | code { 20 | color: blueviolet; 21 | padding: .2rem .4rem; 22 | font-size: 90% !important; 23 | background-color: #f7f7f9; 24 | border-radius: .25rem; 25 | font-family: Source Code Pro, Consolas, monaco, monospace !important; 26 | } 27 | 28 | pre { 29 | border-radius: 5px; 30 | } 31 | 32 | pre code { 33 | font-size: 100% !important; 34 | padding: 0; 35 | } 36 | 37 | ul.sticky { 38 | position: sticky; 39 | position: -webkit-sticky; 40 | top: 8px; 41 | } 42 | 43 | ul.checkmark { 44 | list-style-type:none; 45 | } 46 | ul.checkmark li:before { 47 | content:"\2713\0020"; 48 | font-family: 'Lucida Sans Unicode', 'Arial Unicode MS', Arial; 49 | color: #19a974; 50 | margin-right: 4px; 51 | } 52 | 53 | ul.ordered { 54 | list-style-type:none; 55 | counter-reset: comments; 56 | } 57 | ul.ordered li { 58 | position: relative; 59 | } 60 | ul.ordered li:before { 61 | counter-increment: comments; /* Increment the value of comments counter by 1 */ 62 | content: counter(comments); 63 | color: #fff; 64 | margin-right: 4px; 65 | position: absolute; 66 | left: 0; 67 | font-size: 12px; 68 | background-color: #19a974; 69 | display: inline-block; 70 | width: 20px; 71 | height: 20px; 72 | border-radius: 100%; 73 | display: flex; 74 | align-items: center; 75 | justify-content: center; 76 | line-height: 1; 77 | margin-top: 4px; 78 | } 79 | 80 | 81 | .header { 82 | display: flex; 83 | justify-content: space-between; 84 | align-items: center; 85 | } 86 | 87 | .logo { 88 | display: flex; 89 | align-items: center; 90 | } 91 | .logo__mark { 92 | display: inline-block; 93 | width: 30px; 94 | height: 20px; 95 | /* background-color: #3c57a0; */ 96 | border-radius: 3px; 97 | } 98 | .logo__text { 99 | margin-left: 5px; 100 | /* color: #3c57a0; */ 101 | margin-top: 1px; 102 | } 103 | 104 | .github__logo { 105 | width: 30px; 106 | height: 30px; 107 | } 108 | -------------------------------------------------------------------------------- /docs/src/styles/modal.css: -------------------------------------------------------------------------------- 1 | /**************************\ 2 | Basic Modal Styles 3 | \**************************/ 4 | .modal { 5 | font-family: -apple-system,BlinkMacSystemFont,avenir next,avenir,helvetica neue,helvetica,ubuntu,roboto,noto,segoe ui,arial,sans-serif; 6 | } 7 | 8 | #modal-3 { 9 | display: none; 10 | } 11 | 12 | #modal-3.is-open { 13 | display: block; 14 | } 15 | 16 | .modal__overlay { 17 | position: fixed; 18 | top: 0; 19 | left: 0; 20 | right: 0; 21 | bottom: 0; 22 | background: rgba(0,0,0,0.6); 23 | display: flex; 24 | justify-content: center; 25 | align-items: center; 26 | } 27 | 28 | .modal__container { 29 | background-color: #fff; 30 | padding: 30px; 31 | max-width: 500px; 32 | max-height: 100vh; 33 | border-radius: 4px; 34 | overflow-y: auto; 35 | box-sizing: border-box; 36 | } 37 | 38 | .modal__header { 39 | display: flex; 40 | justify-content: space-between; 41 | align-items: center; 42 | } 43 | 44 | .modal__title { 45 | margin-top: 0; 46 | margin-bottom: 0; 47 | font-weight: 600; 48 | font-size: 1.25rem; 49 | line-height: 1.25; 50 | color: #00449e; 51 | box-sizing: border-box; 52 | } 53 | 54 | .modal__close { 55 | background: transparent; 56 | border: 0; 57 | } 58 | 59 | .modal__header .modal__close:before { content: "\2715"; } 60 | 61 | .modal__content { 62 | margin-top: 2rem; 63 | margin-bottom: 2rem; 64 | line-height: 1.5; 65 | color: rgba(0,0,0,.8); 66 | } 67 | 68 | .modal__btn { 69 | font-size: .875rem; 70 | padding-left: 1rem; 71 | padding-right: 1rem; 72 | padding-top: .5rem; 73 | padding-bottom: .5rem; 74 | background-color: #e6e6e6; 75 | color: rgba(0,0,0,.8); 76 | border-radius: .25rem; 77 | border-style: none; 78 | border-width: 0; 79 | cursor: pointer; 80 | -webkit-appearance: button; 81 | text-transform: none; 82 | overflow: visible; 83 | line-height: 1.15; 84 | margin: 0; 85 | will-change: transform; 86 | -moz-osx-font-smoothing: grayscale; 87 | -webkit-backface-visibility: hidden; 88 | backface-visibility: hidden; 89 | -webkit-transform: translateZ(0); 90 | transform: translateZ(0); 91 | transition: -webkit-transform .25s ease-out; 92 | transition: transform .25s ease-out; 93 | transition: transform .25s ease-out,-webkit-transform .25s ease-out; 94 | } 95 | 96 | .modal__btn:focus, .modal__btn:hover { 97 | -webkit-transform: scale(1.05); 98 | transform: scale(1.05); 99 | } 100 | 101 | .modal__btn-primary { 102 | background-color: #00449e; 103 | color: #fff; 104 | } 105 | 106 | /**************************\ 107 | Demo Animation Style 108 | \**************************/ 109 | @keyframes mmfadeIn { 110 | from { opacity: 0; } 111 | to { opacity: 1; } 112 | } 113 | 114 | @keyframes mmfadeOut { 115 | from { opacity: 1; } 116 | to { opacity: 0; } 117 | } 118 | 119 | @keyframes mmslideIn { 120 | from { transform: translateY(15%); } 121 | to { transform: translateY(0); } 122 | } 123 | 124 | @keyframes mmslideOut { 125 | from { transform: translateY(0); } 126 | to { transform: translateY(-10%); } 127 | } 128 | 129 | .micromodal-slide { 130 | display: none; 131 | } 132 | 133 | .micromodal-slide.is-open { 134 | display: block; 135 | } 136 | 137 | .micromodal-slide[aria-hidden="false"] .modal__overlay { 138 | animation: mmfadeIn .3s cubic-bezier(0.0, 0.0, 0.2, 1); 139 | } 140 | 141 | .micromodal-slide[aria-hidden="false"] .modal__container { 142 | animation: mmslideIn .3s cubic-bezier(0, 0, .2, 1); 143 | } 144 | 145 | .micromodal-slide[aria-hidden="true"] .modal__overlay { 146 | animation: mmfadeOut .3s cubic-bezier(0.0, 0.0, 0.2, 1); 147 | } 148 | 149 | .micromodal-slide[aria-hidden="true"] .modal__container { 150 | animation: mmslideOut .3s cubic-bezier(0, 0, .2, 1); 151 | } 152 | 153 | .micromodal-slide .modal__container, 154 | .micromodal-slide .modal__overlay { 155 | will-change: transform; 156 | } 157 | -------------------------------------------------------------------------------- /docs/src/styles/prism.css: -------------------------------------------------------------------------------- 1 | /** 2 | * GHColors theme by Avi Aryan (http://aviaryan.in) 3 | * Inspired by Github syntax coloring 4 | * - Modified for MicroModal 5 | */ 6 | code[class*=language-],pre[class*=language-]{color:blueviolet;font-family:Consolas,"Bitstream Vera Sans Mono","Courier New",Courier,monospace;direction:ltr;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;font-size:.95em;line-height:1.5em;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}code[class*=language-] ::-moz-selection,code[class*=language-]::-moz-selection,pre[class*=language-] ::-moz-selection,pre[class*=language-]::-moz-selection{background:#b3d4fc}code[class*=language-] ::selection,code[class*=language-]::selection,pre[class*=language-] ::selection,pre[class*=language-]::selection{background:#b3d4fc}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto;background-color:#f7f7f9}:not(pre)>code[class*=language-]{padding:1px .2em;background:#f8f8f8;border:1px solid #ddd}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#998;font-style:italic}.token.namespace{opacity:.7}.token.attr-value,.token.string{color:#e3116c}.token.operator,.token.punctuation{color:#393A34}.token.boolean,.token.constant,.token.entity,.token.inserted,.token.number,.token.property,.token.regex,.token.symbol,.token.url,.token.variable{color:#36acaa}.language-autohotkey .token.selector,.token.atrule,.token.attr-name,.token.keyword{color:#00a4db}.language-autohotkey .token.tag,.token.deleted,.token.function{color:#9a050f}.language-autohotkey .token.keyword,.token.selector,.token.tag{color:#00009f}.token.bold,.token.function,.token.important{font-weight:600}.token.italic{font-style:italic} 7 | -------------------------------------------------------------------------------- /docs/src/styles/tachyons.css: -------------------------------------------------------------------------------- 1 | /*! TACHYONS v4.11.1 | http://tachyons.io */ 2 | /*! normalize.css v8.0.0 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}h1{font-size:2em;margin:.67em 0}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}[hidden],template{display:none}.border-box,a,article,aside,blockquote,body,code,dd,div,dl,dt,fieldset,figcaption,figure,footer,form,h1,h2,h3,h4,h5,h6,header,html,input[type=email],input[type=number],input[type=password],input[type=tel],input[type=text],input[type=url],legend,li,main,nav,ol,p,pre,section,table,td,textarea,th,tr,ul{box-sizing:border-box}.aspect-ratio{height:0;position:relative}.aspect-ratio--16x9{padding-bottom:56.25%}.aspect-ratio--9x16{padding-bottom:177.77%}.aspect-ratio--4x3{padding-bottom:75%}.aspect-ratio--3x4{padding-bottom:133.33%}.aspect-ratio--6x4{padding-bottom:66.6%}.aspect-ratio--4x6{padding-bottom:150%}.aspect-ratio--8x5{padding-bottom:62.5%}.aspect-ratio--5x8{padding-bottom:160%}.aspect-ratio--7x5{padding-bottom:71.42%}.aspect-ratio--5x7{padding-bottom:140%}.aspect-ratio--1x1{padding-bottom:100%}.aspect-ratio--object{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;z-index:100}img{max-width:100%}.cover{background-size:cover!important}.contain{background-size:contain!important}.bg-center{background-position:50%}.bg-center,.bg-top{background-repeat:no-repeat}.bg-top{background-position:top}.bg-right{background-position:100%}.bg-bottom,.bg-right{background-repeat:no-repeat}.bg-bottom{background-position:bottom}.bg-left{background-repeat:no-repeat;background-position:0}.outline{outline:1px solid}.outline-transparent{outline:1px solid transparent}.outline-0{outline:0}.ba{border-style:solid;border-width:1px}.bt{border-top-style:solid;border-top-width:1px}.br{border-right-style:solid;border-right-width:1px}.bb{border-bottom-style:solid;border-bottom-width:1px}.bl{border-left-style:solid;border-left-width:1px}.bn{border-style:none;border-width:0}.b--black{border-color:#000}.b--near-black{border-color:#111}.b--dark-gray{border-color:#333}.b--mid-gray{border-color:#555}.b--gray{border-color:#777}.b--silver{border-color:#999}.b--light-silver{border-color:#aaa}.b--moon-gray{border-color:#ccc}.b--light-gray{border-color:#eee}.b--near-white{border-color:#f4f4f4}.b--white{border-color:#fff}.b--white-90{border-color:hsla(0,0%,100%,.9)}.b--white-80{border-color:hsla(0,0%,100%,.8)}.b--white-70{border-color:hsla(0,0%,100%,.7)}.b--white-60{border-color:hsla(0,0%,100%,.6)}.b--white-50{border-color:hsla(0,0%,100%,.5)}.b--white-40{border-color:hsla(0,0%,100%,.4)}.b--white-30{border-color:hsla(0,0%,100%,.3)}.b--white-20{border-color:hsla(0,0%,100%,.2)}.b--white-10{border-color:hsla(0,0%,100%,.1)}.b--white-05{border-color:hsla(0,0%,100%,.05)}.b--white-025{border-color:hsla(0,0%,100%,.025)}.b--white-0125{border-color:hsla(0,0%,100%,.0125)}.b--black-90{border-color:rgba(0,0,0,.9)}.b--black-80{border-color:rgba(0,0,0,.8)}.b--black-70{border-color:rgba(0,0,0,.7)}.b--black-60{border-color:rgba(0,0,0,.6)}.b--black-50{border-color:rgba(0,0,0,.5)}.b--black-40{border-color:rgba(0,0,0,.4)}.b--black-30{border-color:rgba(0,0,0,.3)}.b--black-20{border-color:rgba(0,0,0,.2)}.b--black-10{border-color:rgba(0,0,0,.1)}.b--black-05{border-color:rgba(0,0,0,.05)}.b--black-025{border-color:rgba(0,0,0,.025)}.b--black-0125{border-color:rgba(0,0,0,.0125)}.b--dark-red{border-color:#e7040f}.b--red{border-color:#ff4136}.b--light-red{border-color:#ff725c}.b--orange{border-color:#ff6300}.b--gold{border-color:#ffb700}.b--yellow{border-color:gold}.b--light-yellow{border-color:#fbf1a9}.b--purple{border-color:#5e2ca5}.b--light-purple{border-color:#a463f2}.b--dark-pink{border-color:#d5008f}.b--hot-pink{border-color:#ff41b4}.b--pink{border-color:#ff80cc}.b--light-pink{border-color:#ffa3d7}.b--dark-green{border-color:#137752}.b--green{border-color:#19a974}.b--light-green{border-color:#9eebcf}.b--navy{border-color:#001b44}.b--dark-blue{border-color:#00449e}.b--blue{border-color:#357edd}.b--light-blue{border-color:#96ccff}.b--lightest-blue{border-color:#cdecff}.b--washed-blue{border-color:#f6fffe}.b--washed-green{border-color:#e8fdf5}.b--washed-yellow{border-color:#fffceb}.b--washed-red{border-color:#ffdfdf}.b--transparent{border-color:transparent}.b--inherit{border-color:inherit}.br0{border-radius:0}.br1{border-radius:.125rem}.br2{border-radius:.25rem}.br3{border-radius:.5rem}.br4{border-radius:1rem}.br-100{border-radius:100%}.br-pill{border-radius:9999px}.br--bottom{border-top-left-radius:0;border-top-right-radius:0}.br--top{border-bottom-right-radius:0}.br--right,.br--top{border-bottom-left-radius:0}.br--right{border-top-left-radius:0}.br--left{border-top-right-radius:0;border-bottom-right-radius:0}.b--dotted{border-style:dotted}.b--dashed{border-style:dashed}.b--solid{border-style:solid}.b--none{border-style:none}.bw0{border-width:0}.bw1{border-width:.125rem}.bw2{border-width:.25rem}.bw3{border-width:.5rem}.bw4{border-width:1rem}.bw5{border-width:2rem}.bt-0{border-top-width:0}.br-0{border-right-width:0}.bb-0{border-bottom-width:0}.bl-0{border-left-width:0}.shadow-1{box-shadow:0 0 4px 2px rgba(0,0,0,.2)}.shadow-2{box-shadow:0 0 8px 2px rgba(0,0,0,.2)}.shadow-3{box-shadow:2px 2px 4px 2px rgba(0,0,0,.2)}.shadow-4{box-shadow:2px 2px 8px 0 rgba(0,0,0,.2)}.shadow-5{box-shadow:4px 4px 8px 0 rgba(0,0,0,.2)}.pre{overflow-x:auto;overflow-y:hidden;overflow:scroll}.top-0{top:0}.right-0{right:0}.bottom-0{bottom:0}.left-0{left:0}.top-1{top:1rem}.right-1{right:1rem}.bottom-1{bottom:1rem}.left-1{left:1rem}.top-2{top:2rem}.right-2{right:2rem}.bottom-2{bottom:2rem}.left-2{left:2rem}.top--1{top:-1rem}.right--1{right:-1rem}.bottom--1{bottom:-1rem}.left--1{left:-1rem}.top--2{top:-2rem}.right--2{right:-2rem}.bottom--2{bottom:-2rem}.left--2{left:-2rem}.absolute--fill{top:0;right:0;bottom:0;left:0}.cf:after,.cf:before{content:" ";display:table}.cf:after{clear:both}.cf{*zoom:1}.cl{clear:left}.cr{clear:right}.cb{clear:both}.cn{clear:none}.dn{display:none}.di{display:inline}.db{display:block}.dib{display:inline-block}.dit{display:inline-table}.dt{display:table}.dtc{display:table-cell}.dt-row{display:table-row}.dt-row-group{display:table-row-group}.dt-column{display:table-column}.dt-column-group{display:table-column-group}.dt--fixed{table-layout:fixed;width:100%}.flex{display:flex}.inline-flex{display:inline-flex}.flex-auto{flex:1 1 auto;min-width:0;min-height:0}.flex-none{flex:none}.flex-column{flex-direction:column}.flex-row{flex-direction:row}.flex-wrap{flex-wrap:wrap}.flex-nowrap{flex-wrap:nowrap}.flex-wrap-reverse{flex-wrap:wrap-reverse}.flex-column-reverse{flex-direction:column-reverse}.flex-row-reverse{flex-direction:row-reverse}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.items-baseline{align-items:baseline}.items-stretch{align-items:stretch}.self-start{align-self:flex-start}.self-end{align-self:flex-end}.self-center{align-self:center}.self-baseline{align-self:baseline}.self-stretch{align-self:stretch}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.justify-around{justify-content:space-around}.content-start{align-content:flex-start}.content-end{align-content:flex-end}.content-center{align-content:center}.content-between{align-content:space-between}.content-around{align-content:space-around}.content-stretch{align-content:stretch}.order-0{order:0}.order-1{order:1}.order-2{order:2}.order-3{order:3}.order-4{order:4}.order-5{order:5}.order-6{order:6}.order-7{order:7}.order-8{order:8}.order-last{order:99999}.flex-grow-0{flex-grow:0}.flex-grow-1{flex-grow:1}.flex-shrink-0{flex-shrink:0}.flex-shrink-1{flex-shrink:1}.fl{float:left}.fl,.fr{_display:inline}.fr{float:right}.fn{float:none}.sans-serif{font-family:-apple-system,BlinkMacSystemFont,avenir next,avenir,helvetica neue,helvetica,ubuntu,roboto,noto,segoe ui,arial,sans-serif}.serif{font-family:georgia,times,serif}.system-sans-serif{font-family:sans-serif}.system-serif{font-family:serif}.code,code{font-family:Consolas,monaco,monospace}.courier{font-family:Courier Next,courier,monospace}.helvetica{font-family:helvetica neue,helvetica,sans-serif}.avenir{font-family:avenir next,avenir,sans-serif}.athelas{font-family:athelas,georgia,serif}.georgia{font-family:georgia,serif}.times{font-family:times,serif}.bodoni{font-family:Bodoni MT,serif}.calisto{font-family:Calisto MT,serif}.garamond{font-family:garamond,serif}.baskerville{font-family:baskerville,serif}.i{font-style:italic}.fs-normal{font-style:normal}.normal{font-weight:400}.b{font-weight:700}.fw1{font-weight:100}.fw2{font-weight:200}.fw3{font-weight:300}.fw4{font-weight:400}.fw5{font-weight:500}.fw6{font-weight:600}.fw7{font-weight:700}.fw8{font-weight:800}.fw9{font-weight:900}.input-reset{-webkit-appearance:none;-moz-appearance:none}.button-reset::-moz-focus-inner,.input-reset::-moz-focus-inner{border:0;padding:0}.h1{height:1rem}.h2{height:2rem}.h3{height:4rem}.h4{height:8rem}.h5{height:16rem}.h-25{height:25%}.h-50{height:50%}.h-75{height:75%}.h-100{height:100%}.min-h-100{min-height:100%}.vh-25{height:25vh}.vh-50{height:50vh}.vh-75{height:75vh}.vh-100{height:100vh}.min-vh-100{min-height:100vh}.h-auto{height:auto}.h-inherit{height:inherit}.tracked{letter-spacing:.1em}.tracked-tight{letter-spacing:-.05em}.tracked-mega{letter-spacing:.25em}.lh-solid{line-height:1}.lh-title{line-height:1.25}.lh-copy{line-height:1.5}.link{text-decoration:none}.link,.link:active,.link:focus,.link:hover,.link:link,.link:visited{transition:color .15s ease-in}.link:focus{outline:1px dotted currentColor}.list{list-style-type:none}.mw-100{max-width:100%}.mw1{max-width:1rem}.mw2{max-width:2rem}.mw3{max-width:4rem}.mw4{max-width:8rem}.mw5{max-width:16rem}.mw6{max-width:32rem}.mw7{max-width:48rem}.mw8{max-width:64rem}.mw9{max-width:96rem}.mw-none{max-width:none}.w1{width:1rem}.w2{width:2rem}.w3{width:4rem}.w4{width:8rem}.w5{width:16rem}.w-10{width:10%}.w-20{width:20%}.w-25{width:25%}.w-30{width:30%}.w-33{width:33%}.w-34{width:34%}.w-40{width:40%}.w-50{width:50%}.w-60{width:60%}.w-70{width:70%}.w-75{width:75%}.w-80{width:80%}.w-90{width:90%}.w-100{width:100%}.w-third{width:33.33333%}.w-two-thirds{width:66.66667%}.w-auto{width:auto}.overflow-visible{overflow:visible}.overflow-hidden{overflow:hidden}.overflow-scroll{overflow:scroll}.overflow-auto{overflow:auto}.overflow-x-visible{overflow-x:visible}.overflow-x-hidden{overflow-x:hidden}.overflow-x-scroll{overflow-x:scroll}.overflow-x-auto{overflow-x:auto}.overflow-y-visible{overflow-y:visible}.overflow-y-hidden{overflow-y:hidden}.overflow-y-scroll{overflow-y:scroll}.overflow-y-auto{overflow-y:auto}.static{position:static}.relative{position:relative}.absolute{position:absolute}.fixed{position:fixed}.o-100{opacity:1}.o-90{opacity:.9}.o-80{opacity:.8}.o-70{opacity:.7}.o-60{opacity:.6}.o-50{opacity:.5}.o-40{opacity:.4}.o-30{opacity:.3}.o-20{opacity:.2}.o-10{opacity:.1}.o-05{opacity:.05}.o-025{opacity:.025}.o-0{opacity:0}.rotate-45{-webkit-transform:rotate(45deg);transform:rotate(45deg)}.rotate-90{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.rotate-135{-webkit-transform:rotate(135deg);transform:rotate(135deg)}.rotate-180{-webkit-transform:rotate(180deg);transform:rotate(180deg)}.rotate-225{-webkit-transform:rotate(225deg);transform:rotate(225deg)}.rotate-270{-webkit-transform:rotate(270deg);transform:rotate(270deg)}.rotate-315{-webkit-transform:rotate(315deg);transform:rotate(315deg)}.black-90{color:rgba(0,0,0,.9)}.black-80{color:rgba(0,0,0,.8)}.black-70{color:rgba(0,0,0,.7)}.black-60{color:rgba(0,0,0,.6)}.black-50{color:rgba(0,0,0,.5)}.black-40{color:rgba(0,0,0,.4)}.black-30{color:rgba(0,0,0,.3)}.black-20{color:rgba(0,0,0,.2)}.black-10{color:rgba(0,0,0,.1)}.black-05{color:rgba(0,0,0,.05)}.white-90{color:hsla(0,0%,100%,.9)}.white-80{color:hsla(0,0%,100%,.8)}.white-70{color:hsla(0,0%,100%,.7)}.white-60{color:hsla(0,0%,100%,.6)}.white-50{color:hsla(0,0%,100%,.5)}.white-40{color:hsla(0,0%,100%,.4)}.white-30{color:hsla(0,0%,100%,.3)}.white-20{color:hsla(0,0%,100%,.2)}.white-10{color:hsla(0,0%,100%,.1)}.black{color:#000}.near-black{color:#111}.dark-gray{color:#333}.mid-gray{color:#555}.gray{color:#777}.silver{color:#999}.light-silver{color:#aaa}.moon-gray{color:#ccc}.light-gray{color:#eee}.near-white{color:#f4f4f4}.white{color:#fff}.dark-red{color:#e7040f}.red{color:#ff4136}.light-red{color:#ff725c}.orange{color:#ff6300}.gold{color:#ffb700}.yellow{color:gold}.light-yellow{color:#fbf1a9}.purple{color:#5e2ca5}.light-purple{color:#a463f2}.dark-pink{color:#d5008f}.hot-pink{color:#ff41b4}.pink{color:#ff80cc}.light-pink{color:#ffa3d7}.dark-green{color:#137752}.green{color:#19a974}.light-green{color:#9eebcf}.navy{color:#001b44}.dark-blue{color:#00449e}.blue{color:#357edd}.light-blue{color:#96ccff}.lightest-blue{color:#cdecff}.washed-blue{color:#f6fffe}.washed-green{color:#e8fdf5}.washed-yellow{color:#fffceb}.washed-red{color:#ffdfdf}.color-inherit{color:inherit}.bg-black-90{background-color:rgba(0,0,0,.9)}.bg-black-80{background-color:rgba(0,0,0,.8)}.bg-black-70{background-color:rgba(0,0,0,.7)}.bg-black-60{background-color:rgba(0,0,0,.6)}.bg-black-50{background-color:rgba(0,0,0,.5)}.bg-black-40{background-color:rgba(0,0,0,.4)}.bg-black-30{background-color:rgba(0,0,0,.3)}.bg-black-20{background-color:rgba(0,0,0,.2)}.bg-black-10{background-color:rgba(0,0,0,.1)}.bg-black-05{background-color:rgba(0,0,0,.05)}.bg-white-90{background-color:hsla(0,0%,100%,.9)}.bg-white-80{background-color:hsla(0,0%,100%,.8)}.bg-white-70{background-color:hsla(0,0%,100%,.7)}.bg-white-60{background-color:hsla(0,0%,100%,.6)}.bg-white-50{background-color:hsla(0,0%,100%,.5)}.bg-white-40{background-color:hsla(0,0%,100%,.4)}.bg-white-30{background-color:hsla(0,0%,100%,.3)}.bg-white-20{background-color:hsla(0,0%,100%,.2)}.bg-white-10{background-color:hsla(0,0%,100%,.1)}.bg-black{background-color:#000}.bg-near-black{background-color:#111}.bg-dark-gray{background-color:#333}.bg-mid-gray{background-color:#555}.bg-gray{background-color:#777}.bg-silver{background-color:#999}.bg-light-silver{background-color:#aaa}.bg-moon-gray{background-color:#ccc}.bg-light-gray{background-color:#eee}.bg-near-white{background-color:#f4f4f4}.bg-white{background-color:#fff}.bg-transparent{background-color:transparent}.bg-dark-red{background-color:#e7040f}.bg-red{background-color:#ff4136}.bg-light-red{background-color:#ff725c}.bg-orange{background-color:#ff6300}.bg-gold{background-color:#ffb700}.bg-yellow{background-color:gold}.bg-light-yellow{background-color:#fbf1a9}.bg-purple{background-color:#5e2ca5}.bg-light-purple{background-color:#a463f2}.bg-dark-pink{background-color:#d5008f}.bg-hot-pink{background-color:#ff41b4}.bg-pink{background-color:#ff80cc}.bg-light-pink{background-color:#ffa3d7}.bg-dark-green{background-color:#137752}.bg-green{background-color:#19a974}.bg-light-green{background-color:#9eebcf}.bg-navy{background-color:#001b44}.bg-dark-blue{background-color:#00449e}.bg-blue{background-color:#357edd}.bg-light-blue{background-color:#96ccff}.bg-lightest-blue{background-color:#cdecff}.bg-washed-blue{background-color:#f6fffe}.bg-washed-green{background-color:#e8fdf5}.bg-washed-yellow{background-color:#fffceb}.bg-washed-red{background-color:#ffdfdf}.bg-inherit{background-color:inherit}.hover-black:focus,.hover-black:hover{color:#000}.hover-near-black:focus,.hover-near-black:hover{color:#111}.hover-dark-gray:focus,.hover-dark-gray:hover{color:#333}.hover-mid-gray:focus,.hover-mid-gray:hover{color:#555}.hover-gray:focus,.hover-gray:hover{color:#777}.hover-silver:focus,.hover-silver:hover{color:#999}.hover-light-silver:focus,.hover-light-silver:hover{color:#aaa}.hover-moon-gray:focus,.hover-moon-gray:hover{color:#ccc}.hover-light-gray:focus,.hover-light-gray:hover{color:#eee}.hover-near-white:focus,.hover-near-white:hover{color:#f4f4f4}.hover-white:focus,.hover-white:hover{color:#fff}.hover-black-90:focus,.hover-black-90:hover{color:rgba(0,0,0,.9)}.hover-black-80:focus,.hover-black-80:hover{color:rgba(0,0,0,.8)}.hover-black-70:focus,.hover-black-70:hover{color:rgba(0,0,0,.7)}.hover-black-60:focus,.hover-black-60:hover{color:rgba(0,0,0,.6)}.hover-black-50:focus,.hover-black-50:hover{color:rgba(0,0,0,.5)}.hover-black-40:focus,.hover-black-40:hover{color:rgba(0,0,0,.4)}.hover-black-30:focus,.hover-black-30:hover{color:rgba(0,0,0,.3)}.hover-black-20:focus,.hover-black-20:hover{color:rgba(0,0,0,.2)}.hover-black-10:focus,.hover-black-10:hover{color:rgba(0,0,0,.1)}.hover-white-90:focus,.hover-white-90:hover{color:hsla(0,0%,100%,.9)}.hover-white-80:focus,.hover-white-80:hover{color:hsla(0,0%,100%,.8)}.hover-white-70:focus,.hover-white-70:hover{color:hsla(0,0%,100%,.7)}.hover-white-60:focus,.hover-white-60:hover{color:hsla(0,0%,100%,.6)}.hover-white-50:focus,.hover-white-50:hover{color:hsla(0,0%,100%,.5)}.hover-white-40:focus,.hover-white-40:hover{color:hsla(0,0%,100%,.4)}.hover-white-30:focus,.hover-white-30:hover{color:hsla(0,0%,100%,.3)}.hover-white-20:focus,.hover-white-20:hover{color:hsla(0,0%,100%,.2)}.hover-white-10:focus,.hover-white-10:hover{color:hsla(0,0%,100%,.1)}.hover-inherit:focus,.hover-inherit:hover{color:inherit}.hover-bg-black:focus,.hover-bg-black:hover{background-color:#000}.hover-bg-near-black:focus,.hover-bg-near-black:hover{background-color:#111}.hover-bg-dark-gray:focus,.hover-bg-dark-gray:hover{background-color:#333}.hover-bg-mid-gray:focus,.hover-bg-mid-gray:hover{background-color:#555}.hover-bg-gray:focus,.hover-bg-gray:hover{background-color:#777}.hover-bg-silver:focus,.hover-bg-silver:hover{background-color:#999}.hover-bg-light-silver:focus,.hover-bg-light-silver:hover{background-color:#aaa}.hover-bg-moon-gray:focus,.hover-bg-moon-gray:hover{background-color:#ccc}.hover-bg-light-gray:focus,.hover-bg-light-gray:hover{background-color:#eee}.hover-bg-near-white:focus,.hover-bg-near-white:hover{background-color:#f4f4f4}.hover-bg-white:focus,.hover-bg-white:hover{background-color:#fff}.hover-bg-transparent:focus,.hover-bg-transparent:hover{background-color:transparent}.hover-bg-black-90:focus,.hover-bg-black-90:hover{background-color:rgba(0,0,0,.9)}.hover-bg-black-80:focus,.hover-bg-black-80:hover{background-color:rgba(0,0,0,.8)}.hover-bg-black-70:focus,.hover-bg-black-70:hover{background-color:rgba(0,0,0,.7)}.hover-bg-black-60:focus,.hover-bg-black-60:hover{background-color:rgba(0,0,0,.6)}.hover-bg-black-50:focus,.hover-bg-black-50:hover{background-color:rgba(0,0,0,.5)}.hover-bg-black-40:focus,.hover-bg-black-40:hover{background-color:rgba(0,0,0,.4)}.hover-bg-black-30:focus,.hover-bg-black-30:hover{background-color:rgba(0,0,0,.3)}.hover-bg-black-20:focus,.hover-bg-black-20:hover{background-color:rgba(0,0,0,.2)}.hover-bg-black-10:focus,.hover-bg-black-10:hover{background-color:rgba(0,0,0,.1)}.hover-bg-white-90:focus,.hover-bg-white-90:hover{background-color:hsla(0,0%,100%,.9)}.hover-bg-white-80:focus,.hover-bg-white-80:hover{background-color:hsla(0,0%,100%,.8)}.hover-bg-white-70:focus,.hover-bg-white-70:hover{background-color:hsla(0,0%,100%,.7)}.hover-bg-white-60:focus,.hover-bg-white-60:hover{background-color:hsla(0,0%,100%,.6)}.hover-bg-white-50:focus,.hover-bg-white-50:hover{background-color:hsla(0,0%,100%,.5)}.hover-bg-white-40:focus,.hover-bg-white-40:hover{background-color:hsla(0,0%,100%,.4)}.hover-bg-white-30:focus,.hover-bg-white-30:hover{background-color:hsla(0,0%,100%,.3)}.hover-bg-white-20:focus,.hover-bg-white-20:hover{background-color:hsla(0,0%,100%,.2)}.hover-bg-white-10:focus,.hover-bg-white-10:hover{background-color:hsla(0,0%,100%,.1)}.hover-dark-red:focus,.hover-dark-red:hover{color:#e7040f}.hover-red:focus,.hover-red:hover{color:#ff4136}.hover-light-red:focus,.hover-light-red:hover{color:#ff725c}.hover-orange:focus,.hover-orange:hover{color:#ff6300}.hover-gold:focus,.hover-gold:hover{color:#ffb700}.hover-yellow:focus,.hover-yellow:hover{color:gold}.hover-light-yellow:focus,.hover-light-yellow:hover{color:#fbf1a9}.hover-purple:focus,.hover-purple:hover{color:#5e2ca5}.hover-light-purple:focus,.hover-light-purple:hover{color:#a463f2}.hover-dark-pink:focus,.hover-dark-pink:hover{color:#d5008f}.hover-hot-pink:focus,.hover-hot-pink:hover{color:#ff41b4}.hover-pink:focus,.hover-pink:hover{color:#ff80cc}.hover-light-pink:focus,.hover-light-pink:hover{color:#ffa3d7}.hover-dark-green:focus,.hover-dark-green:hover{color:#137752}.hover-green:focus,.hover-green:hover{color:#19a974}.hover-light-green:focus,.hover-light-green:hover{color:#9eebcf}.hover-navy:focus,.hover-navy:hover{color:#001b44}.hover-dark-blue:focus,.hover-dark-blue:hover{color:#00449e}.hover-blue:focus,.hover-blue:hover{color:#357edd}.hover-light-blue:focus,.hover-light-blue:hover{color:#96ccff}.hover-lightest-blue:focus,.hover-lightest-blue:hover{color:#cdecff}.hover-washed-blue:focus,.hover-washed-blue:hover{color:#f6fffe}.hover-washed-green:focus,.hover-washed-green:hover{color:#e8fdf5}.hover-washed-yellow:focus,.hover-washed-yellow:hover{color:#fffceb}.hover-washed-red:focus,.hover-washed-red:hover{color:#ffdfdf}.hover-bg-dark-red:focus,.hover-bg-dark-red:hover{background-color:#e7040f}.hover-bg-red:focus,.hover-bg-red:hover{background-color:#ff4136}.hover-bg-light-red:focus,.hover-bg-light-red:hover{background-color:#ff725c}.hover-bg-orange:focus,.hover-bg-orange:hover{background-color:#ff6300}.hover-bg-gold:focus,.hover-bg-gold:hover{background-color:#ffb700}.hover-bg-yellow:focus,.hover-bg-yellow:hover{background-color:gold}.hover-bg-light-yellow:focus,.hover-bg-light-yellow:hover{background-color:#fbf1a9}.hover-bg-purple:focus,.hover-bg-purple:hover{background-color:#5e2ca5}.hover-bg-light-purple:focus,.hover-bg-light-purple:hover{background-color:#a463f2}.hover-bg-dark-pink:focus,.hover-bg-dark-pink:hover{background-color:#d5008f}.hover-bg-hot-pink:focus,.hover-bg-hot-pink:hover{background-color:#ff41b4}.hover-bg-pink:focus,.hover-bg-pink:hover{background-color:#ff80cc}.hover-bg-light-pink:focus,.hover-bg-light-pink:hover{background-color:#ffa3d7}.hover-bg-dark-green:focus,.hover-bg-dark-green:hover{background-color:#137752}.hover-bg-green:focus,.hover-bg-green:hover{background-color:#19a974}.hover-bg-light-green:focus,.hover-bg-light-green:hover{background-color:#9eebcf}.hover-bg-navy:focus,.hover-bg-navy:hover{background-color:#001b44}.hover-bg-dark-blue:focus,.hover-bg-dark-blue:hover{background-color:#00449e}.hover-bg-blue:focus,.hover-bg-blue:hover{background-color:#357edd}.hover-bg-light-blue:focus,.hover-bg-light-blue:hover{background-color:#96ccff}.hover-bg-lightest-blue:focus,.hover-bg-lightest-blue:hover{background-color:#cdecff}.hover-bg-washed-blue:focus,.hover-bg-washed-blue:hover{background-color:#f6fffe}.hover-bg-washed-green:focus,.hover-bg-washed-green:hover{background-color:#e8fdf5}.hover-bg-washed-yellow:focus,.hover-bg-washed-yellow:hover{background-color:#fffceb}.hover-bg-washed-red:focus,.hover-bg-washed-red:hover{background-color:#ffdfdf}.hover-bg-inherit:focus,.hover-bg-inherit:hover{background-color:inherit}.pa0{padding:0}.pa1{padding:.25rem}.pa2{padding:.5rem}.pa3{padding:1rem}.pa4{padding:2rem}.pa5{padding:4rem}.pa6{padding:8rem}.pa7{padding:16rem}.pl0{padding-left:0}.pl1{padding-left:.25rem}.pl2{padding-left:.5rem}.pl3{padding-left:1rem}.pl4{padding-left:2rem}.pl5{padding-left:4rem}.pl6{padding-left:8rem}.pl7{padding-left:16rem}.pr0{padding-right:0}.pr1{padding-right:.25rem}.pr2{padding-right:.5rem}.pr3{padding-right:1rem}.pr4{padding-right:2rem}.pr5{padding-right:4rem}.pr6{padding-right:8rem}.pr7{padding-right:16rem}.pb0{padding-bottom:0}.pb1{padding-bottom:.25rem}.pb2{padding-bottom:.5rem}.pb3{padding-bottom:1rem}.pb4{padding-bottom:2rem}.pb5{padding-bottom:4rem}.pb6{padding-bottom:8rem}.pb7{padding-bottom:16rem}.pt0{padding-top:0}.pt1{padding-top:.25rem}.pt2{padding-top:.5rem}.pt3{padding-top:1rem}.pt4{padding-top:2rem}.pt5{padding-top:4rem}.pt6{padding-top:8rem}.pt7{padding-top:16rem}.pv0{padding-top:0;padding-bottom:0}.pv1{padding-top:.25rem;padding-bottom:.25rem}.pv2{padding-top:.5rem;padding-bottom:.5rem}.pv3{padding-top:1rem;padding-bottom:1rem}.pv4{padding-top:2rem;padding-bottom:2rem}.pv5{padding-top:4rem;padding-bottom:4rem}.pv6{padding-top:8rem;padding-bottom:8rem}.pv7{padding-top:16rem;padding-bottom:16rem}.ph0{padding-left:0;padding-right:0}.ph1{padding-left:.25rem;padding-right:.25rem}.ph2{padding-left:.5rem;padding-right:.5rem}.ph3{padding-left:1rem;padding-right:1rem}.ph4{padding-left:2rem;padding-right:2rem}.ph5{padding-left:4rem;padding-right:4rem}.ph6{padding-left:8rem;padding-right:8rem}.ph7{padding-left:16rem;padding-right:16rem}.ma0{margin:0}.ma1{margin:.25rem}.ma2{margin:.5rem}.ma3{margin:1rem}.ma4{margin:2rem}.ma5{margin:4rem}.ma6{margin:8rem}.ma7{margin:16rem}.ml0{margin-left:0}.ml1{margin-left:.25rem}.ml2{margin-left:.5rem}.ml3{margin-left:1rem}.ml4{margin-left:2rem}.ml5{margin-left:4rem}.ml6{margin-left:8rem}.ml7{margin-left:16rem}.mr0{margin-right:0}.mr1{margin-right:.25rem}.mr2{margin-right:.5rem}.mr3{margin-right:1rem}.mr4{margin-right:2rem}.mr5{margin-right:4rem}.mr6{margin-right:8rem}.mr7{margin-right:16rem}.mb0{margin-bottom:0}.mb1{margin-bottom:.25rem}.mb2{margin-bottom:.5rem}.mb3{margin-bottom:1rem}.mb4{margin-bottom:2rem}.mb5{margin-bottom:4rem}.mb6{margin-bottom:8rem}.mb7{margin-bottom:16rem}.mt0{margin-top:0}.mt1{margin-top:.25rem}.mt2{margin-top:.5rem}.mt3{margin-top:1rem}.mt4{margin-top:2rem}.mt5{margin-top:4rem}.mt6{margin-top:8rem}.mt7{margin-top:16rem}.mv0{margin-top:0;margin-bottom:0}.mv1{margin-top:.25rem;margin-bottom:.25rem}.mv2{margin-top:.5rem;margin-bottom:.5rem}.mv3{margin-top:1rem;margin-bottom:1rem}.mv4{margin-top:2rem;margin-bottom:2rem}.mv5{margin-top:4rem;margin-bottom:4rem}.mv6{margin-top:8rem;margin-bottom:8rem}.mv7{margin-top:16rem;margin-bottom:16rem}.mh0{margin-left:0;margin-right:0}.mh1{margin-left:.25rem;margin-right:.25rem}.mh2{margin-left:.5rem;margin-right:.5rem}.mh3{margin-left:1rem;margin-right:1rem}.mh4{margin-left:2rem;margin-right:2rem}.mh5{margin-left:4rem;margin-right:4rem}.mh6{margin-left:8rem;margin-right:8rem}.mh7{margin-left:16rem;margin-right:16rem}.na1{margin:-.25rem}.na2{margin:-.5rem}.na3{margin:-1rem}.na4{margin:-2rem}.na5{margin:-4rem}.na6{margin:-8rem}.na7{margin:-16rem}.nl1{margin-left:-.25rem}.nl2{margin-left:-.5rem}.nl3{margin-left:-1rem}.nl4{margin-left:-2rem}.nl5{margin-left:-4rem}.nl6{margin-left:-8rem}.nl7{margin-left:-16rem}.nr1{margin-right:-.25rem}.nr2{margin-right:-.5rem}.nr3{margin-right:-1rem}.nr4{margin-right:-2rem}.nr5{margin-right:-4rem}.nr6{margin-right:-8rem}.nr7{margin-right:-16rem}.nb1{margin-bottom:-.25rem}.nb2{margin-bottom:-.5rem}.nb3{margin-bottom:-1rem}.nb4{margin-bottom:-2rem}.nb5{margin-bottom:-4rem}.nb6{margin-bottom:-8rem}.nb7{margin-bottom:-16rem}.nt1{margin-top:-.25rem}.nt2{margin-top:-.5rem}.nt3{margin-top:-1rem}.nt4{margin-top:-2rem}.nt5{margin-top:-4rem}.nt6{margin-top:-8rem}.nt7{margin-top:-16rem}.collapse{border-collapse:collapse;border-spacing:0}.striped--light-silver:nth-child(odd){background-color:#aaa}.striped--moon-gray:nth-child(odd){background-color:#ccc}.striped--light-gray:nth-child(odd){background-color:#eee}.striped--near-white:nth-child(odd){background-color:#f4f4f4}.stripe-light:nth-child(odd){background-color:hsla(0,0%,100%,.1)}.stripe-dark:nth-child(odd){background-color:rgba(0,0,0,.1)}.strike{text-decoration:line-through}.underline{text-decoration:underline}.no-underline{text-decoration:none}.tl{text-align:left}.tr{text-align:right}.tc{text-align:center}.tj{text-align:justify}.ttc{text-transform:capitalize}.ttl{text-transform:lowercase}.ttu{text-transform:uppercase}.ttn{text-transform:none}.f-6,.f-headline{font-size:6rem}.f-5,.f-subheadline{font-size:5rem}.f1{font-size:3rem}.f2{font-size:2.25rem}.f3{font-size:1.5rem}.f4{font-size:1.25rem}.f5{font-size:1rem}.f6{font-size:.875rem}.f7{font-size:.75rem}.measure{max-width:30em}.measure-wide{max-width:34em}.measure-narrow{max-width:20em}.indent{text-indent:1em;margin-top:0;margin-bottom:0}.small-caps{font-variant:small-caps}.truncate{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.overflow-container{overflow-y:scroll}.center{margin-left:auto}.center,.mr-auto{margin-right:auto}.ml-auto{margin-left:auto}.clip{position:fixed!important;_position:absolute!important;clip:rect(1px 1px 1px 1px);clip:rect(1px,1px,1px,1px)}.ws-normal{white-space:normal}.nowrap{white-space:nowrap}.pre{white-space:pre}.v-base{vertical-align:baseline}.v-mid{vertical-align:middle}.v-top{vertical-align:top}.v-btm{vertical-align:bottom}.dim{opacity:1}.dim,.dim:focus,.dim:hover{transition:opacity .15s ease-in}.dim:focus,.dim:hover{opacity:.5}.dim:active{opacity:.8;transition:opacity .15s ease-out}.glow,.glow:focus,.glow:hover{transition:opacity .15s ease-in}.glow:focus,.glow:hover{opacity:1}.hide-child .child{opacity:0;transition:opacity .15s ease-in}.hide-child:active .child,.hide-child:focus .child,.hide-child:hover .child{opacity:1;transition:opacity .15s ease-in}.underline-hover:focus,.underline-hover:hover{text-decoration:underline}.grow{-moz-osx-font-smoothing:grayscale;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-transform:translateZ(0);transform:translateZ(0);transition:-webkit-transform .25s ease-out;transition:transform .25s ease-out;transition:transform .25s ease-out,-webkit-transform .25s ease-out}.grow:focus,.grow:hover{-webkit-transform:scale(1.05);transform:scale(1.05)}.grow:active{-webkit-transform:scale(.9);transform:scale(.9)}.grow-large{-moz-osx-font-smoothing:grayscale;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-transform:translateZ(0);transform:translateZ(0);transition:-webkit-transform .25s ease-in-out;transition:transform .25s ease-in-out;transition:transform .25s ease-in-out,-webkit-transform .25s ease-in-out}.grow-large:focus,.grow-large:hover{-webkit-transform:scale(1.2);transform:scale(1.2)}.grow-large:active{-webkit-transform:scale(.95);transform:scale(.95)}.pointer:hover,.shadow-hover{cursor:pointer}.shadow-hover{position:relative;transition:all .5s cubic-bezier(.165,.84,.44,1)}.shadow-hover:after{content:"";box-shadow:0 0 16px 2px rgba(0,0,0,.2);border-radius:inherit;opacity:0;position:absolute;top:0;left:0;width:100%;height:100%;z-index:-1;transition:opacity .5s cubic-bezier(.165,.84,.44,1)}.shadow-hover:focus:after,.shadow-hover:hover:after{opacity:1}.bg-animate,.bg-animate:focus,.bg-animate:hover{transition:background-color .15s ease-in-out}.z-0{z-index:0}.z-1{z-index:1}.z-2{z-index:2}.z-3{z-index:3}.z-4{z-index:4}.z-5{z-index:5}.z-999{z-index:999}.z-9999{z-index:9999}.z-max{z-index:2147483647}.z-inherit{z-index:inherit}.z-initial{z-index:auto}.z-unset{z-index:unset}.nested-copy-line-height ol,.nested-copy-line-height p,.nested-copy-line-height ul{line-height:1.5}.nested-headline-line-height h1,.nested-headline-line-height h2,.nested-headline-line-height h3,.nested-headline-line-height h4,.nested-headline-line-height h5,.nested-headline-line-height h6{line-height:1.25}.nested-list-reset ol,.nested-list-reset ul{padding-left:0;margin-left:0;list-style-type:none}.nested-copy-indent p+p{text-indent:1em;margin-top:0;margin-bottom:0}.nested-copy-separator p+p{margin-top:1.5em}.nested-img img{width:100%;max-width:100%;display:block}.nested-links a{color:#357edd;transition:color .15s ease-in}.nested-links a:focus,.nested-links a:hover{color:#96ccff;transition:color .15s ease-in}.debug *{outline:1px solid gold}.debug-white *{outline:1px solid #fff}.debug-black *{outline:1px solid #000}.debug-grid{background:transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAFElEQVR4AWPAC97/9x0eCsAEPgwAVLshdpENIxcAAAAASUVORK5CYII=) repeat 0 0}.debug-grid-16{background:transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAMklEQVR4AWOgCLz/b0epAa6UGuBOqQHOQHLUgFEDnAbcBZ4UGwDOkiCnkIhdgNgNxAYAiYlD+8sEuo8AAAAASUVORK5CYII=) repeat 0 0}.debug-grid-8-solid{background:#fff url(data:image/gif;base64,R0lGODdhCAAIAPEAAADw/wDx/////wAAACwAAAAACAAIAAACDZQvgaeb/lxbAIKA8y0AOw==) repeat 0 0}.debug-grid-16-solid{background:#fff url(data:image/gif;base64,R0lGODdhEAAQAPEAAADw/wDx/xXy/////ywAAAAAEAAQAAACIZyPKckYDQFsb6ZqD85jZ2+BkwiRFKehhqQCQgDHcgwEBQA7) repeat 0 0}@media screen and (min-width:30em){.aspect-ratio-ns{height:0;position:relative}.aspect-ratio--16x9-ns{padding-bottom:56.25%}.aspect-ratio--9x16-ns{padding-bottom:177.77%}.aspect-ratio--4x3-ns{padding-bottom:75%}.aspect-ratio--3x4-ns{padding-bottom:133.33%}.aspect-ratio--6x4-ns{padding-bottom:66.6%}.aspect-ratio--4x6-ns{padding-bottom:150%}.aspect-ratio--8x5-ns{padding-bottom:62.5%}.aspect-ratio--5x8-ns{padding-bottom:160%}.aspect-ratio--7x5-ns{padding-bottom:71.42%}.aspect-ratio--5x7-ns{padding-bottom:140%}.aspect-ratio--1x1-ns{padding-bottom:100%}.aspect-ratio--object-ns{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;z-index:100}.cover-ns{background-size:cover!important}.contain-ns{background-size:contain!important}.bg-center-ns{background-position:50%}.bg-center-ns,.bg-top-ns{background-repeat:no-repeat}.bg-top-ns{background-position:top}.bg-right-ns{background-position:100%}.bg-bottom-ns,.bg-right-ns{background-repeat:no-repeat}.bg-bottom-ns{background-position:bottom}.bg-left-ns{background-repeat:no-repeat;background-position:0}.outline-ns{outline:1px solid}.outline-transparent-ns{outline:1px solid transparent}.outline-0-ns{outline:0}.ba-ns{border-style:solid;border-width:1px}.bt-ns{border-top-style:solid;border-top-width:1px}.br-ns{border-right-style:solid;border-right-width:1px}.bb-ns{border-bottom-style:solid;border-bottom-width:1px}.bl-ns{border-left-style:solid;border-left-width:1px}.bn-ns{border-style:none;border-width:0}.br0-ns{border-radius:0}.br1-ns{border-radius:.125rem}.br2-ns{border-radius:.25rem}.br3-ns{border-radius:.5rem}.br4-ns{border-radius:1rem}.br-100-ns{border-radius:100%}.br-pill-ns{border-radius:9999px}.br--bottom-ns{border-top-left-radius:0;border-top-right-radius:0}.br--top-ns{border-bottom-right-radius:0}.br--right-ns,.br--top-ns{border-bottom-left-radius:0}.br--right-ns{border-top-left-radius:0}.br--left-ns{border-top-right-radius:0;border-bottom-right-radius:0}.b--dotted-ns{border-style:dotted}.b--dashed-ns{border-style:dashed}.b--solid-ns{border-style:solid}.b--none-ns{border-style:none}.bw0-ns{border-width:0}.bw1-ns{border-width:.125rem}.bw2-ns{border-width:.25rem}.bw3-ns{border-width:.5rem}.bw4-ns{border-width:1rem}.bw5-ns{border-width:2rem}.bt-0-ns{border-top-width:0}.br-0-ns{border-right-width:0}.bb-0-ns{border-bottom-width:0}.bl-0-ns{border-left-width:0}.shadow-1-ns{box-shadow:0 0 4px 2px rgba(0,0,0,.2)}.shadow-2-ns{box-shadow:0 0 8px 2px rgba(0,0,0,.2)}.shadow-3-ns{box-shadow:2px 2px 4px 2px rgba(0,0,0,.2)}.shadow-4-ns{box-shadow:2px 2px 8px 0 rgba(0,0,0,.2)}.shadow-5-ns{box-shadow:4px 4px 8px 0 rgba(0,0,0,.2)}.top-0-ns{top:0}.left-0-ns{left:0}.right-0-ns{right:0}.bottom-0-ns{bottom:0}.top-1-ns{top:1rem}.left-1-ns{left:1rem}.right-1-ns{right:1rem}.bottom-1-ns{bottom:1rem}.top-2-ns{top:2rem}.left-2-ns{left:2rem}.right-2-ns{right:2rem}.bottom-2-ns{bottom:2rem}.top--1-ns{top:-1rem}.right--1-ns{right:-1rem}.bottom--1-ns{bottom:-1rem}.left--1-ns{left:-1rem}.top--2-ns{top:-2rem}.right--2-ns{right:-2rem}.bottom--2-ns{bottom:-2rem}.left--2-ns{left:-2rem}.absolute--fill-ns{top:0;right:0;bottom:0;left:0}.cl-ns{clear:left}.cr-ns{clear:right}.cb-ns{clear:both}.cn-ns{clear:none}.dn-ns{display:none}.di-ns{display:inline}.db-ns{display:block}.dib-ns{display:inline-block}.dit-ns{display:inline-table}.dt-ns{display:table}.dtc-ns{display:table-cell}.dt-row-ns{display:table-row}.dt-row-group-ns{display:table-row-group}.dt-column-ns{display:table-column}.dt-column-group-ns{display:table-column-group}.dt--fixed-ns{table-layout:fixed;width:100%}.flex-ns{display:flex}.inline-flex-ns{display:inline-flex}.flex-auto-ns{flex:1 1 auto;min-width:0;min-height:0}.flex-none-ns{flex:none}.flex-column-ns{flex-direction:column}.flex-row-ns{flex-direction:row}.flex-wrap-ns{flex-wrap:wrap}.flex-nowrap-ns{flex-wrap:nowrap}.flex-wrap-reverse-ns{flex-wrap:wrap-reverse}.flex-column-reverse-ns{flex-direction:column-reverse}.flex-row-reverse-ns{flex-direction:row-reverse}.items-start-ns{align-items:flex-start}.items-end-ns{align-items:flex-end}.items-center-ns{align-items:center}.items-baseline-ns{align-items:baseline}.items-stretch-ns{align-items:stretch}.self-start-ns{align-self:flex-start}.self-end-ns{align-self:flex-end}.self-center-ns{align-self:center}.self-baseline-ns{align-self:baseline}.self-stretch-ns{align-self:stretch}.justify-start-ns{justify-content:flex-start}.justify-end-ns{justify-content:flex-end}.justify-center-ns{justify-content:center}.justify-between-ns{justify-content:space-between}.justify-around-ns{justify-content:space-around}.content-start-ns{align-content:flex-start}.content-end-ns{align-content:flex-end}.content-center-ns{align-content:center}.content-between-ns{align-content:space-between}.content-around-ns{align-content:space-around}.content-stretch-ns{align-content:stretch}.order-0-ns{order:0}.order-1-ns{order:1}.order-2-ns{order:2}.order-3-ns{order:3}.order-4-ns{order:4}.order-5-ns{order:5}.order-6-ns{order:6}.order-7-ns{order:7}.order-8-ns{order:8}.order-last-ns{order:99999}.flex-grow-0-ns{flex-grow:0}.flex-grow-1-ns{flex-grow:1}.flex-shrink-0-ns{flex-shrink:0}.flex-shrink-1-ns{flex-shrink:1}.fl-ns{float:left}.fl-ns,.fr-ns{_display:inline}.fr-ns{float:right}.fn-ns{float:none}.i-ns{font-style:italic}.fs-normal-ns{font-style:normal}.normal-ns{font-weight:400}.b-ns{font-weight:700}.fw1-ns{font-weight:100}.fw2-ns{font-weight:200}.fw3-ns{font-weight:300}.fw4-ns{font-weight:400}.fw5-ns{font-weight:500}.fw6-ns{font-weight:600}.fw7-ns{font-weight:700}.fw8-ns{font-weight:800}.fw9-ns{font-weight:900}.h1-ns{height:1rem}.h2-ns{height:2rem}.h3-ns{height:4rem}.h4-ns{height:8rem}.h5-ns{height:16rem}.h-25-ns{height:25%}.h-50-ns{height:50%}.h-75-ns{height:75%}.h-100-ns{height:100%}.min-h-100-ns{min-height:100%}.vh-25-ns{height:25vh}.vh-50-ns{height:50vh}.vh-75-ns{height:75vh}.vh-100-ns{height:100vh}.min-vh-100-ns{min-height:100vh}.h-auto-ns{height:auto}.h-inherit-ns{height:inherit}.tracked-ns{letter-spacing:.1em}.tracked-tight-ns{letter-spacing:-.05em}.tracked-mega-ns{letter-spacing:.25em}.lh-solid-ns{line-height:1}.lh-title-ns{line-height:1.25}.lh-copy-ns{line-height:1.5}.mw-100-ns{max-width:100%}.mw1-ns{max-width:1rem}.mw2-ns{max-width:2rem}.mw3-ns{max-width:4rem}.mw4-ns{max-width:8rem}.mw5-ns{max-width:16rem}.mw6-ns{max-width:32rem}.mw7-ns{max-width:48rem}.mw8-ns{max-width:64rem}.mw9-ns{max-width:96rem}.mw-none-ns{max-width:none}.w1-ns{width:1rem}.w2-ns{width:2rem}.w3-ns{width:4rem}.w4-ns{width:8rem}.w5-ns{width:16rem}.w-10-ns{width:10%}.w-20-ns{width:20%}.w-25-ns{width:25%}.w-30-ns{width:30%}.w-33-ns{width:33%}.w-34-ns{width:34%}.w-40-ns{width:40%}.w-50-ns{width:50%}.w-60-ns{width:60%}.w-70-ns{width:70%}.w-75-ns{width:75%}.w-80-ns{width:80%}.w-90-ns{width:90%}.w-100-ns{width:100%}.w-third-ns{width:33.33333%}.w-two-thirds-ns{width:66.66667%}.w-auto-ns{width:auto}.overflow-visible-ns{overflow:visible}.overflow-hidden-ns{overflow:hidden}.overflow-scroll-ns{overflow:scroll}.overflow-auto-ns{overflow:auto}.overflow-x-visible-ns{overflow-x:visible}.overflow-x-hidden-ns{overflow-x:hidden}.overflow-x-scroll-ns{overflow-x:scroll}.overflow-x-auto-ns{overflow-x:auto}.overflow-y-visible-ns{overflow-y:visible}.overflow-y-hidden-ns{overflow-y:hidden}.overflow-y-scroll-ns{overflow-y:scroll}.overflow-y-auto-ns{overflow-y:auto}.static-ns{position:static}.relative-ns{position:relative}.absolute-ns{position:absolute}.fixed-ns{position:fixed}.rotate-45-ns{-webkit-transform:rotate(45deg);transform:rotate(45deg)}.rotate-90-ns{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.rotate-135-ns{-webkit-transform:rotate(135deg);transform:rotate(135deg)}.rotate-180-ns{-webkit-transform:rotate(180deg);transform:rotate(180deg)}.rotate-225-ns{-webkit-transform:rotate(225deg);transform:rotate(225deg)}.rotate-270-ns{-webkit-transform:rotate(270deg);transform:rotate(270deg)}.rotate-315-ns{-webkit-transform:rotate(315deg);transform:rotate(315deg)}.pa0-ns{padding:0}.pa1-ns{padding:.25rem}.pa2-ns{padding:.5rem}.pa3-ns{padding:1rem}.pa4-ns{padding:2rem}.pa5-ns{padding:4rem}.pa6-ns{padding:8rem}.pa7-ns{padding:16rem}.pl0-ns{padding-left:0}.pl1-ns{padding-left:.25rem}.pl2-ns{padding-left:.5rem}.pl3-ns{padding-left:1rem}.pl4-ns{padding-left:2rem}.pl5-ns{padding-left:4rem}.pl6-ns{padding-left:8rem}.pl7-ns{padding-left:16rem}.pr0-ns{padding-right:0}.pr1-ns{padding-right:.25rem}.pr2-ns{padding-right:.5rem}.pr3-ns{padding-right:1rem}.pr4-ns{padding-right:2rem}.pr5-ns{padding-right:4rem}.pr6-ns{padding-right:8rem}.pr7-ns{padding-right:16rem}.pb0-ns{padding-bottom:0}.pb1-ns{padding-bottom:.25rem}.pb2-ns{padding-bottom:.5rem}.pb3-ns{padding-bottom:1rem}.pb4-ns{padding-bottom:2rem}.pb5-ns{padding-bottom:4rem}.pb6-ns{padding-bottom:8rem}.pb7-ns{padding-bottom:16rem}.pt0-ns{padding-top:0}.pt1-ns{padding-top:.25rem}.pt2-ns{padding-top:.5rem}.pt3-ns{padding-top:1rem}.pt4-ns{padding-top:2rem}.pt5-ns{padding-top:4rem}.pt6-ns{padding-top:8rem}.pt7-ns{padding-top:16rem}.pv0-ns{padding-top:0;padding-bottom:0}.pv1-ns{padding-top:.25rem;padding-bottom:.25rem}.pv2-ns{padding-top:.5rem;padding-bottom:.5rem}.pv3-ns{padding-top:1rem;padding-bottom:1rem}.pv4-ns{padding-top:2rem;padding-bottom:2rem}.pv5-ns{padding-top:4rem;padding-bottom:4rem}.pv6-ns{padding-top:8rem;padding-bottom:8rem}.pv7-ns{padding-top:16rem;padding-bottom:16rem}.ph0-ns{padding-left:0;padding-right:0}.ph1-ns{padding-left:.25rem;padding-right:.25rem}.ph2-ns{padding-left:.5rem;padding-right:.5rem}.ph3-ns{padding-left:1rem;padding-right:1rem}.ph4-ns{padding-left:2rem;padding-right:2rem}.ph5-ns{padding-left:4rem;padding-right:4rem}.ph6-ns{padding-left:8rem;padding-right:8rem}.ph7-ns{padding-left:16rem;padding-right:16rem}.ma0-ns{margin:0}.ma1-ns{margin:.25rem}.ma2-ns{margin:.5rem}.ma3-ns{margin:1rem}.ma4-ns{margin:2rem}.ma5-ns{margin:4rem}.ma6-ns{margin:8rem}.ma7-ns{margin:16rem}.ml0-ns{margin-left:0}.ml1-ns{margin-left:.25rem}.ml2-ns{margin-left:.5rem}.ml3-ns{margin-left:1rem}.ml4-ns{margin-left:2rem}.ml5-ns{margin-left:4rem}.ml6-ns{margin-left:8rem}.ml7-ns{margin-left:16rem}.mr0-ns{margin-right:0}.mr1-ns{margin-right:.25rem}.mr2-ns{margin-right:.5rem}.mr3-ns{margin-right:1rem}.mr4-ns{margin-right:2rem}.mr5-ns{margin-right:4rem}.mr6-ns{margin-right:8rem}.mr7-ns{margin-right:16rem}.mb0-ns{margin-bottom:0}.mb1-ns{margin-bottom:.25rem}.mb2-ns{margin-bottom:.5rem}.mb3-ns{margin-bottom:1rem}.mb4-ns{margin-bottom:2rem}.mb5-ns{margin-bottom:4rem}.mb6-ns{margin-bottom:8rem}.mb7-ns{margin-bottom:16rem}.mt0-ns{margin-top:0}.mt1-ns{margin-top:.25rem}.mt2-ns{margin-top:.5rem}.mt3-ns{margin-top:1rem}.mt4-ns{margin-top:2rem}.mt5-ns{margin-top:4rem}.mt6-ns{margin-top:8rem}.mt7-ns{margin-top:16rem}.mv0-ns{margin-top:0;margin-bottom:0}.mv1-ns{margin-top:.25rem;margin-bottom:.25rem}.mv2-ns{margin-top:.5rem;margin-bottom:.5rem}.mv3-ns{margin-top:1rem;margin-bottom:1rem}.mv4-ns{margin-top:2rem;margin-bottom:2rem}.mv5-ns{margin-top:4rem;margin-bottom:4rem}.mv6-ns{margin-top:8rem;margin-bottom:8rem}.mv7-ns{margin-top:16rem;margin-bottom:16rem}.mh0-ns{margin-left:0;margin-right:0}.mh1-ns{margin-left:.25rem;margin-right:.25rem}.mh2-ns{margin-left:.5rem;margin-right:.5rem}.mh3-ns{margin-left:1rem;margin-right:1rem}.mh4-ns{margin-left:2rem;margin-right:2rem}.mh5-ns{margin-left:4rem;margin-right:4rem}.mh6-ns{margin-left:8rem;margin-right:8rem}.mh7-ns{margin-left:16rem;margin-right:16rem}.na1-ns{margin:-.25rem}.na2-ns{margin:-.5rem}.na3-ns{margin:-1rem}.na4-ns{margin:-2rem}.na5-ns{margin:-4rem}.na6-ns{margin:-8rem}.na7-ns{margin:-16rem}.nl1-ns{margin-left:-.25rem}.nl2-ns{margin-left:-.5rem}.nl3-ns{margin-left:-1rem}.nl4-ns{margin-left:-2rem}.nl5-ns{margin-left:-4rem}.nl6-ns{margin-left:-8rem}.nl7-ns{margin-left:-16rem}.nr1-ns{margin-right:-.25rem}.nr2-ns{margin-right:-.5rem}.nr3-ns{margin-right:-1rem}.nr4-ns{margin-right:-2rem}.nr5-ns{margin-right:-4rem}.nr6-ns{margin-right:-8rem}.nr7-ns{margin-right:-16rem}.nb1-ns{margin-bottom:-.25rem}.nb2-ns{margin-bottom:-.5rem}.nb3-ns{margin-bottom:-1rem}.nb4-ns{margin-bottom:-2rem}.nb5-ns{margin-bottom:-4rem}.nb6-ns{margin-bottom:-8rem}.nb7-ns{margin-bottom:-16rem}.nt1-ns{margin-top:-.25rem}.nt2-ns{margin-top:-.5rem}.nt3-ns{margin-top:-1rem}.nt4-ns{margin-top:-2rem}.nt5-ns{margin-top:-4rem}.nt6-ns{margin-top:-8rem}.nt7-ns{margin-top:-16rem}.strike-ns{text-decoration:line-through}.underline-ns{text-decoration:underline}.no-underline-ns{text-decoration:none}.tl-ns{text-align:left}.tr-ns{text-align:right}.tc-ns{text-align:center}.tj-ns{text-align:justify}.ttc-ns{text-transform:capitalize}.ttl-ns{text-transform:lowercase}.ttu-ns{text-transform:uppercase}.ttn-ns{text-transform:none}.f-6-ns,.f-headline-ns{font-size:6rem}.f-5-ns,.f-subheadline-ns{font-size:5rem}.f1-ns{font-size:3rem}.f2-ns{font-size:2.25rem}.f3-ns{font-size:1.5rem}.f4-ns{font-size:1.25rem}.f5-ns{font-size:1rem}.f6-ns{font-size:.875rem}.f7-ns{font-size:.75rem}.measure-ns{max-width:30em}.measure-wide-ns{max-width:34em}.measure-narrow-ns{max-width:20em}.indent-ns{text-indent:1em;margin-top:0;margin-bottom:0}.small-caps-ns{font-variant:small-caps}.truncate-ns{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.center-ns{margin-left:auto}.center-ns,.mr-auto-ns{margin-right:auto}.ml-auto-ns{margin-left:auto}.clip-ns{position:fixed!important;_position:absolute!important;clip:rect(1px 1px 1px 1px);clip:rect(1px,1px,1px,1px)}.ws-normal-ns{white-space:normal}.nowrap-ns{white-space:nowrap}.pre-ns{white-space:pre}.v-base-ns{vertical-align:baseline}.v-mid-ns{vertical-align:middle}.v-top-ns{vertical-align:top}.v-btm-ns{vertical-align:bottom}}@media screen and (min-width:30em) and (max-width:60em){.aspect-ratio-m{height:0;position:relative}.aspect-ratio--16x9-m{padding-bottom:56.25%}.aspect-ratio--9x16-m{padding-bottom:177.77%}.aspect-ratio--4x3-m{padding-bottom:75%}.aspect-ratio--3x4-m{padding-bottom:133.33%}.aspect-ratio--6x4-m{padding-bottom:66.6%}.aspect-ratio--4x6-m{padding-bottom:150%}.aspect-ratio--8x5-m{padding-bottom:62.5%}.aspect-ratio--5x8-m{padding-bottom:160%}.aspect-ratio--7x5-m{padding-bottom:71.42%}.aspect-ratio--5x7-m{padding-bottom:140%}.aspect-ratio--1x1-m{padding-bottom:100%}.aspect-ratio--object-m{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;z-index:100}.cover-m{background-size:cover!important}.contain-m{background-size:contain!important}.bg-center-m{background-position:50%}.bg-center-m,.bg-top-m{background-repeat:no-repeat}.bg-top-m{background-position:top}.bg-right-m{background-position:100%}.bg-bottom-m,.bg-right-m{background-repeat:no-repeat}.bg-bottom-m{background-position:bottom}.bg-left-m{background-repeat:no-repeat;background-position:0}.outline-m{outline:1px solid}.outline-transparent-m{outline:1px solid transparent}.outline-0-m{outline:0}.ba-m{border-style:solid;border-width:1px}.bt-m{border-top-style:solid;border-top-width:1px}.br-m{border-right-style:solid;border-right-width:1px}.bb-m{border-bottom-style:solid;border-bottom-width:1px}.bl-m{border-left-style:solid;border-left-width:1px}.bn-m{border-style:none;border-width:0}.br0-m{border-radius:0}.br1-m{border-radius:.125rem}.br2-m{border-radius:.25rem}.br3-m{border-radius:.5rem}.br4-m{border-radius:1rem}.br-100-m{border-radius:100%}.br-pill-m{border-radius:9999px}.br--bottom-m{border-top-left-radius:0;border-top-right-radius:0}.br--top-m{border-bottom-right-radius:0}.br--right-m,.br--top-m{border-bottom-left-radius:0}.br--right-m{border-top-left-radius:0}.br--left-m{border-top-right-radius:0;border-bottom-right-radius:0}.b--dotted-m{border-style:dotted}.b--dashed-m{border-style:dashed}.b--solid-m{border-style:solid}.b--none-m{border-style:none}.bw0-m{border-width:0}.bw1-m{border-width:.125rem}.bw2-m{border-width:.25rem}.bw3-m{border-width:.5rem}.bw4-m{border-width:1rem}.bw5-m{border-width:2rem}.bt-0-m{border-top-width:0}.br-0-m{border-right-width:0}.bb-0-m{border-bottom-width:0}.bl-0-m{border-left-width:0}.shadow-1-m{box-shadow:0 0 4px 2px rgba(0,0,0,.2)}.shadow-2-m{box-shadow:0 0 8px 2px rgba(0,0,0,.2)}.shadow-3-m{box-shadow:2px 2px 4px 2px rgba(0,0,0,.2)}.shadow-4-m{box-shadow:2px 2px 8px 0 rgba(0,0,0,.2)}.shadow-5-m{box-shadow:4px 4px 8px 0 rgba(0,0,0,.2)}.top-0-m{top:0}.left-0-m{left:0}.right-0-m{right:0}.bottom-0-m{bottom:0}.top-1-m{top:1rem}.left-1-m{left:1rem}.right-1-m{right:1rem}.bottom-1-m{bottom:1rem}.top-2-m{top:2rem}.left-2-m{left:2rem}.right-2-m{right:2rem}.bottom-2-m{bottom:2rem}.top--1-m{top:-1rem}.right--1-m{right:-1rem}.bottom--1-m{bottom:-1rem}.left--1-m{left:-1rem}.top--2-m{top:-2rem}.right--2-m{right:-2rem}.bottom--2-m{bottom:-2rem}.left--2-m{left:-2rem}.absolute--fill-m{top:0;right:0;bottom:0;left:0}.cl-m{clear:left}.cr-m{clear:right}.cb-m{clear:both}.cn-m{clear:none}.dn-m{display:none}.di-m{display:inline}.db-m{display:block}.dib-m{display:inline-block}.dit-m{display:inline-table}.dt-m{display:table}.dtc-m{display:table-cell}.dt-row-m{display:table-row}.dt-row-group-m{display:table-row-group}.dt-column-m{display:table-column}.dt-column-group-m{display:table-column-group}.dt--fixed-m{table-layout:fixed;width:100%}.flex-m{display:flex}.inline-flex-m{display:inline-flex}.flex-auto-m{flex:1 1 auto;min-width:0;min-height:0}.flex-none-m{flex:none}.flex-column-m{flex-direction:column}.flex-row-m{flex-direction:row}.flex-wrap-m{flex-wrap:wrap}.flex-nowrap-m{flex-wrap:nowrap}.flex-wrap-reverse-m{flex-wrap:wrap-reverse}.flex-column-reverse-m{flex-direction:column-reverse}.flex-row-reverse-m{flex-direction:row-reverse}.items-start-m{align-items:flex-start}.items-end-m{align-items:flex-end}.items-center-m{align-items:center}.items-baseline-m{align-items:baseline}.items-stretch-m{align-items:stretch}.self-start-m{align-self:flex-start}.self-end-m{align-self:flex-end}.self-center-m{align-self:center}.self-baseline-m{align-self:baseline}.self-stretch-m{align-self:stretch}.justify-start-m{justify-content:flex-start}.justify-end-m{justify-content:flex-end}.justify-center-m{justify-content:center}.justify-between-m{justify-content:space-between}.justify-around-m{justify-content:space-around}.content-start-m{align-content:flex-start}.content-end-m{align-content:flex-end}.content-center-m{align-content:center}.content-between-m{align-content:space-between}.content-around-m{align-content:space-around}.content-stretch-m{align-content:stretch}.order-0-m{order:0}.order-1-m{order:1}.order-2-m{order:2}.order-3-m{order:3}.order-4-m{order:4}.order-5-m{order:5}.order-6-m{order:6}.order-7-m{order:7}.order-8-m{order:8}.order-last-m{order:99999}.flex-grow-0-m{flex-grow:0}.flex-grow-1-m{flex-grow:1}.flex-shrink-0-m{flex-shrink:0}.flex-shrink-1-m{flex-shrink:1}.fl-m{float:left}.fl-m,.fr-m{_display:inline}.fr-m{float:right}.fn-m{float:none}.i-m{font-style:italic}.fs-normal-m{font-style:normal}.normal-m{font-weight:400}.b-m{font-weight:700}.fw1-m{font-weight:100}.fw2-m{font-weight:200}.fw3-m{font-weight:300}.fw4-m{font-weight:400}.fw5-m{font-weight:500}.fw6-m{font-weight:600}.fw7-m{font-weight:700}.fw8-m{font-weight:800}.fw9-m{font-weight:900}.h1-m{height:1rem}.h2-m{height:2rem}.h3-m{height:4rem}.h4-m{height:8rem}.h5-m{height:16rem}.h-25-m{height:25%}.h-50-m{height:50%}.h-75-m{height:75%}.h-100-m{height:100%}.min-h-100-m{min-height:100%}.vh-25-m{height:25vh}.vh-50-m{height:50vh}.vh-75-m{height:75vh}.vh-100-m{height:100vh}.min-vh-100-m{min-height:100vh}.h-auto-m{height:auto}.h-inherit-m{height:inherit}.tracked-m{letter-spacing:.1em}.tracked-tight-m{letter-spacing:-.05em}.tracked-mega-m{letter-spacing:.25em}.lh-solid-m{line-height:1}.lh-title-m{line-height:1.25}.lh-copy-m{line-height:1.5}.mw-100-m{max-width:100%}.mw1-m{max-width:1rem}.mw2-m{max-width:2rem}.mw3-m{max-width:4rem}.mw4-m{max-width:8rem}.mw5-m{max-width:16rem}.mw6-m{max-width:32rem}.mw7-m{max-width:48rem}.mw8-m{max-width:64rem}.mw9-m{max-width:96rem}.mw-none-m{max-width:none}.w1-m{width:1rem}.w2-m{width:2rem}.w3-m{width:4rem}.w4-m{width:8rem}.w5-m{width:16rem}.w-10-m{width:10%}.w-20-m{width:20%}.w-25-m{width:25%}.w-30-m{width:30%}.w-33-m{width:33%}.w-34-m{width:34%}.w-40-m{width:40%}.w-50-m{width:50%}.w-60-m{width:60%}.w-70-m{width:70%}.w-75-m{width:75%}.w-80-m{width:80%}.w-90-m{width:90%}.w-100-m{width:100%}.w-third-m{width:33.33333%}.w-two-thirds-m{width:66.66667%}.w-auto-m{width:auto}.overflow-visible-m{overflow:visible}.overflow-hidden-m{overflow:hidden}.overflow-scroll-m{overflow:scroll}.overflow-auto-m{overflow:auto}.overflow-x-visible-m{overflow-x:visible}.overflow-x-hidden-m{overflow-x:hidden}.overflow-x-scroll-m{overflow-x:scroll}.overflow-x-auto-m{overflow-x:auto}.overflow-y-visible-m{overflow-y:visible}.overflow-y-hidden-m{overflow-y:hidden}.overflow-y-scroll-m{overflow-y:scroll}.overflow-y-auto-m{overflow-y:auto}.static-m{position:static}.relative-m{position:relative}.absolute-m{position:absolute}.fixed-m{position:fixed}.rotate-45-m{-webkit-transform:rotate(45deg);transform:rotate(45deg)}.rotate-90-m{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.rotate-135-m{-webkit-transform:rotate(135deg);transform:rotate(135deg)}.rotate-180-m{-webkit-transform:rotate(180deg);transform:rotate(180deg)}.rotate-225-m{-webkit-transform:rotate(225deg);transform:rotate(225deg)}.rotate-270-m{-webkit-transform:rotate(270deg);transform:rotate(270deg)}.rotate-315-m{-webkit-transform:rotate(315deg);transform:rotate(315deg)}.pa0-m{padding:0}.pa1-m{padding:.25rem}.pa2-m{padding:.5rem}.pa3-m{padding:1rem}.pa4-m{padding:2rem}.pa5-m{padding:4rem}.pa6-m{padding:8rem}.pa7-m{padding:16rem}.pl0-m{padding-left:0}.pl1-m{padding-left:.25rem}.pl2-m{padding-left:.5rem}.pl3-m{padding-left:1rem}.pl4-m{padding-left:2rem}.pl5-m{padding-left:4rem}.pl6-m{padding-left:8rem}.pl7-m{padding-left:16rem}.pr0-m{padding-right:0}.pr1-m{padding-right:.25rem}.pr2-m{padding-right:.5rem}.pr3-m{padding-right:1rem}.pr4-m{padding-right:2rem}.pr5-m{padding-right:4rem}.pr6-m{padding-right:8rem}.pr7-m{padding-right:16rem}.pb0-m{padding-bottom:0}.pb1-m{padding-bottom:.25rem}.pb2-m{padding-bottom:.5rem}.pb3-m{padding-bottom:1rem}.pb4-m{padding-bottom:2rem}.pb5-m{padding-bottom:4rem}.pb6-m{padding-bottom:8rem}.pb7-m{padding-bottom:16rem}.pt0-m{padding-top:0}.pt1-m{padding-top:.25rem}.pt2-m{padding-top:.5rem}.pt3-m{padding-top:1rem}.pt4-m{padding-top:2rem}.pt5-m{padding-top:4rem}.pt6-m{padding-top:8rem}.pt7-m{padding-top:16rem}.pv0-m{padding-top:0;padding-bottom:0}.pv1-m{padding-top:.25rem;padding-bottom:.25rem}.pv2-m{padding-top:.5rem;padding-bottom:.5rem}.pv3-m{padding-top:1rem;padding-bottom:1rem}.pv4-m{padding-top:2rem;padding-bottom:2rem}.pv5-m{padding-top:4rem;padding-bottom:4rem}.pv6-m{padding-top:8rem;padding-bottom:8rem}.pv7-m{padding-top:16rem;padding-bottom:16rem}.ph0-m{padding-left:0;padding-right:0}.ph1-m{padding-left:.25rem;padding-right:.25rem}.ph2-m{padding-left:.5rem;padding-right:.5rem}.ph3-m{padding-left:1rem;padding-right:1rem}.ph4-m{padding-left:2rem;padding-right:2rem}.ph5-m{padding-left:4rem;padding-right:4rem}.ph6-m{padding-left:8rem;padding-right:8rem}.ph7-m{padding-left:16rem;padding-right:16rem}.ma0-m{margin:0}.ma1-m{margin:.25rem}.ma2-m{margin:.5rem}.ma3-m{margin:1rem}.ma4-m{margin:2rem}.ma5-m{margin:4rem}.ma6-m{margin:8rem}.ma7-m{margin:16rem}.ml0-m{margin-left:0}.ml1-m{margin-left:.25rem}.ml2-m{margin-left:.5rem}.ml3-m{margin-left:1rem}.ml4-m{margin-left:2rem}.ml5-m{margin-left:4rem}.ml6-m{margin-left:8rem}.ml7-m{margin-left:16rem}.mr0-m{margin-right:0}.mr1-m{margin-right:.25rem}.mr2-m{margin-right:.5rem}.mr3-m{margin-right:1rem}.mr4-m{margin-right:2rem}.mr5-m{margin-right:4rem}.mr6-m{margin-right:8rem}.mr7-m{margin-right:16rem}.mb0-m{margin-bottom:0}.mb1-m{margin-bottom:.25rem}.mb2-m{margin-bottom:.5rem}.mb3-m{margin-bottom:1rem}.mb4-m{margin-bottom:2rem}.mb5-m{margin-bottom:4rem}.mb6-m{margin-bottom:8rem}.mb7-m{margin-bottom:16rem}.mt0-m{margin-top:0}.mt1-m{margin-top:.25rem}.mt2-m{margin-top:.5rem}.mt3-m{margin-top:1rem}.mt4-m{margin-top:2rem}.mt5-m{margin-top:4rem}.mt6-m{margin-top:8rem}.mt7-m{margin-top:16rem}.mv0-m{margin-top:0;margin-bottom:0}.mv1-m{margin-top:.25rem;margin-bottom:.25rem}.mv2-m{margin-top:.5rem;margin-bottom:.5rem}.mv3-m{margin-top:1rem;margin-bottom:1rem}.mv4-m{margin-top:2rem;margin-bottom:2rem}.mv5-m{margin-top:4rem;margin-bottom:4rem}.mv6-m{margin-top:8rem;margin-bottom:8rem}.mv7-m{margin-top:16rem;margin-bottom:16rem}.mh0-m{margin-left:0;margin-right:0}.mh1-m{margin-left:.25rem;margin-right:.25rem}.mh2-m{margin-left:.5rem;margin-right:.5rem}.mh3-m{margin-left:1rem;margin-right:1rem}.mh4-m{margin-left:2rem;margin-right:2rem}.mh5-m{margin-left:4rem;margin-right:4rem}.mh6-m{margin-left:8rem;margin-right:8rem}.mh7-m{margin-left:16rem;margin-right:16rem}.na1-m{margin:-.25rem}.na2-m{margin:-.5rem}.na3-m{margin:-1rem}.na4-m{margin:-2rem}.na5-m{margin:-4rem}.na6-m{margin:-8rem}.na7-m{margin:-16rem}.nl1-m{margin-left:-.25rem}.nl2-m{margin-left:-.5rem}.nl3-m{margin-left:-1rem}.nl4-m{margin-left:-2rem}.nl5-m{margin-left:-4rem}.nl6-m{margin-left:-8rem}.nl7-m{margin-left:-16rem}.nr1-m{margin-right:-.25rem}.nr2-m{margin-right:-.5rem}.nr3-m{margin-right:-1rem}.nr4-m{margin-right:-2rem}.nr5-m{margin-right:-4rem}.nr6-m{margin-right:-8rem}.nr7-m{margin-right:-16rem}.nb1-m{margin-bottom:-.25rem}.nb2-m{margin-bottom:-.5rem}.nb3-m{margin-bottom:-1rem}.nb4-m{margin-bottom:-2rem}.nb5-m{margin-bottom:-4rem}.nb6-m{margin-bottom:-8rem}.nb7-m{margin-bottom:-16rem}.nt1-m{margin-top:-.25rem}.nt2-m{margin-top:-.5rem}.nt3-m{margin-top:-1rem}.nt4-m{margin-top:-2rem}.nt5-m{margin-top:-4rem}.nt6-m{margin-top:-8rem}.nt7-m{margin-top:-16rem}.strike-m{text-decoration:line-through}.underline-m{text-decoration:underline}.no-underline-m{text-decoration:none}.tl-m{text-align:left}.tr-m{text-align:right}.tc-m{text-align:center}.tj-m{text-align:justify}.ttc-m{text-transform:capitalize}.ttl-m{text-transform:lowercase}.ttu-m{text-transform:uppercase}.ttn-m{text-transform:none}.f-6-m,.f-headline-m{font-size:6rem}.f-5-m,.f-subheadline-m{font-size:5rem}.f1-m{font-size:3rem}.f2-m{font-size:2.25rem}.f3-m{font-size:1.5rem}.f4-m{font-size:1.25rem}.f5-m{font-size:1rem}.f6-m{font-size:.875rem}.f7-m{font-size:.75rem}.measure-m{max-width:30em}.measure-wide-m{max-width:34em}.measure-narrow-m{max-width:20em}.indent-m{text-indent:1em;margin-top:0;margin-bottom:0}.small-caps-m{font-variant:small-caps}.truncate-m{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.center-m{margin-left:auto}.center-m,.mr-auto-m{margin-right:auto}.ml-auto-m{margin-left:auto}.clip-m{position:fixed!important;_position:absolute!important;clip:rect(1px 1px 1px 1px);clip:rect(1px,1px,1px,1px)}.ws-normal-m{white-space:normal}.nowrap-m{white-space:nowrap}.pre-m{white-space:pre}.v-base-m{vertical-align:baseline}.v-mid-m{vertical-align:middle}.v-top-m{vertical-align:top}.v-btm-m{vertical-align:bottom}}@media screen and (min-width:60em){.aspect-ratio-l{height:0;position:relative}.aspect-ratio--16x9-l{padding-bottom:56.25%}.aspect-ratio--9x16-l{padding-bottom:177.77%}.aspect-ratio--4x3-l{padding-bottom:75%}.aspect-ratio--3x4-l{padding-bottom:133.33%}.aspect-ratio--6x4-l{padding-bottom:66.6%}.aspect-ratio--4x6-l{padding-bottom:150%}.aspect-ratio--8x5-l{padding-bottom:62.5%}.aspect-ratio--5x8-l{padding-bottom:160%}.aspect-ratio--7x5-l{padding-bottom:71.42%}.aspect-ratio--5x7-l{padding-bottom:140%}.aspect-ratio--1x1-l{padding-bottom:100%}.aspect-ratio--object-l{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;z-index:100}.cover-l{background-size:cover!important}.contain-l{background-size:contain!important}.bg-center-l{background-position:50%}.bg-center-l,.bg-top-l{background-repeat:no-repeat}.bg-top-l{background-position:top}.bg-right-l{background-position:100%}.bg-bottom-l,.bg-right-l{background-repeat:no-repeat}.bg-bottom-l{background-position:bottom}.bg-left-l{background-repeat:no-repeat;background-position:0}.outline-l{outline:1px solid}.outline-transparent-l{outline:1px solid transparent}.outline-0-l{outline:0}.ba-l{border-style:solid;border-width:1px}.bt-l{border-top-style:solid;border-top-width:1px}.br-l{border-right-style:solid;border-right-width:1px}.bb-l{border-bottom-style:solid;border-bottom-width:1px}.bl-l{border-left-style:solid;border-left-width:1px}.bn-l{border-style:none;border-width:0}.br0-l{border-radius:0}.br1-l{border-radius:.125rem}.br2-l{border-radius:.25rem}.br3-l{border-radius:.5rem}.br4-l{border-radius:1rem}.br-100-l{border-radius:100%}.br-pill-l{border-radius:9999px}.br--bottom-l{border-top-left-radius:0;border-top-right-radius:0}.br--top-l{border-bottom-right-radius:0}.br--right-l,.br--top-l{border-bottom-left-radius:0}.br--right-l{border-top-left-radius:0}.br--left-l{border-top-right-radius:0;border-bottom-right-radius:0}.b--dotted-l{border-style:dotted}.b--dashed-l{border-style:dashed}.b--solid-l{border-style:solid}.b--none-l{border-style:none}.bw0-l{border-width:0}.bw1-l{border-width:.125rem}.bw2-l{border-width:.25rem}.bw3-l{border-width:.5rem}.bw4-l{border-width:1rem}.bw5-l{border-width:2rem}.bt-0-l{border-top-width:0}.br-0-l{border-right-width:0}.bb-0-l{border-bottom-width:0}.bl-0-l{border-left-width:0}.shadow-1-l{box-shadow:0 0 4px 2px rgba(0,0,0,.2)}.shadow-2-l{box-shadow:0 0 8px 2px rgba(0,0,0,.2)}.shadow-3-l{box-shadow:2px 2px 4px 2px rgba(0,0,0,.2)}.shadow-4-l{box-shadow:2px 2px 8px 0 rgba(0,0,0,.2)}.shadow-5-l{box-shadow:4px 4px 8px 0 rgba(0,0,0,.2)}.top-0-l{top:0}.left-0-l{left:0}.right-0-l{right:0}.bottom-0-l{bottom:0}.top-1-l{top:1rem}.left-1-l{left:1rem}.right-1-l{right:1rem}.bottom-1-l{bottom:1rem}.top-2-l{top:2rem}.left-2-l{left:2rem}.right-2-l{right:2rem}.bottom-2-l{bottom:2rem}.top--1-l{top:-1rem}.right--1-l{right:-1rem}.bottom--1-l{bottom:-1rem}.left--1-l{left:-1rem}.top--2-l{top:-2rem}.right--2-l{right:-2rem}.bottom--2-l{bottom:-2rem}.left--2-l{left:-2rem}.absolute--fill-l{top:0;right:0;bottom:0;left:0}.cl-l{clear:left}.cr-l{clear:right}.cb-l{clear:both}.cn-l{clear:none}.dn-l{display:none}.di-l{display:inline}.db-l{display:block}.dib-l{display:inline-block}.dit-l{display:inline-table}.dt-l{display:table}.dtc-l{display:table-cell}.dt-row-l{display:table-row}.dt-row-group-l{display:table-row-group}.dt-column-l{display:table-column}.dt-column-group-l{display:table-column-group}.dt--fixed-l{table-layout:fixed;width:100%}.flex-l{display:flex}.inline-flex-l{display:inline-flex}.flex-auto-l{flex:1 1 auto;min-width:0;min-height:0}.flex-none-l{flex:none}.flex-column-l{flex-direction:column}.flex-row-l{flex-direction:row}.flex-wrap-l{flex-wrap:wrap}.flex-nowrap-l{flex-wrap:nowrap}.flex-wrap-reverse-l{flex-wrap:wrap-reverse}.flex-column-reverse-l{flex-direction:column-reverse}.flex-row-reverse-l{flex-direction:row-reverse}.items-start-l{align-items:flex-start}.items-end-l{align-items:flex-end}.items-center-l{align-items:center}.items-baseline-l{align-items:baseline}.items-stretch-l{align-items:stretch}.self-start-l{align-self:flex-start}.self-end-l{align-self:flex-end}.self-center-l{align-self:center}.self-baseline-l{align-self:baseline}.self-stretch-l{align-self:stretch}.justify-start-l{justify-content:flex-start}.justify-end-l{justify-content:flex-end}.justify-center-l{justify-content:center}.justify-between-l{justify-content:space-between}.justify-around-l{justify-content:space-around}.content-start-l{align-content:flex-start}.content-end-l{align-content:flex-end}.content-center-l{align-content:center}.content-between-l{align-content:space-between}.content-around-l{align-content:space-around}.content-stretch-l{align-content:stretch}.order-0-l{order:0}.order-1-l{order:1}.order-2-l{order:2}.order-3-l{order:3}.order-4-l{order:4}.order-5-l{order:5}.order-6-l{order:6}.order-7-l{order:7}.order-8-l{order:8}.order-last-l{order:99999}.flex-grow-0-l{flex-grow:0}.flex-grow-1-l{flex-grow:1}.flex-shrink-0-l{flex-shrink:0}.flex-shrink-1-l{flex-shrink:1}.fl-l{float:left}.fl-l,.fr-l{_display:inline}.fr-l{float:right}.fn-l{float:none}.i-l{font-style:italic}.fs-normal-l{font-style:normal}.normal-l{font-weight:400}.b-l{font-weight:700}.fw1-l{font-weight:100}.fw2-l{font-weight:200}.fw3-l{font-weight:300}.fw4-l{font-weight:400}.fw5-l{font-weight:500}.fw6-l{font-weight:600}.fw7-l{font-weight:700}.fw8-l{font-weight:800}.fw9-l{font-weight:900}.h1-l{height:1rem}.h2-l{height:2rem}.h3-l{height:4rem}.h4-l{height:8rem}.h5-l{height:16rem}.h-25-l{height:25%}.h-50-l{height:50%}.h-75-l{height:75%}.h-100-l{height:100%}.min-h-100-l{min-height:100%}.vh-25-l{height:25vh}.vh-50-l{height:50vh}.vh-75-l{height:75vh}.vh-100-l{height:100vh}.min-vh-100-l{min-height:100vh}.h-auto-l{height:auto}.h-inherit-l{height:inherit}.tracked-l{letter-spacing:.1em}.tracked-tight-l{letter-spacing:-.05em}.tracked-mega-l{letter-spacing:.25em}.lh-solid-l{line-height:1}.lh-title-l{line-height:1.25}.lh-copy-l{line-height:1.5}.mw-100-l{max-width:100%}.mw1-l{max-width:1rem}.mw2-l{max-width:2rem}.mw3-l{max-width:4rem}.mw4-l{max-width:8rem}.mw5-l{max-width:16rem}.mw6-l{max-width:32rem}.mw7-l{max-width:48rem}.mw8-l{max-width:64rem}.mw9-l{max-width:96rem}.mw-none-l{max-width:none}.w1-l{width:1rem}.w2-l{width:2rem}.w3-l{width:4rem}.w4-l{width:8rem}.w5-l{width:16rem}.w-10-l{width:10%}.w-20-l{width:20%}.w-25-l{width:25%}.w-30-l{width:30%}.w-33-l{width:33%}.w-34-l{width:34%}.w-40-l{width:40%}.w-50-l{width:50%}.w-60-l{width:60%}.w-70-l{width:70%}.w-75-l{width:75%}.w-80-l{width:80%}.w-90-l{width:90%}.w-100-l{width:100%}.w-third-l{width:33.33333%}.w-two-thirds-l{width:66.66667%}.w-auto-l{width:auto}.overflow-visible-l{overflow:visible}.overflow-hidden-l{overflow:hidden}.overflow-scroll-l{overflow:scroll}.overflow-auto-l{overflow:auto}.overflow-x-visible-l{overflow-x:visible}.overflow-x-hidden-l{overflow-x:hidden}.overflow-x-scroll-l{overflow-x:scroll}.overflow-x-auto-l{overflow-x:auto}.overflow-y-visible-l{overflow-y:visible}.overflow-y-hidden-l{overflow-y:hidden}.overflow-y-scroll-l{overflow-y:scroll}.overflow-y-auto-l{overflow-y:auto}.static-l{position:static}.relative-l{position:relative}.absolute-l{position:absolute}.fixed-l{position:fixed}.rotate-45-l{-webkit-transform:rotate(45deg);transform:rotate(45deg)}.rotate-90-l{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.rotate-135-l{-webkit-transform:rotate(135deg);transform:rotate(135deg)}.rotate-180-l{-webkit-transform:rotate(180deg);transform:rotate(180deg)}.rotate-225-l{-webkit-transform:rotate(225deg);transform:rotate(225deg)}.rotate-270-l{-webkit-transform:rotate(270deg);transform:rotate(270deg)}.rotate-315-l{-webkit-transform:rotate(315deg);transform:rotate(315deg)}.pa0-l{padding:0}.pa1-l{padding:.25rem}.pa2-l{padding:.5rem}.pa3-l{padding:1rem}.pa4-l{padding:2rem}.pa5-l{padding:4rem}.pa6-l{padding:8rem}.pa7-l{padding:16rem}.pl0-l{padding-left:0}.pl1-l{padding-left:.25rem}.pl2-l{padding-left:.5rem}.pl3-l{padding-left:1rem}.pl4-l{padding-left:2rem}.pl5-l{padding-left:4rem}.pl6-l{padding-left:8rem}.pl7-l{padding-left:16rem}.pr0-l{padding-right:0}.pr1-l{padding-right:.25rem}.pr2-l{padding-right:.5rem}.pr3-l{padding-right:1rem}.pr4-l{padding-right:2rem}.pr5-l{padding-right:4rem}.pr6-l{padding-right:8rem}.pr7-l{padding-right:16rem}.pb0-l{padding-bottom:0}.pb1-l{padding-bottom:.25rem}.pb2-l{padding-bottom:.5rem}.pb3-l{padding-bottom:1rem}.pb4-l{padding-bottom:2rem}.pb5-l{padding-bottom:4rem}.pb6-l{padding-bottom:8rem}.pb7-l{padding-bottom:16rem}.pt0-l{padding-top:0}.pt1-l{padding-top:.25rem}.pt2-l{padding-top:.5rem}.pt3-l{padding-top:1rem}.pt4-l{padding-top:2rem}.pt5-l{padding-top:4rem}.pt6-l{padding-top:8rem}.pt7-l{padding-top:16rem}.pv0-l{padding-top:0;padding-bottom:0}.pv1-l{padding-top:.25rem;padding-bottom:.25rem}.pv2-l{padding-top:.5rem;padding-bottom:.5rem}.pv3-l{padding-top:1rem;padding-bottom:1rem}.pv4-l{padding-top:2rem;padding-bottom:2rem}.pv5-l{padding-top:4rem;padding-bottom:4rem}.pv6-l{padding-top:8rem;padding-bottom:8rem}.pv7-l{padding-top:16rem;padding-bottom:16rem}.ph0-l{padding-left:0;padding-right:0}.ph1-l{padding-left:.25rem;padding-right:.25rem}.ph2-l{padding-left:.5rem;padding-right:.5rem}.ph3-l{padding-left:1rem;padding-right:1rem}.ph4-l{padding-left:2rem;padding-right:2rem}.ph5-l{padding-left:4rem;padding-right:4rem}.ph6-l{padding-left:8rem;padding-right:8rem}.ph7-l{padding-left:16rem;padding-right:16rem}.ma0-l{margin:0}.ma1-l{margin:.25rem}.ma2-l{margin:.5rem}.ma3-l{margin:1rem}.ma4-l{margin:2rem}.ma5-l{margin:4rem}.ma6-l{margin:8rem}.ma7-l{margin:16rem}.ml0-l{margin-left:0}.ml1-l{margin-left:.25rem}.ml2-l{margin-left:.5rem}.ml3-l{margin-left:1rem}.ml4-l{margin-left:2rem}.ml5-l{margin-left:4rem}.ml6-l{margin-left:8rem}.ml7-l{margin-left:16rem}.mr0-l{margin-right:0}.mr1-l{margin-right:.25rem}.mr2-l{margin-right:.5rem}.mr3-l{margin-right:1rem}.mr4-l{margin-right:2rem}.mr5-l{margin-right:4rem}.mr6-l{margin-right:8rem}.mr7-l{margin-right:16rem}.mb0-l{margin-bottom:0}.mb1-l{margin-bottom:.25rem}.mb2-l{margin-bottom:.5rem}.mb3-l{margin-bottom:1rem}.mb4-l{margin-bottom:2rem}.mb5-l{margin-bottom:4rem}.mb6-l{margin-bottom:8rem}.mb7-l{margin-bottom:16rem}.mt0-l{margin-top:0}.mt1-l{margin-top:.25rem}.mt2-l{margin-top:.5rem}.mt3-l{margin-top:1rem}.mt4-l{margin-top:2rem}.mt5-l{margin-top:4rem}.mt6-l{margin-top:8rem}.mt7-l{margin-top:16rem}.mv0-l{margin-top:0;margin-bottom:0}.mv1-l{margin-top:.25rem;margin-bottom:.25rem}.mv2-l{margin-top:.5rem;margin-bottom:.5rem}.mv3-l{margin-top:1rem;margin-bottom:1rem}.mv4-l{margin-top:2rem;margin-bottom:2rem}.mv5-l{margin-top:4rem;margin-bottom:4rem}.mv6-l{margin-top:8rem;margin-bottom:8rem}.mv7-l{margin-top:16rem;margin-bottom:16rem}.mh0-l{margin-left:0;margin-right:0}.mh1-l{margin-left:.25rem;margin-right:.25rem}.mh2-l{margin-left:.5rem;margin-right:.5rem}.mh3-l{margin-left:1rem;margin-right:1rem}.mh4-l{margin-left:2rem;margin-right:2rem}.mh5-l{margin-left:4rem;margin-right:4rem}.mh6-l{margin-left:8rem;margin-right:8rem}.mh7-l{margin-left:16rem;margin-right:16rem}.na1-l{margin:-.25rem}.na2-l{margin:-.5rem}.na3-l{margin:-1rem}.na4-l{margin:-2rem}.na5-l{margin:-4rem}.na6-l{margin:-8rem}.na7-l{margin:-16rem}.nl1-l{margin-left:-.25rem}.nl2-l{margin-left:-.5rem}.nl3-l{margin-left:-1rem}.nl4-l{margin-left:-2rem}.nl5-l{margin-left:-4rem}.nl6-l{margin-left:-8rem}.nl7-l{margin-left:-16rem}.nr1-l{margin-right:-.25rem}.nr2-l{margin-right:-.5rem}.nr3-l{margin-right:-1rem}.nr4-l{margin-right:-2rem}.nr5-l{margin-right:-4rem}.nr6-l{margin-right:-8rem}.nr7-l{margin-right:-16rem}.nb1-l{margin-bottom:-.25rem}.nb2-l{margin-bottom:-.5rem}.nb3-l{margin-bottom:-1rem}.nb4-l{margin-bottom:-2rem}.nb5-l{margin-bottom:-4rem}.nb6-l{margin-bottom:-8rem}.nb7-l{margin-bottom:-16rem}.nt1-l{margin-top:-.25rem}.nt2-l{margin-top:-.5rem}.nt3-l{margin-top:-1rem}.nt4-l{margin-top:-2rem}.nt5-l{margin-top:-4rem}.nt6-l{margin-top:-8rem}.nt7-l{margin-top:-16rem}.strike-l{text-decoration:line-through}.underline-l{text-decoration:underline}.no-underline-l{text-decoration:none}.tl-l{text-align:left}.tr-l{text-align:right}.tc-l{text-align:center}.tj-l{text-align:justify}.ttc-l{text-transform:capitalize}.ttl-l{text-transform:lowercase}.ttu-l{text-transform:uppercase}.ttn-l{text-transform:none}.f-6-l,.f-headline-l{font-size:6rem}.f-5-l,.f-subheadline-l{font-size:5rem}.f1-l{font-size:3rem}.f2-l{font-size:2.25rem}.f3-l{font-size:1.5rem}.f4-l{font-size:1.25rem}.f5-l{font-size:1rem}.f6-l{font-size:.875rem}.f7-l{font-size:.75rem}.measure-l{max-width:30em}.measure-wide-l{max-width:34em}.measure-narrow-l{max-width:20em}.indent-l{text-indent:1em;margin-top:0;margin-bottom:0}.small-caps-l{font-variant:small-caps}.truncate-l{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.center-l{margin-left:auto}.center-l,.mr-auto-l{margin-right:auto}.ml-auto-l{margin-left:auto}.clip-l{position:fixed!important;_position:absolute!important;clip:rect(1px 1px 1px 1px);clip:rect(1px,1px,1px,1px)}.ws-normal-l{white-space:normal}.nowrap-l{white-space:nowrap}.pre-l{white-space:pre}.v-base-l{vertical-align:baseline}.v-mid-l{vertical-align:middle}.v-top-l{vertical-align:top}.v-btm-l{vertical-align:bottom}} 3 | 4 | -------------------------------------------------------------------------------- /lib/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env" 5 | ] 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /lib/.browserslistrc: -------------------------------------------------------------------------------- 1 | # Browsers that we support 2 | 3 | defaults 4 | IE 11 5 | -------------------------------------------------------------------------------- /lib/README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 |

5 | Micromodal.js 6 |

7 | 8 |

9 | 10 | Made with love 11 | 12 | 13 | License 14 | 15 | 16 | Package version 17 | 18 | 19 | Build Status 20 | 21 |

22 | 23 |

24 | Tiny, dependency-free javascript library for creating accessible modal dialogs 25 |

26 | 27 | --- 28 | 29 | 30 | 31 | The aim of this library is to make modal dialogs accessible and easy to include in your project with minimum configuration. It's only ~1.8kb minified and gzipped - A tiny library for big change. 32 | 33 | **[Demo and documentation](https://micromodal.now.sh/)** 34 | 35 |   36 | 37 | ## Features 38 | ✔ Toggles relevant aria attributes on open and close 39 | 40 | ✔ Closes modal on overlay click 41 | 42 | ✔ Closes modal on pressing the `esc` key 43 | 44 | ✔ Traps tab focus within the modal 45 | 46 | ✔ Focuses on the first focusable element within the modal 47 | 48 | ✔ Retains the focused element state after closing the modal 49 | 50 |   51 | 52 | ## Installation 53 | 54 | **via npm** 55 | ```shell 56 | npm install micromodal --save 57 | ``` 58 | 59 | **via yarn** 60 | ```shell 61 | yarn add micromodal 62 | ``` 63 | 64 | **via CDN direct link** 65 | ```html 66 | 67 | 68 | 69 | ``` 70 | 71 | **direct download** 72 | ```shell 73 | curl -o https://unpkg.com/micromodal/dist/micromodal.min.js 74 | ``` 75 | 76 |   77 | 78 | ## IE 11 and below 79 | 80 | Please use this pollyfill suggested [here](https://github.com/ghosh/Micromodal/issues/49#issuecomment-424213347). 81 | 82 |   83 | 84 | ## Changelog 85 | 86 | Find the latest changelog [here](https://github.com/ghosh/micromodal/blob/master/CHANGELOG.md). 87 | 88 |   89 | 90 | ## Contributing 91 | 92 | We are always open and invite developers to contribute to Micromodal. We have kept the guidelines and process dead simple, so you invest more time in making modals accessible to all. 93 | 94 | Micromodal follows the [standardjs](https://standardjs.com/) coding standard and is part of our `package.json` file. It will help us to maintain consistency in the code base. 95 | 96 | #### Development setup 97 | 1. Clone Github repo `$ git clone https://github.com/ghosh/micromodal.git` 98 | 2. Install `yarn` package manager (Read [installation guide](https://yarnpkg.com/en/docs/install#mac-tab)) 99 | 3. Run `yarn install` in the root folder to install all dependencies 100 | 4. Run `yarn dev` to start a dev server. This serves the example directory and live reloads when any files are changed 101 | 5. [Optional] Run `yarn build` to build the files for distribution. This is run automatically as a pre-commit hook as well. 102 | 6. Send us pull request and chill 103 | 104 |   105 | 106 | ## Licensing 107 | This project is licensed under [MIT license](https://opensource.org/licenses/MIT). 108 | 109 |   110 | ## Related 111 | - [Microtip](https://github.com/ghosh/microtip) - Modern, lightweight, accessible css tooltip library. Just 1kb. 112 | 113 |   114 | 115 | ## Contact 116 | You can mention us on Twitter for any questions, suggestions or just send us funny GIF. We ♥️ GIFs. 117 | 118 | #### Tweet some love 119 | [Tweet](https://twitter.com/intent/tweet?url=https%3A%2F%2Fgoo.gl%2FsEgnBZ&text=Make%20your%20modal%20dialogs%20accessible%20to%20all%20using%20Micromodal.js%2C%20a%20tiny%20library%20for%20big%20change.&hashtags=a11y "Tweet about Micromodal") about Micromodal and help us to spread the message about the importance of Web accessibility and Inclusive design. 120 | 121 |   122 | 123 | ## Created and maintained by 124 | 125 | Indrashish Ghosh – [@_ighosh](https://twitter.com/_ighosh) 🇮🇳 126 | 127 | Kalpesh Singh - [@knowkalpesh](https://twitter.com/knowkalpesh) 🇮🇳 128 | 129 | Darpan Kakadia - [@kakadiadarpan](https://twitter.com/kakadiadarpan) 🇩🇪 130 | 131 | Contributors - [list](https://github.com/ghosh/micromodal/graphs/contributors) 🌐 132 | -------------------------------------------------------------------------------- /lib/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "micromodal", 3 | "version": "0.6.1", 4 | "description": "Tiny javascript library for creating accessible modal dialogs", 5 | "main": "dist/micromodal.js", 6 | "cdn": "dist/micromodal.min.js", 7 | "module": "dist/micromodal.es.js", 8 | "files": [ 9 | "/dist" 10 | ], 11 | "jsdelivr": "dist/micromodal.min.js", 12 | "author": "Indrashish Ghosh", 13 | "license": "ISC", 14 | "repository": "https://github.com/ghosh/micromodal", 15 | "bugs": { 16 | "url": "https://github.com/ghosh/micromodal/issues" 17 | }, 18 | "scripts": { 19 | "test": "echo \"Error: no test specified\" && exit 1", 20 | "dev": "rollup -c -w", 21 | "build": "rollup -c", 22 | "deploy": "yarn build && yarn publish", 23 | "sync": "cp -rf ../Readme.md ./" 24 | }, 25 | "keywords": [ 26 | "a11y", 27 | "modal", 28 | "accessible" 29 | ], 30 | "engines": { 31 | "node": ">=10" 32 | }, 33 | "devDependencies": { 34 | "@babel/core": "^7.8.7", 35 | "@babel/preset-env": "^7.9.0", 36 | "@rollup/plugin-babel": "^5.3.0", 37 | "@rollup/plugin-eslint": "^8.0.1", 38 | "@rollup/plugin-json": "^4.1.0", 39 | "browserlist": "^1.0.1", 40 | "eslint": "^8.2.0", 41 | "eslint-config-standard": "^16.0.3", 42 | "eslint-plugin-import": "^2.25.3", 43 | "eslint-plugin-node": "^11.1.0", 44 | "eslint-plugin-promise": "^5.1.1", 45 | "rollup": "^2.0.2", 46 | "rollup-plugin-filesize": "^9.1.1", 47 | "rollup-plugin-terser": "^7.0.2" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /lib/rollup.config.js: -------------------------------------------------------------------------------- 1 | import eslint from '@rollup/plugin-eslint' 2 | import { babel } from '@rollup/plugin-babel' 3 | import json from '@rollup/plugin-json' 4 | import { terser } from 'rollup-plugin-terser' 5 | import filesize from 'rollup-plugin-filesize' 6 | 7 | const pkg = require('./package.json') 8 | 9 | // dev build if watching, prod build if not 10 | const isProduction = !process.env.ROLLUP_WATCH 11 | 12 | export default { 13 | input: 'src/index.js', 14 | output: [ 15 | { 16 | file: pkg.main, 17 | format: 'umd', 18 | name: 'MicroModal' 19 | }, 20 | { 21 | file: pkg.cdn, 22 | format: 'umd', 23 | name: 'MicroModal' 24 | }, 25 | { 26 | file: pkg.module, 27 | format: 'es' 28 | } 29 | ], 30 | plugins: [ 31 | eslint({ exclude: 'package.json' }), 32 | json(), 33 | babel({ exclude: 'node_modules/**', babelHelpers: 'bundled' }), 34 | isProduction && terser(), 35 | isProduction && filesize() 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /lib/src/index.js: -------------------------------------------------------------------------------- 1 | const MicroModal = (() => { 2 | 'use strict' 3 | 4 | const FOCUSABLE_ELEMENTS = [ 5 | 'a[href]', 6 | 'area[href]', 7 | 'input:not([disabled]):not([type="hidden"]):not([aria-hidden])', 8 | 'select:not([disabled]):not([aria-hidden])', 9 | 'textarea:not([disabled]):not([aria-hidden])', 10 | 'button:not([disabled]):not([aria-hidden])', 11 | 'iframe', 12 | 'object', 13 | 'embed', 14 | '[contenteditable]', 15 | '[tabindex]:not([tabindex^="-"])' 16 | ] 17 | 18 | class Modal { 19 | constructor ({ 20 | targetModal, 21 | triggers = [], 22 | onShow = () => { }, 23 | onClose = () => { }, 24 | openTrigger = 'data-micromodal-trigger', 25 | closeTrigger = 'data-micromodal-close', 26 | openClass = 'is-open', 27 | disableScroll = false, 28 | disableFocus = false, 29 | awaitCloseAnimation = false, 30 | awaitOpenAnimation = false, 31 | debugMode = false 32 | }) { 33 | // Save a reference of the modal 34 | this.modal = typeof targetModal === 'string' ? document.getElementById(targetModal) : targetModal 35 | 36 | // Save a reference to the passed config 37 | this.config = { debugMode, disableScroll, openTrigger, closeTrigger, openClass, onShow, onClose, awaitCloseAnimation, awaitOpenAnimation, disableFocus } 38 | 39 | // Register click events only if pre binding eventListeners 40 | if (triggers.length > 0) this.registerTriggers(...triggers) 41 | 42 | // pre bind functions for event listeners 43 | this.onClick = this.onClick.bind(this) 44 | this.onKeydown = this.onKeydown.bind(this) 45 | } 46 | 47 | /** 48 | * Loops through all openTriggers and binds click event 49 | * @param {array} triggers [Array of node elements] 50 | * @return {void} 51 | */ 52 | registerTriggers (...triggers) { 53 | triggers.filter(Boolean).forEach(trigger => { 54 | trigger.addEventListener('click', event => this.showModal(event)) 55 | }) 56 | } 57 | 58 | showModal (event = null) { 59 | this.activeElement = document.activeElement 60 | this.modal.setAttribute('aria-hidden', 'false') 61 | this.modal.classList.add(this.config.openClass) 62 | this.scrollBehaviour('disable') 63 | this.addEventListeners() 64 | 65 | if (this.config.awaitOpenAnimation) { 66 | const handler = () => { 67 | this.modal.removeEventListener('animationend', handler, false) 68 | this.setFocusToFirstNode() 69 | } 70 | this.modal.addEventListener('animationend', handler, false) 71 | } else { 72 | this.setFocusToFirstNode() 73 | } 74 | 75 | this.config.onShow(this.modal, this.activeElement, event) 76 | } 77 | 78 | closeModal (event = null) { 79 | const modal = this.modal 80 | this.modal.setAttribute('aria-hidden', 'true') 81 | this.removeEventListeners() 82 | this.scrollBehaviour('enable') 83 | if (this.activeElement && this.activeElement.focus) { 84 | this.activeElement.focus() 85 | } 86 | this.config.onClose(this.modal, this.activeElement, event) 87 | 88 | if (this.config.awaitCloseAnimation) { 89 | const openClass = this.config.openClass // <- old school ftw 90 | this.modal.addEventListener('animationend', function handler () { 91 | modal.classList.remove(openClass) 92 | modal.removeEventListener('animationend', handler, false) 93 | }, false) 94 | } else { 95 | modal.classList.remove(this.config.openClass) 96 | } 97 | } 98 | 99 | closeModalByIdOrElement (targetModal) { 100 | this.modal = typeof targetModal === 'string' ? document.getElementById(targetModal) : targetModal 101 | if (this.modal) this.closeModal() 102 | } 103 | 104 | scrollBehaviour (toggle) { 105 | if (!this.config.disableScroll) return 106 | const body = document.querySelector('body') 107 | switch (toggle) { 108 | case 'enable': 109 | Object.assign(body.style, { overflow: '' }) 110 | break 111 | case 'disable': 112 | Object.assign(body.style, { overflow: 'hidden' }) 113 | break 114 | default: 115 | } 116 | } 117 | 118 | addEventListeners () { 119 | this.modal.addEventListener('touchstart', this.onClick) 120 | this.modal.addEventListener('click', this.onClick) 121 | document.addEventListener('keydown', this.onKeydown) 122 | } 123 | 124 | removeEventListeners () { 125 | this.modal.removeEventListener('touchstart', this.onClick) 126 | this.modal.removeEventListener('click', this.onClick) 127 | document.removeEventListener('keydown', this.onKeydown) 128 | } 129 | 130 | /** 131 | * Handles all click events from the modal. 132 | * Closes modal if a target matches the closeTrigger attribute. 133 | * @param {*} event Click Event 134 | */ 135 | onClick (event) { 136 | if ( 137 | event.target.hasAttribute(this.config.closeTrigger) || 138 | event.target.parentNode.hasAttribute(this.config.closeTrigger) 139 | ) { 140 | event.preventDefault() 141 | event.stopPropagation() 142 | this.closeModal(event) 143 | } 144 | } 145 | 146 | onKeydown (event) { 147 | if (event.keyCode === 27) this.closeModal(event) // esc 148 | if (event.keyCode === 9) this.retainFocus(event) // tab 149 | } 150 | 151 | getFocusableNodes () { 152 | const nodes = this.modal.querySelectorAll(FOCUSABLE_ELEMENTS) 153 | return Array(...nodes) 154 | } 155 | 156 | /** 157 | * Tries to set focus on a node which is not a close trigger 158 | * if no other nodes exist then focuses on first close trigger 159 | */ 160 | setFocusToFirstNode () { 161 | if (this.config.disableFocus) return 162 | 163 | const focusableNodes = this.getFocusableNodes() 164 | 165 | // no focusable nodes 166 | if (focusableNodes.length === 0) return 167 | 168 | // remove nodes on whose click, the modal closes 169 | // could not think of a better name :( 170 | const nodesWhichAreNotCloseTargets = focusableNodes.filter(node => { 171 | return !node.hasAttribute(this.config.closeTrigger) 172 | }) 173 | 174 | if (nodesWhichAreNotCloseTargets.length > 0) nodesWhichAreNotCloseTargets[0].focus() 175 | if (nodesWhichAreNotCloseTargets.length === 0) focusableNodes[0].focus() 176 | } 177 | 178 | retainFocus (event) { 179 | let focusableNodes = this.getFocusableNodes() 180 | 181 | // no focusable nodes 182 | if (focusableNodes.length === 0) return 183 | 184 | /** 185 | * Filters nodes which are hidden to prevent 186 | * focus leak outside modal 187 | */ 188 | focusableNodes = focusableNodes.filter(node => { 189 | return (node.offsetParent !== null) 190 | }) 191 | 192 | // if disableFocus is true 193 | if (!this.modal.contains(document.activeElement)) { 194 | focusableNodes[0].focus() 195 | } else { 196 | const focusedItemIndex = focusableNodes.indexOf(document.activeElement) 197 | 198 | if (event.shiftKey && focusedItemIndex === 0) { 199 | focusableNodes[focusableNodes.length - 1].focus() 200 | event.preventDefault() 201 | } 202 | 203 | if (!event.shiftKey && focusableNodes.length > 0 && focusedItemIndex === focusableNodes.length - 1) { 204 | focusableNodes[0].focus() 205 | event.preventDefault() 206 | } 207 | } 208 | } 209 | } 210 | 211 | /** 212 | * Modal prototype ends. 213 | * Here on code is responsible for detecting and 214 | * auto binding event handlers on modal triggers 215 | */ 216 | 217 | // Keep a reference to the opened modal 218 | let activeModal = null 219 | 220 | /** 221 | * Generates an associative array of modals and it's 222 | * respective triggers 223 | * @param {array} triggers An array of all triggers 224 | * @param {string} triggerAttr The data-attribute which triggers the module 225 | * @return {array} 226 | */ 227 | const generateTriggerMap = (triggers, triggerAttr) => { 228 | const triggerMap = [] 229 | 230 | triggers.forEach(trigger => { 231 | const targetModal = trigger.attributes[triggerAttr].value 232 | if (triggerMap[targetModal] === undefined) triggerMap[targetModal] = [] 233 | triggerMap[targetModal].push(trigger) 234 | }) 235 | 236 | return triggerMap 237 | } 238 | 239 | /** 240 | * Validates whether a modal of the given id exists 241 | * in the DOM 242 | * @param {string|object} modal the html ID of the modal, or the modal element itself 243 | * @return {boolean} 244 | */ 245 | const validateModalPresence = modal => { 246 | if (typeof id === 'string' ? !document.getElementById(modal) : !modal) { 247 | console.warn(`MicroModal: \u2757Seems like you have missed %c'${ modal }'`, 'background-color: #f8f9fa;color: #50596c;font-weight: bold;', 'ID somewhere in your code. Refer example below to resolve it.') 248 | console.warn('%cExample:', 'background-color: #f8f9fa;color: #50596c;font-weight: bold;', ``) 249 | return false 250 | } 251 | } 252 | 253 | /** 254 | * Validates if there are modal triggers present 255 | * in the DOM 256 | * @param {array} triggers An array of data-triggers 257 | * @return {boolean} 258 | */ 259 | const validateTriggerPresence = triggers => { 260 | if (triggers.length <= 0) { 261 | console.warn('MicroModal: \u2757Please specify at least one %c\'micromodal-trigger\'', 'background-color: #f8f9fa;color: #50596c;font-weight: bold;', 'data attribute.') 262 | console.warn('%cExample:', 'background-color: #f8f9fa;color: #50596c;font-weight: bold;', '') 263 | return false 264 | } 265 | } 266 | 267 | /** 268 | * Checks if triggers and their corresponding modals 269 | * are present in the DOM 270 | * @param {array} triggers Array of DOM nodes which have data-triggers 271 | * @param {array} triggerMap Associative array of modals and their triggers 272 | * @return {boolean} 273 | */ 274 | const validateArgs = (triggers, triggerMap) => { 275 | validateTriggerPresence(triggers) 276 | if (!triggerMap) return true 277 | for (const id in triggerMap) validateModalPresence(id) 278 | return true 279 | } 280 | 281 | /** 282 | * Binds click handlers to all modal triggers 283 | * @param {object} config [description] 284 | * @return void 285 | */ 286 | const init = config => { 287 | // Create an config object with default openTrigger 288 | const options = Object.assign({}, { openTrigger: 'data-micromodal-trigger' }, config) 289 | 290 | // Collects all the nodes with the trigger 291 | const triggers = [...document.querySelectorAll(`[${ options.openTrigger }]`)] 292 | 293 | // Makes a mappings of modals with their trigger nodes 294 | const triggerMap = generateTriggerMap(triggers, options.openTrigger) 295 | 296 | // Checks if modals and triggers exist in dom 297 | if (options.debugMode === true && validateArgs(triggers, triggerMap) === false) return 298 | 299 | // For every target modal creates a new instance 300 | for (const key in triggerMap) { 301 | const value = triggerMap[key] 302 | options.targetModal = key 303 | options.triggers = [...value] 304 | activeModal = new Modal(options) // eslint-disable-line no-new 305 | } 306 | } 307 | 308 | /** 309 | * Shows a particular modal 310 | * @param {string|object} targetModal [The id of the modal to display] 311 | * @param {object} config [The configuration object to pass] 312 | * @return {void} 313 | */ 314 | const show = (targetModal, config) => { 315 | const options = config || {} 316 | options.targetModal = targetModal 317 | 318 | // Checks if modals and triggers exist in dom 319 | if (options.debugMode === true && validateModalPresence(targetModal) === false) return 320 | 321 | // clear events in case previous modal wasn't closed 322 | if (activeModal) activeModal.removeEventListeners() 323 | 324 | // stores reference to active modal 325 | activeModal = new Modal(options) // eslint-disable-line no-new 326 | activeModal.showModal() 327 | } 328 | 329 | /** 330 | * Closes the active modal 331 | * @param {string|object} targetModal The id of the modal to close, or the modal element itself 332 | * @return {void} 333 | */ 334 | const close = targetModal => { 335 | targetModal ? activeModal.closeModalByIdOrElement(targetModal) : activeModal.closeModal() 336 | } 337 | 338 | return { init, show, close } 339 | })() 340 | 341 | export default MicroModal 342 | 343 | if (typeof window !== 'undefined') { 344 | window.MicroModal = MicroModal 345 | } 346 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@micromodal/repo", 3 | "version": "1.0.1", 4 | "description": "", 5 | "private": true, 6 | "workspaces": [ 7 | "lib", 8 | "docs", 9 | "tests" 10 | ], 11 | "main": "index.js", 12 | "scripts": { 13 | "dev": "concurrently \"yarn lib:dev\" \"yarn docs:dev\"", 14 | "build": "yarn lib:build && yarn docs:build", 15 | "docs:dev": "yarn workspace @micromodal/docs dev", 16 | "docs:build": "yarn workspace @micromodal/docs build", 17 | "lib:dev": "yarn workspace micromodal dev", 18 | "lib:build": "yarn workspace micromodal build", 19 | "test:serve": "yarn workspace @micromodal/tests start", 20 | "test:gui": "yarn workspace @micromodal/tests cypress:open", 21 | "test:cli": "yarn workspace @micromodal/tests cypress:cli", 22 | "deploy:npm": "yarn workspace micromodal deploy", 23 | "deploy:docs": "yarn workspace @micromodal/docs deploy" 24 | }, 25 | "repository": { 26 | "type": "git", 27 | "url": "git+https://github.com/ghosh/micromodal.git" 28 | }, 29 | "author": "", 30 | "license": "ISC", 31 | "bugs": { 32 | "url": "https://github.com/ghosh/micromodal/issues" 33 | }, 34 | "homepage": "https://github.com/ghosh/micromodal#readme", 35 | "dependencies": { 36 | "concurrently": "^6.0.2", 37 | "cypress": "^9.0.0", 38 | "eslint": "8.2.0" 39 | }, 40 | "engines": { 41 | "node": ">=10" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /tests/assets/modal.css: -------------------------------------------------------------------------------- 1 | /**************************\ 2 | Basic Modal Styles 3 | \**************************/ 4 | 5 | #modal-1 { 6 | display: none; 7 | } 8 | 9 | #modal-1.open { 10 | display: block; 11 | } 12 | 13 | .modal { 14 | font-family: -apple-system,BlinkMacSystemFont,avenir next,avenir,helvetica neue,helvetica,ubuntu,roboto,noto,segoe ui,arial,sans-serif; 15 | } 16 | 17 | .modal__overlay { 18 | position: fixed; 19 | top: 0; 20 | left: 0; 21 | right: 0; 22 | bottom: 0; 23 | background: rgba(0,0,0,0.6); 24 | display: flex; 25 | justify-content: center; 26 | align-items: center; 27 | } 28 | 29 | .modal__container { 30 | background-color: #fff; 31 | padding: 30px; 32 | max-width: 500px; 33 | max-height: 100vh; 34 | border-radius: 4px; 35 | overflow-y: auto; 36 | box-sizing: border-box; 37 | } 38 | 39 | .modal__header { 40 | display: flex; 41 | justify-content: space-between; 42 | align-items: center; 43 | } 44 | 45 | .modal__title { 46 | margin-top: 0; 47 | margin-bottom: 0; 48 | font-weight: 600; 49 | font-size: 1.25rem; 50 | line-height: 1.25; 51 | color: #00449e; 52 | box-sizing: border-box; 53 | } 54 | 55 | .modal__close { 56 | background: transparent; 57 | border: 0; 58 | } 59 | 60 | .modal__header .modal__close:before { content: "\2715"; } 61 | 62 | .modal__content { 63 | margin-top: 2rem; 64 | margin-bottom: 2rem; 65 | line-height: 1.5; 66 | color: rgba(0,0,0,.8); 67 | } 68 | 69 | .modal__btn { 70 | font-size: .875rem; 71 | padding-left: 1rem; 72 | padding-right: 1rem; 73 | padding-top: .5rem; 74 | padding-bottom: .5rem; 75 | background-color: #e6e6e6; 76 | color: rgba(0,0,0,.8); 77 | border-radius: .25rem; 78 | border-style: none; 79 | border-width: 0; 80 | cursor: pointer; 81 | -webkit-appearance: button; 82 | text-transform: none; 83 | overflow: visible; 84 | line-height: 1.15; 85 | margin: 0; 86 | will-change: transform; 87 | -moz-osx-font-smoothing: grayscale; 88 | -webkit-backface-visibility: hidden; 89 | backface-visibility: hidden; 90 | -webkit-transform: translateZ(0); 91 | transform: translateZ(0); 92 | transition: -webkit-transform .25s ease-out; 93 | transition: transform .25s ease-out; 94 | transition: transform .25s ease-out,-webkit-transform .25s ease-out; 95 | } 96 | 97 | .modal__btn:focus, .modal__btn:hover { 98 | -webkit-transform: scale(1.05); 99 | transform: scale(1.05); 100 | } 101 | 102 | .modal__btn-primary { 103 | background-color: #00449e; 104 | color: #fff; 105 | } 106 | 107 | 108 | 109 | /**************************\ 110 | Demo Animation Style 111 | \**************************/ 112 | @keyframes mmfadeIn { 113 | from { opacity: 0; } 114 | to { opacity: 1; } 115 | } 116 | 117 | @keyframes mmfadeOut { 118 | from { opacity: 1; } 119 | to { opacity: 0; } 120 | } 121 | 122 | @keyframes mmslideIn { 123 | from { transform: translateY(15%); } 124 | to { transform: translateY(0); } 125 | } 126 | 127 | @keyframes mmslideOut { 128 | from { transform: translateY(0); } 129 | to { transform: translateY(-10%); } 130 | } 131 | 132 | .micromodal-slide { 133 | display: none; 134 | } 135 | 136 | .micromodal-slide.open { 137 | display: block; 138 | } 139 | 140 | .micromodal-slide[aria-hidden="false"] .modal__overlay { 141 | animation: mmfadeIn .3s cubic-bezier(0.0, 0.0, 0.2, 1); 142 | } 143 | 144 | .micromodal-slide[aria-hidden="false"] .modal__container { 145 | animation: mmslideIn .3s cubic-bezier(0, 0, .2, 1); 146 | } 147 | 148 | .micromodal-slide[aria-hidden="true"] .modal__overlay { 149 | animation: mmfadeOut .3s cubic-bezier(0.0, 0.0, 0.2, 1); 150 | } 151 | 152 | .micromodal-slide[aria-hidden="true"] .modal__container { 153 | animation: mmslideOut .3s cubic-bezier(0, 0, .2, 1); 154 | } 155 | 156 | .micromodal-slide .modal__container, 157 | .micromodal-slide .modal__overlay { 158 | will-change: transform; 159 | } 160 | -------------------------------------------------------------------------------- /tests/assets/modal.js: -------------------------------------------------------------------------------- 1 | import MicroModal from '../../lib/dist/micromodal' 2 | 3 | console.log(MicroModal) 4 | console.log('Micromodal imported!') 5 | -------------------------------------------------------------------------------- /tests/assets/test.css: -------------------------------------------------------------------------------- 1 | html { 2 | box-sizing: border-box; 3 | height: 100vh; 4 | width: 100vw; 5 | } 6 | 7 | body { 8 | font: caption; 9 | box-sizing: border-box; 10 | font-size: 16px; 11 | margin: 0; 12 | padding: 0; 13 | height: 100vh; 14 | width: 100vw; 15 | display: flex; 16 | justify-content: center; 17 | align-items: center; 18 | } 19 | 20 | .wrapper { 21 | background-color: #e8fdf5; 22 | height: 12rem; 23 | width: 20rem; 24 | border-radius: 4px; 25 | display: flex; 26 | justify-content: center; 27 | align-items: center; 28 | text-align: center; 29 | } 30 | 31 | .button { 32 | border: 0; 33 | color: white; 34 | padding: 1rem 2rem; 35 | background-color: rgb(19, 119, 82); 36 | font-size: .875rem; 37 | text-decoration: none; 38 | display: inline-block; 39 | border-radius: 4px; 40 | transition: transform .25s ease-out,-webkit-transform .25s ease-out; 41 | } 42 | 43 | .button:hover { 44 | cursor: pointer; 45 | transform: scale(1.05); 46 | } 47 | -------------------------------------------------------------------------------- /tests/cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "baseUrl": "http://localhost:1234", 3 | "fixturesFolder": false, 4 | "integrationFolder" : "./specs", 5 | "video": false, 6 | "screenshotsFolder": "./screenshots", 7 | "viewportWidth": 980, 8 | "viewportHeight": 800, 9 | "reporter": "Dot" 10 | } 11 | -------------------------------------------------------------------------------- /tests/cypress/plugins/index.js: -------------------------------------------------------------------------------- 1 | /// 2 | // *********************************************************** 3 | // This example plugins/index.js can be used to load plugins 4 | // 5 | // You can change the location of this file or turn off loading 6 | // the plugins file with the 'pluginsFile' configuration option. 7 | // 8 | // You can read more here: 9 | // https://on.cypress.io/plugins-guide 10 | // *********************************************************** 11 | 12 | // This function is called when a project is opened or re-opened (e.g. due to 13 | // the project's config changing) 14 | 15 | /** 16 | * @type {Cypress.PluginConfig} 17 | */ 18 | module.exports = (on, config) => { 19 | // `on` is used to hook into various events Cypress emits 20 | // `config` is the resolved Cypress config 21 | } 22 | -------------------------------------------------------------------------------- /tests/cypress/support/commands.js: -------------------------------------------------------------------------------- 1 | // *********************************************** 2 | // This example commands.js shows you how to 3 | // create various custom commands and overwrite 4 | // existing commands. 5 | // 6 | // For more comprehensive examples of custom 7 | // commands please read more here: 8 | // https://on.cypress.io/custom-commands 9 | // *********************************************** 10 | // 11 | // 12 | // -- This is a parent command -- 13 | // Cypress.Commands.add("login", (email, password) => { ... }) 14 | // 15 | // 16 | // -- This is a child command -- 17 | // Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) 18 | // 19 | // 20 | // -- This is a dual command -- 21 | // Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) 22 | // 23 | // 24 | // -- This will overwrite an existing command -- 25 | // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) 26 | -------------------------------------------------------------------------------- /tests/cypress/support/index.js: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/index.js is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // Import commands.js using ES2015 syntax: 17 | import './commands' 18 | 19 | // Alternatively you can use CommonJS syntax: 20 | // require('./commands') 21 | -------------------------------------------------------------------------------- /tests/examples/basic.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Basic | Tests 11 | 12 | 13 | 14 | 15 |
16 |

Basic tests

17 | 18 |
19 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 53 | 54 |
55 | 56 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /tests/examples/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Document 9 | 10 | 11 | 12 | All tests file 13 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /tests/examples/programmatic.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | programmatic | Tests 11 | 12 | 13 | 14 | 15 |
16 |

Programmatic tests

17 | 18 |
19 | 22 |
23 | 24 |
25 | 28 |
29 | 30 | 31 | 32 | 33 | 34 | 62 | 63 |
64 | 65 | 91 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /tests/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@micromodal/tests", 3 | "version": "0.1.0", 4 | "description": "Tests for micromodal", 5 | "main": "index.js", 6 | "private": true, 7 | "workspaces": [ 8 | "lib", 9 | "docs", 10 | "tests" 11 | ], 12 | "scripts": { 13 | "start": "parcel examples/*.html", 14 | "cypress:open": "cypress open", 15 | "cypress:cli": "cypress run" 16 | }, 17 | "author": "Indrashish Ghosh", 18 | "license": "MIT", 19 | "devDependencies": { 20 | "browserlist": "^1.0.1", 21 | "cypress": "^9.0.0", 22 | "express": "^4.17.1", 23 | "parcel": "^2.0.1" 24 | }, 25 | "dependencies": {} 26 | } 27 | -------------------------------------------------------------------------------- /tests/specs/basic.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | 3 | afterEach(function () { 4 | if (this.currentTest.state === 'failed') { 5 | Cypress.runner.stop() 6 | } 7 | }); 8 | 9 | describe('Basic Modal', function () { 10 | 11 | const openModal = () => { 12 | cy.get('#trigger').click() 13 | } 14 | 15 | const closeModal = () => { 16 | cy.get('.modal__close').click() 17 | } 18 | 19 | it('should sucessfully load', () => { 20 | cy.visit('/basic.html') 21 | }) 22 | 23 | it('should see toggle button', () => { 24 | cy.get('#trigger') 25 | }) 26 | 27 | it('should not see the modal by default', () => { 28 | cy.get('#modal-1').and('not.be.visible') 29 | cy.get('#modal-1 .modal__overlay').and('not.be.visible') 30 | }) 31 | 32 | /** 33 | * Checking overlay because the height of 34 | * .modal is zero and cypress treats that 35 | * as hidden 36 | */ 37 | it('should open modal on target click', () => { 38 | openModal() 39 | cy.get('#modal-1 .modal__overlay').and('be.visible') 40 | closeModal() 41 | }) 42 | 43 | it('should close modal on close button click', () => { 44 | openModal() 45 | cy.get('.modal__close').click() 46 | cy.get('.modal__close').and('not.be.visible') 47 | // modal closed here 48 | }) 49 | 50 | it('should close modal on overlay click', () => { 51 | openModal() 52 | cy.get('.modal__overlay').click('top') 53 | cy.get('.modal__overlay').and('not.be.visible') 54 | // modal closed here 55 | }) 56 | 57 | 58 | it('should close modal on escape button press', () => { 59 | openModal() 60 | cy.get('body').type('{esc}') 61 | cy.get('#modal-1 .modal__overlay').and('not.be.visible') 62 | // modal closed here 63 | }) 64 | 65 | 66 | it('should toggle aria-hidden class', () => { 67 | cy.get('#modal-1').should('have.attr', 'aria-hidden', 'true') 68 | openModal() 69 | cy.get('#modal-1').should('have.attr', 'aria-hidden', 'false') 70 | closeModal() 71 | cy.get('#modal-1').should('have.attr', 'aria-hidden', 'true') 72 | }) 73 | 74 | 75 | 76 | it('should fire onShow method on modal open', () => { 77 | openModal() 78 | cy.get('body').should('have.class', 'howdy') 79 | closeModal() 80 | }) 81 | 82 | 83 | it('should fire onClose method on modal close', () => { 84 | openModal() 85 | closeModal() 86 | cy.get('body').should('not.have.class', 'howdy') 87 | }) 88 | 89 | 90 | it('should work with custom open class', () => { 91 | openModal() 92 | cy.get('#modal-1').should('have.class', 'open') 93 | closeModal() 94 | cy.get('#modal-1').should('not.have.class', 'open') 95 | }) 96 | 97 | }) 98 | -------------------------------------------------------------------------------- /tests/specs/programmatic.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | 3 | describe('Programmatic toggling of Modal', function () { 4 | 5 | const openModal = () => { 6 | cy.get('#open-trigger').click() 7 | } 8 | 9 | const openModalViaElementReference = () => { 10 | cy.get('#open-trigger-2').click() 11 | } 12 | 13 | const closeModal = () => { 14 | cy.get('#close-trigger').click() 15 | } 16 | 17 | const closeModalViaElementReference = () => { 18 | cy.get('#close-trigger-2').click() 19 | } 20 | 21 | it('should sucessfully load', () => { 22 | cy.visit('/programmatic.html') 23 | }) 24 | 25 | it('should see toggle button', () => { 26 | cy.get('#open-trigger') 27 | }) 28 | 29 | it('should not see the modal by default', () => { 30 | cy.get('#modal-1').and('not.be.visible') 31 | cy.get('#modal-1 .modal__overlay').and('not.be.visible') 32 | }) 33 | 34 | /** 35 | * Checking overlay because the height of 36 | * .modal is zero and cypress treats that 37 | * as hidden 38 | */ 39 | it('should open modal programmaticaly', () => { 40 | openModal() 41 | cy.get('#modal-1 .modal__overlay').and('be.visible') 42 | closeModal() 43 | }) 44 | 45 | it('should open modal programmaticaly', () => { 46 | openModal() 47 | closeModal() 48 | cy.get('#modal-1 .modal__overlay').and('not.be.visible') 49 | }) 50 | 51 | it('should close modal on close button click', () => { 52 | openModal() 53 | cy.get('.modal__close').click() 54 | cy.get('.modal__close').and('not.be.visible') 55 | }) 56 | 57 | it('should close modal on overlay click', () => { 58 | openModal() 59 | cy.get('.modal__overlay').click('top') 60 | cy.get('.modal__overlay').and('not.be.visible') 61 | // modal closed here 62 | }) 63 | 64 | 65 | it('should close modal on escape button press', () => { 66 | openModal() 67 | cy.get('body').type('{esc}') 68 | cy.get('#modal-1 .modal__overlay').and('not.be.visible') 69 | // modal closed here 70 | }) 71 | 72 | 73 | it('should toggle aria-hidden class', () => { 74 | cy.get('#modal-1').should('have.attr', 'aria-hidden', 'true') 75 | openModal() 76 | cy.get('#modal-1').should('have.attr', 'aria-hidden', 'false') 77 | closeModal() 78 | cy.get('#modal-1').should('have.attr', 'aria-hidden', 'true') 79 | }) 80 | 81 | 82 | it('should fire onShow method on modal open', () => { 83 | openModal() 84 | cy.get('body').should('have.class', 'howdy') 85 | closeModal() 86 | }) 87 | 88 | 89 | it('should fire onClose method on modal close', () => { 90 | openModal() 91 | closeModal() 92 | cy.get('body').should('not.have.class', 'howdy') 93 | }) 94 | 95 | it('should work with custom open class', () => { 96 | openModal() 97 | cy.get('#modal-1').should('have.class', 'open') 98 | closeModal() 99 | cy.get('#modal-1').should('not.have.class', 'open') 100 | }) 101 | 102 | it('should open modal via element reference', () => { 103 | openModalViaElementReference() 104 | cy.get('#modal-1 .modal__overlay').and('be.visible') 105 | closeModal() 106 | }) 107 | 108 | it('should close modal via element reference', () => { 109 | openModalViaElementReference() 110 | cy.get('#modal-1 .modal__overlay').and('be.visible') 111 | closeModalViaElementReference() 112 | cy.get('#modal-1 .modal__overlay').and('not.be.visible') 113 | }) 114 | 115 | }) 116 | --------------------------------------------------------------------------------