diff --git a/_layouts/newinternet.html b/_layouts/newinternet.html
deleted file mode 100644
index 3847871c9b..0000000000
--- a/_layouts/newinternet.html
+++ /dev/null
@@ -1,70 +0,0 @@
----
-layout: default
----
-
-
-
-
-
-
-
-
-
-
-
- {{ page.title | escape }}
-
- {% if page.subtitle %}{{ page.subtitle }}
{% endif %}
-
-
- {% include post-meta.html %}
-
-
-
- {{ content }}
- {% include share.html %}
-
-
-
-
- {% include paginate-doc.html %}
-
- {% include related-newinternet.html %}
-
- {% if site.disqus.shortname %} {% include disqus_comments.html %} {% endif %}
-
-
-
-
-
-
-
-
diff --git a/_layouts/page.html b/_layouts/page.html
deleted file mode 100644
index 32771b2882..0000000000
--- a/_layouts/page.html
+++ /dev/null
@@ -1,19 +0,0 @@
----
-layout: default
----
-
-
-
-
-
-
- {{ page.title | escape }}
-
-
- {{ content }}
-
-
-
-
-
-
diff --git a/_layouts/post.html b/_layouts/post.html
deleted file mode 100644
index 7c0624d0db..0000000000
--- a/_layouts/post.html
+++ /dev/null
@@ -1,36 +0,0 @@
----
-layout: default
----
-
-
-
-
-
- {{ page.title | escape }}
-
-
- {% include post-meta.html %}
-
-
-
- {{ content }}
- {% include share.html %}
-
-
-
-
- {% include paginate-post.html %}
-
- {% if site.disqus.shortname %} {% include disqus_comments.html %} {% endif %}
-
-
-
-
-
-
diff --git a/_posts/2017-05-25-post63.md b/_posts/2017-05-25-post63.md
deleted file mode 100644
index 85eda15dc1..0000000000
--- a/_posts/2017-05-25-post63.md
+++ /dev/null
@@ -1,51 +0,0 @@
----
-layout: post
-title: Example Post
-author: John Black
----
-
-## Site tags
-
-
- {% if site.tags contains page.featured.tag %}
- **There is at least one**
- {% endif %}
-
-
-{{ site.post_assets | absolute_url }}
-
-{{ page.url }}
-
-Musce libero nunc, dignissim quis turpis quis, semper vehicula dolor. Suspendisse tincidunt consequat quam, ac posuere leo dapibus id. Cras fringilla convallis elit, at eleifend mi interam.
-
-Nulla non sollicitudin. Morbi sit amet laoreet ipsum, vel pretium mi. Morbi varius, tellus in accumsan blandit, elit ligula eleifend velit, luctus mattis ante nulla condimentum nulla. Etiam vestibulum risus vel arcu elementum eleifend. Cras at dolor eget urna varius faucibus tempus in elit.
-
-## Image Lightbox Example
-Nunc porta malesuada porta. Etiam tristique vestibulum dolor at ultricies. Proin hendrerit sapien sed erat fermentum, at commodo velit consectetur.
-
-{% include image.html img="image1.png" style="wide" lightbox="true" alt="Alt for image" caption="Image in lightbox" %}
-
-Etiam vestibulum risus vel arcu elementum eleifend. Cras at dolor eget urna varius faucibus tempus in elit. Cras a dui imperdiet, tempus metus quis, pharetra turpis. Phasellus at massa sit amet ante semper fermentum sed eget lectus. Quisque id dictum magna, et dapibus turpis.
-
-## Example Of Code Block
-In accumsan lacus ac neque maximus dictum. Phasellus eleifend leo id mattis bibendum. Curabitur et purus turpis. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;
-
-```html
-
-
-
-
-
-
-
-
-```
-
-## Text and Quote
-Cras at dolor eget urna varius faucibus tempus in elit. Cras a dui imperdiet, tempus metus quis, pharetra turpis. Phasellus at massa sit amet ante semper fermentum sed eget lectus. Quisque id dictum magna turpis.
-
-> Etiam vestibulum risus vel arcu elementum eleifend. Cras at dolor eget urna varius faucibus tempus in elit. Cras a dui imperdiet
-
-In accumsan lacus ac neque maximus dictum. Phasellus eleifend leo id mattis bibendum. Curabitur et purus turpis. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;
-
-Etiam in fermentum mi. Sed et tempor felis, eu aliquet nisi. Nam eget ullamcorper arcu. Nunc porttitor nisl a dolor blandit, eget consequat sem maximus. Phasellus lacinia quam porta orci malesuada, vel tincidunt.
diff --git a/_sass/syntax-highlighting/github.scss b/_sass/syntax-highlighting/github.scss
deleted file mode 100644
index c85e1ed14a..0000000000
--- a/_sass/syntax-highlighting/github.scss
+++ /dev/null
@@ -1,289 +0,0 @@
-/**
- * Syntax highlighting styles
- */
-
-
-
-.highlight, .highlighter-rouge {
- background-color: #F7F8FA;
- color: #5A6575;
- border: none;
-}
-
-.highlight .lineno {
- color: #B1B8C4
-}
-
-.highlight .c {
- color: #B1B8C4
-}
-
-.highlight .err {
- color: #5A6575
-}
-
-.highlight .g {
- color: #5A6575
-}
-
-.highlight .k {
- color: #25BEA1
-}
-
-.highlight .l {
- color: #5A6575
-}
-
-.highlight .n {
- color: #5A6575
-}
-
-.highlight .o {
- color: #25BEA1
-}
-
-.highlight .x {
- color: #FBBC09
-}
-
-.highlight .p {
- color: #25BEA1
-}
-
-.highlight .cm {
- color: #B1B8C4
-}
-
-.highlight .cp {
- color: #25BEA1
-}
-
-.highlight .c1 {
- color: #B1B8C4
-}
-
-.highlight .cs {
- color: #25BEA1
-}
-
-.highlight .gd {
- color: #E56134
-}
-
-.highlight .ge {
- color: #5A6575;
- font-style: italic
-}
-
-.highlight .gr {
- color: #9961C9
-}
-
-.highlight .gh {
- color: #FBBC09
-}
-
-.highlight .gi {
- color: #25BEA1
-}
-
-.highlight .go {
- color: #5A6575
-}
-
-.highlight .gp {
- color: #FBBC09
-}
-
-.highlight .gs {
- color: #5A6575;
- font-weight: bold
-}
-
-.highlight .gu {
- color: #FBBC09
-}
-
-.highlight .gt {
- color: #5A6575
-}
-
-.highlight .kc {
- color: #FBBC09
-}
-
-.highlight .kd {
- color: #11A0F3
-}
-
-.highlight .kn {
- color: #25BEA1
-}
-
-.highlight .kp {
- color: #25BEA1
-}
-
-.highlight .kr {
- color: #11A0F3
-}
-
-.highlight .kt {
- color: #9961C9
-}
-
-.highlight .ld {
- color: #5A6575
-}
-
-.highlight .m {
- color: #E56134
-}
-
-.highlight .s {
- color: #E56134
-}
-
-.highlight .na {
- color: #5A6575
-}
-
-.highlight .nb {
- color: #5A6575
-}
-
-.highlight .nc {
- color: #11A0F3
-}
-
-.highlight .no {
- color: #5A6575
-}
-
-.highlight .nd {
- color: #11A0F3
-}
-
-.highlight .ni {
- color: #FBBC09
-}
-
-.highlight .ne {
- color: #FBBC09
-}
-
-.highlight .nf {
- color: #11A0F3
-}
-
-.highlight .nl {
- color: #5A6575
-}
-
-.highlight .nn {
- color: #5A6575
-}
-
-.highlight .nx {
- color: #5A6575
-}
-
-.highlight .py {
- color: #5A6575
-}
-
-.highlight .nt {
- color: #11A0F3
-}
-
-.highlight .nv {
- color: #5A6575
-}
-
-.highlight .ow {
- color: #25BEA1
-}
-
-.highlight .w {
- color: #5A6575
-}
-
-.highlight .mf {
- color: #E56134
-}
-
-.highlight .mh {
- color: #E56134
-}
-
-.highlight .mi {
- color: #E56134
-}
-
-.highlight .mo {
- color: #E56134
-}
-
-.highlight .sb {
- color: #B1B8C4
-}
-
-.highlight .sc {
- color: #E56134
-}
-
-.highlight .sd {
- color: #5A6575
-}
-
-.highlight .s2 {
- color: #E56134
-}
-
-.highlight .se {
- color: #FBBC09
-}
-
-.highlight .sh {
- color: #5A6575
-}
-
-.highlight .si {
- color: #E56134
-}
-
-.highlight .sx {
- color: #E56134
-}
-
-.highlight .sr {
- color: #9961C9
-}
-
-.highlight .s1 {
- color: #E56134
-}
-
-.highlight .ss {
- color: #E56134
-}
-
-.highlight .bp {
- color: #11A0F3
-}
-
-.highlight .vc {
- color: #11A0F3
-}
-
-.highlight .vg {
- color: #11A0F3
-}
-
-.highlight .vi {
- color: #11A0F3
-}
-
-.highlight .il {
- color: #E56134
-}
diff --git a/_sass/system-font-css/CHANGELOG.md b/_sass/system-font-css/CHANGELOG.md
deleted file mode 100644
index 7a4eee3d64..0000000000
--- a/_sass/system-font-css/CHANGELOG.md
+++ /dev/null
@@ -1,13 +0,0 @@
-## 2.0.0 (2017-06-28)
-
-- Changed from `system` to `system-ui` to match the CSS specification.
-
-## 1.1.0 (2015-08-02)
-
-- Added: Android fonts Roboto and Droid Sans after Ubuntu.
-- Removed: Windows 3.1-ME font Microsoft Sans Serif.
-- Updated: documentation.
-
-## 1.0.0 (2015-07-30)
-
-- Added: Initial version
diff --git a/_sass/system-font-css/LICENSE.md b/_sass/system-font-css/LICENSE.md
deleted file mode 100644
index 565f84e33c..0000000000
--- a/_sass/system-font-css/LICENSE.md
+++ /dev/null
@@ -1,15 +0,0 @@
-# CC0 1.0 Universal License
-
-Public Domain Dedication
-
-The person(s) who associated a work with this deed has dedicated the work to the public domain by waiving all of his or her rights to the work worldwide under copyright law, including all related and neighboring rights, to the extent allowed by law.
-
-You can copy, modify, distribute and perform the work, even for commercial purposes, all without asking permission.
-
-In no way are the patent or trademark rights of any person affected by CC0, nor are the rights that other persons may have in the work or in how the work is used, such as publicity or privacy rights.
-
-Unless expressly stated otherwise, the person(s) who associated a work with this deed makes no warranties about the work, and disclaims liability for all uses of the work, to the fullest extent permitted by applicable law.
-
-When using or citing the work, you should not imply endorsement by the author or the affirmer.
-
-This is a [human-readable summary of the Legal Code](https://creativecommons.org/publicdomain/zero/1.0/) ([read the full text](https://creativecommons.org/publicdomain/zero/1.0/legalcode)).
diff --git a/_sass/system-font-css/README.md b/_sass/system-font-css/README.md
deleted file mode 100644
index 08268fb2b5..0000000000
--- a/_sass/system-font-css/README.md
+++ /dev/null
@@ -1,68 +0,0 @@
-# System Font CSS
-
-System Font CSS is set of `@font-face` rules that let you use the native system font of the OS running the browser.
-
-```css
-body {
- font-family: system-ui;
-}
-```
-
-[system-font.css](system-font.css) offers eight variations of the `system-ui` font family; **light** (300) **light italic**, **normal** (400), **normal italic**, **medium** (500), **medium italic**, **bold** (700), and **bold italic**.
-
-```css
-blockquote {
- font: italic 300 system-ui;
-}
-
-p {
- font: 400 system-ui;
-}
-```
-
-## Quick Start
-
-### Install
-
-This package can be installed with:
-
-* [npm](https://www.npmjs.com/package/system-font-css): `npm install --save system-font-css`
-
-### Load
-
-When installed with npm, system-font.css will create both a SCSS and LESS partial for easy importing:
-
-```scss
-@import 'system-font';
-```
-
-## OSX
-
-**OSX** has used three system typefaces. Since **El Capitan** it has used **San Fransisco**. In **Yosemite** it used **Helvetica Neue**. From **Mavericks** back to **Kodiak** it used **Lucida Grande**.
-
-## Windows
-
-**Windows** has used four system typefaces. Since **Vista** it has used **Segoe UI**. In XP, it used **Tahoma**, which oddly enough does not have an italic variation. From **Windows ME** back to **Windows 3.1** it used **Microsoft Sans Serif**. Finally, from **Windows 2.0** back to **Windows 1.0** it used **Fixedsys**. Neither **Microsoft Sans Serif** or **Fixedsys** are included in this set, with apologies.
-
-Also, for those of opposed to joy, remember that **Internet Explorer 8** does not support local `@font-face` rules. Therefore, should you need to reference system fonts in that browser then you will need to do so from the `font` declaration.
-
-```css
-body {
- font-family: system-ui, "Segoe UI", Tahoma;
-}
-```
-
-## Android
-
-**Android** has used two system typefaces. Since **Ice Cream Sandwich** it has used **Roboto**. From **Jelly Bean** back to **Cupcake** it used **Droid Sans**, which also lacks an italic variation. Do you suppose OS developers dislike *emphasis*?
-
-## Ubuntu
-
-Ubuntu has always used one system typeface, aptly named **Ubuntu**. That part was easy.
-
-## Native `system-ui` resources
-
-* [CSS Fonts Module Level 4 Editor’s Draft Specification](https://drafts.csswg.org/css-fonts-4/#system-ui-def)
-* [Chrome Platform Status](https://www.chromestatus.com/feature/5640395337760768)
-* Proposed for inclusion on [Can I Use](https://github.com/Fyrd/caniuse/issues/2918)
-* Previous [discussions in the W3C](https://lists.w3.org/Archives/Public/www-style/2015Jul/0169.html) to standardize a generic `system` family.
diff --git a/_sass/system-font-css/_system-font.scss b/_sass/system-font-css/_system-font.scss
deleted file mode 100644
index fd07821988..0000000000
--- a/_sass/system-font-css/_system-font.scss
+++ /dev/null
@@ -1,57 +0,0 @@
-/*! system-font.css v2.0.2 | CC0-1.0 License | github.com/jonathantneal/system-font-css */
-
-@font-face {
- font-family: system-ui;
- font-style: normal;
- font-weight: 300;
- src: local(".SFNSText-Light"), local(".HelveticaNeueDeskInterface-Light"), local(".LucidaGrandeUI"), local("Segoe UI Light"), local("Ubuntu Light"), local("Roboto-Light"), local("DroidSans"), local("Tahoma");
-}
-
-@font-face {
- font-family: system-ui;
- font-style: italic;
- font-weight: 300;
- src: local(".SFNSText-LightItalic"), local(".HelveticaNeueDeskInterface-Italic"), local(".LucidaGrandeUI"), local("Segoe UI Light Italic"), local("Ubuntu Light Italic"), local("Roboto-LightItalic"), local("DroidSans"), local("Tahoma");
-}
-
-@font-face {
- font-family: system-ui;
- font-style: normal;
- font-weight: 400;
- src: local(".SFNSText-Regular"), local(".HelveticaNeueDeskInterface-Regular"), local(".LucidaGrandeUI"), local("Segoe UI"), local("Ubuntu"), local("Roboto-Regular"), local("DroidSans"), local("Tahoma");
-}
-
-@font-face {
- font-family: system-ui;
- font-style: italic;
- font-weight: 400;
- src: local(".SFNSText-Italic"), local(".HelveticaNeueDeskInterface-Italic"), local(".LucidaGrandeUI"), local("Segoe UI Italic"), local("Ubuntu Italic"), local("Roboto-Italic"), local("DroidSans"), local("Tahoma");
-}
-
-@font-face {
- font-family: system-ui;
- font-style: normal;
- font-weight: 500;
- src: local(".SFNSText-Medium"), local(".HelveticaNeueDeskInterface-MediumP4"), local(".LucidaGrandeUI"), local("Segoe UI Semibold"), local("Ubuntu Medium"), local("Roboto-Medium"), local("DroidSans-Bold"), local("Tahoma Bold");
-}
-
-@font-face {
- font-family: system-ui;
- font-style: italic;
- font-weight: 500;
- src: local(".SFNSText-MediumItalic"), local(".HelveticaNeueDeskInterface-MediumItalicP4"), local(".LucidaGrandeUI"), local("Segoe UI Semibold Italic"), local("Ubuntu Medium Italic"), local("Roboto-MediumItalic"), local("DroidSans-Bold"), local("Tahoma Bold");
-}
-
-@font-face {
- font-family: system-ui;
- font-style: normal;
- font-weight: 700;
- src: local(".SFNSText-Bold"), local(".HelveticaNeueDeskInterface-Bold"), local(".LucidaGrandeUI"), local("Segoe UI Bold"), local("Ubuntu Bold"), local("Roboto-Bold"), local("DroidSans-Bold"), local("Tahoma Bold");
-}
-
-@font-face {
- font-family: system-ui;
- font-style: italic;
- font-weight: 700;
- src: local(".SFNSText-BoldItalic"), local(".HelveticaNeueDeskInterface-BoldItalic"), local(".LucidaGrandeUI"), local("Segoe UI Bold Italic"), local("Ubuntu Bold Italic"), local("Roboto-BoldItalic"), local("DroidSans-Bold"), local("Tahoma Bold");
-}
diff --git a/_sass/system-font-css/index.html b/_sass/system-font-css/index.html
deleted file mode 100644
index ec5ea86283..0000000000
--- a/_sass/system-font-css/index.html
+++ /dev/null
@@ -1,189 +0,0 @@
-
-
System Font CSS
-
-
-
-
-
-
-
- System Font CSS
-
-
-
- System Font CSS is set of @font-face rules that let you use the native system font of the OS running the browser.
-
-
-
-body {
- font-family : system ;
-}
-
-
-
- system-font.css offers eight variations of the system font family; light (300) light italic , normal (400), normal italic , medium (500), medium italic , bold (700), and bold italic .
-
-
-
-blockquote {
- font : italic 300 system ;
-}
-
-p {
- font : 400 system ;
-}
-
-
-
- OSX
-
-
-
- OSX has used three system typefaces. Since El Capitan it has used San Fransisco . In Yosemite it used Helvetica Neue . From Mavericks back to Kodiak it used Lucida Grande .
-
-
-
- Windows
-
-
-
- Windows has used four system typefaces. Since Vista it has used Segoe UI . In XP, it used Tahoma , which oddly enough lacks an italic variation. From Windows ME back to Windows 3.1 it used Microsoft Sans Serif . Finally, from Windows 2.0 back to Windows 1.0 it used Fixedsys . Neither Microsoft Sans Serif or Fixedsys are included in this set, with apologies.
-
-
-
- Also, for those of opposed to joy, remember that Internet Explorer 8 does not support local @font-face rules. Therefore, should you need to reference system fonts in that browser then you will need to do so from the font declaration.
-
-
-
-body {
- font-family : system, "Segoe UI", Tahoma ;
-}
-
-
-
- Android
-
-
-
- Android has used two system typefaces. Since Ice Cream Sandwich it has used Roboto . From Jelly Bean back to Cupcake it used Droid Sans , which also lacks an italic variation. Do you suppose OS developers dislike emphasis ?
-
-
-
- Ubuntu
-
-
-
- Ubuntu has always used one system typeface, apty named Ubuntu . That part was easy.
-
-
-
- Is system going to be a thing?
-
-
-
- Maybe. There are discussions in the W3C to standardize a generic system family.
-
diff --git a/_sass/system-font-css/package.json b/_sass/system-font-css/package.json
deleted file mode 100644
index 91916c24e2..0000000000
--- a/_sass/system-font-css/package.json
+++ /dev/null
@@ -1,83 +0,0 @@
-{
- "_from": "system-font-css@^2.0.1",
- "_id": "system-font-css@2.0.2",
- "_inBundle": false,
- "_integrity": "sha512-zK36lpja4NIi4Po99bXReeqeDcM1sW4hTKJt5Mby/IXX6kLSwjkQ4pZThFdgb/jDwfRsBvxxVG+VekP1sTdF0w==",
- "_location": "/system-font-css",
- "_phantomChildren": {},
- "_requested": {
- "type": "range",
- "registry": true,
- "raw": "system-font-css@^2.0.1",
- "name": "system-font-css",
- "escapedName": "system-font-css",
- "rawSpec": "^2.0.1",
- "saveSpec": null,
- "fetchSpec": "^2.0.1"
- },
- "_requiredBy": [
- "/"
- ],
- "_resolved": "https://registry.npmjs.org/system-font-css/-/system-font-css-2.0.2.tgz",
- "_shasum": "88c4ae30eda94bc60705cba7d66c8c822f3c47db",
- "_spec": "system-font-css@^2.0.1",
- "_where": "/Users/ivan/Dev/jekyll/jekyll-theme-docs",
- "author": {
- "name": "Jonathan Neal",
- "email": "jonathantneal@hotmail.com",
- "url": "http://jonathantneal.com"
- },
- "bugs": {
- "url": "https://github.com/jonathantneal/system-font-css/issues"
- },
- "bundleDependencies": false,
- "contributors": [
- {
- "name": "Zach Leatherman",
- "email": "zachleatherman@gmail.com",
- "url": "https://zachleat.com/"
- }
- ],
- "dependencies": {
- "cpr": "^2.2.0"
- },
- "deprecated": false,
- "description": "Use the native system font of the OS running the browser",
- "devDependencies": {},
- "engines": {
- "node": ">=0.8.0"
- },
- "homepage": "https://github.com/jonathantneal/system-font-css",
- "keywords": [
- "system",
- "fonts",
- "faces",
- "rules",
- "css",
- "mac",
- "windows",
- "ubuntu",
- "san",
- "fransisco",
- "helvetica",
- "neue",
- "lucida",
- "grande",
- "segoe",
- "ui",
- "microsoft",
- "sans",
- "serif"
- ],
- "license": "CC0-1.0",
- "main": "system-font.css",
- "name": "system-font-css",
- "repository": {
- "type": "git",
- "url": "git+ssh://git@github.com/jonathantneal/system-font-css.git"
- },
- "scripts": {
- "install": "cpr system-font.css _system-font.scss -o && cpr system-font.css system-font.less -o"
- },
- "version": "2.0.2"
-}
diff --git a/_sass/system-font-css/system-font.css b/_sass/system-font-css/system-font.css
deleted file mode 100644
index fd07821988..0000000000
--- a/_sass/system-font-css/system-font.css
+++ /dev/null
@@ -1,57 +0,0 @@
-/*! system-font.css v2.0.2 | CC0-1.0 License | github.com/jonathantneal/system-font-css */
-
-@font-face {
- font-family: system-ui;
- font-style: normal;
- font-weight: 300;
- src: local(".SFNSText-Light"), local(".HelveticaNeueDeskInterface-Light"), local(".LucidaGrandeUI"), local("Segoe UI Light"), local("Ubuntu Light"), local("Roboto-Light"), local("DroidSans"), local("Tahoma");
-}
-
-@font-face {
- font-family: system-ui;
- font-style: italic;
- font-weight: 300;
- src: local(".SFNSText-LightItalic"), local(".HelveticaNeueDeskInterface-Italic"), local(".LucidaGrandeUI"), local("Segoe UI Light Italic"), local("Ubuntu Light Italic"), local("Roboto-LightItalic"), local("DroidSans"), local("Tahoma");
-}
-
-@font-face {
- font-family: system-ui;
- font-style: normal;
- font-weight: 400;
- src: local(".SFNSText-Regular"), local(".HelveticaNeueDeskInterface-Regular"), local(".LucidaGrandeUI"), local("Segoe UI"), local("Ubuntu"), local("Roboto-Regular"), local("DroidSans"), local("Tahoma");
-}
-
-@font-face {
- font-family: system-ui;
- font-style: italic;
- font-weight: 400;
- src: local(".SFNSText-Italic"), local(".HelveticaNeueDeskInterface-Italic"), local(".LucidaGrandeUI"), local("Segoe UI Italic"), local("Ubuntu Italic"), local("Roboto-Italic"), local("DroidSans"), local("Tahoma");
-}
-
-@font-face {
- font-family: system-ui;
- font-style: normal;
- font-weight: 500;
- src: local(".SFNSText-Medium"), local(".HelveticaNeueDeskInterface-MediumP4"), local(".LucidaGrandeUI"), local("Segoe UI Semibold"), local("Ubuntu Medium"), local("Roboto-Medium"), local("DroidSans-Bold"), local("Tahoma Bold");
-}
-
-@font-face {
- font-family: system-ui;
- font-style: italic;
- font-weight: 500;
- src: local(".SFNSText-MediumItalic"), local(".HelveticaNeueDeskInterface-MediumItalicP4"), local(".LucidaGrandeUI"), local("Segoe UI Semibold Italic"), local("Ubuntu Medium Italic"), local("Roboto-MediumItalic"), local("DroidSans-Bold"), local("Tahoma Bold");
-}
-
-@font-face {
- font-family: system-ui;
- font-style: normal;
- font-weight: 700;
- src: local(".SFNSText-Bold"), local(".HelveticaNeueDeskInterface-Bold"), local(".LucidaGrandeUI"), local("Segoe UI Bold"), local("Ubuntu Bold"), local("Roboto-Bold"), local("DroidSans-Bold"), local("Tahoma Bold");
-}
-
-@font-face {
- font-family: system-ui;
- font-style: italic;
- font-weight: 700;
- src: local(".SFNSText-BoldItalic"), local(".HelveticaNeueDeskInterface-BoldItalic"), local(".LucidaGrandeUI"), local("Segoe UI Bold Italic"), local("Ubuntu Bold Italic"), local("Roboto-BoldItalic"), local("DroidSans-Bold"), local("Tahoma Bold");
-}
diff --git a/_sass/system-font-css/system-font.less b/_sass/system-font-css/system-font.less
deleted file mode 100644
index fd07821988..0000000000
--- a/_sass/system-font-css/system-font.less
+++ /dev/null
@@ -1,57 +0,0 @@
-/*! system-font.css v2.0.2 | CC0-1.0 License | github.com/jonathantneal/system-font-css */
-
-@font-face {
- font-family: system-ui;
- font-style: normal;
- font-weight: 300;
- src: local(".SFNSText-Light"), local(".HelveticaNeueDeskInterface-Light"), local(".LucidaGrandeUI"), local("Segoe UI Light"), local("Ubuntu Light"), local("Roboto-Light"), local("DroidSans"), local("Tahoma");
-}
-
-@font-face {
- font-family: system-ui;
- font-style: italic;
- font-weight: 300;
- src: local(".SFNSText-LightItalic"), local(".HelveticaNeueDeskInterface-Italic"), local(".LucidaGrandeUI"), local("Segoe UI Light Italic"), local("Ubuntu Light Italic"), local("Roboto-LightItalic"), local("DroidSans"), local("Tahoma");
-}
-
-@font-face {
- font-family: system-ui;
- font-style: normal;
- font-weight: 400;
- src: local(".SFNSText-Regular"), local(".HelveticaNeueDeskInterface-Regular"), local(".LucidaGrandeUI"), local("Segoe UI"), local("Ubuntu"), local("Roboto-Regular"), local("DroidSans"), local("Tahoma");
-}
-
-@font-face {
- font-family: system-ui;
- font-style: italic;
- font-weight: 400;
- src: local(".SFNSText-Italic"), local(".HelveticaNeueDeskInterface-Italic"), local(".LucidaGrandeUI"), local("Segoe UI Italic"), local("Ubuntu Italic"), local("Roboto-Italic"), local("DroidSans"), local("Tahoma");
-}
-
-@font-face {
- font-family: system-ui;
- font-style: normal;
- font-weight: 500;
- src: local(".SFNSText-Medium"), local(".HelveticaNeueDeskInterface-MediumP4"), local(".LucidaGrandeUI"), local("Segoe UI Semibold"), local("Ubuntu Medium"), local("Roboto-Medium"), local("DroidSans-Bold"), local("Tahoma Bold");
-}
-
-@font-face {
- font-family: system-ui;
- font-style: italic;
- font-weight: 500;
- src: local(".SFNSText-MediumItalic"), local(".HelveticaNeueDeskInterface-MediumItalicP4"), local(".LucidaGrandeUI"), local("Segoe UI Semibold Italic"), local("Ubuntu Medium Italic"), local("Roboto-MediumItalic"), local("DroidSans-Bold"), local("Tahoma Bold");
-}
-
-@font-face {
- font-family: system-ui;
- font-style: normal;
- font-weight: 700;
- src: local(".SFNSText-Bold"), local(".HelveticaNeueDeskInterface-Bold"), local(".LucidaGrandeUI"), local("Segoe UI Bold"), local("Ubuntu Bold"), local("Roboto-Bold"), local("DroidSans-Bold"), local("Tahoma Bold");
-}
-
-@font-face {
- font-family: system-ui;
- font-style: italic;
- font-weight: 700;
- src: local(".SFNSText-BoldItalic"), local(".HelveticaNeueDeskInterface-BoldItalic"), local(".LucidaGrandeUI"), local("Segoe UI Bold Italic"), local("Ubuntu Bold Italic"), local("Roboto-BoldItalic"), local("DroidSans-Bold"), local("Tahoma Bold");
-}
diff --git a/_sass/theme/mixins.scss b/_sass/theme/mixins.scss
deleted file mode 100644
index f225462032..0000000000
--- a/_sass/theme/mixins.scss
+++ /dev/null
@@ -1,469 +0,0 @@
-
-@mixin hook-heading-hero(){
- font-weight: bold;
-}
-
-@mixin hook-navbar(){
- font-weight: 500;
- .uk-drop {
- width: 360px;
- }
- .uk-search-navbar .uk-search-input {
- height: 50px;
- font-size: 1.0625rem;
- padding-left: 1.1875rem;
- background: #fff;
- }
-}
-@mixin hook-button(){
- border-radius: 5px;
-}
-
-// Doc navigation
-$docs-sidebar-width: 260px;
-$docs-sidebar-width-l: 360px;
-.sidebar-fixed-width {
- width: $docs-sidebar-width;
-}
-.sidebar-docs {
- width: $docs-sidebar-width - $global-medium-gutter;
- padding-right: $global-medium-gutter;
- top: 112px;
- bottom: 70px;
- overflow-y: scroll;
- overflow-x: hidden;
- > h5 {
- margin: 15px 0 0;
- &:first-child {
- margin-top: 17px
- }
- }
-}
-
-@media (min-width: $breakpoint-large) {
- .sidebar-fixed-width {
- width: $docs-sidebar-width-l;
- }
- .sidebar-docs {
- width: $docs-sidebar-width-l - $global-large-gutter;
- padding-right: $global-large-gutter;
- }
-}
-ul.doc-nav {
- padding-left: 14px;
- margin-top: 5px;
-}
-.doc-nav > li.uk-active > a {
- position: relative;
- &:before {
- content: "";
- position: absolute;
- top: 15px;
- left: -14px;
- width: 7px;
- border-top: 1px solid $global-primary-background;
- }
-}
-
-// Home page hero
-.hero-image img {
- max-width: 200px;
- max-height: 75px;
-}
-.button-cta:nth-child(2n), .button-cta:nth-child(3n) {
- margin-top: $global-margin;
-}
-.heading-hero-2 {
- font-size: 1.875rem
-}
-@media (min-width: $breakpoint-small) {
- .heading-hero-2 {
- // font-size: 2.375rem;
- font-size: 1.375rem;
- }
-}
-@media (min-width: $breakpoint-medium) {
- .heading-hero-2 {
- // font-size: 2.75rem;
- font-size: 1.75rem;
- }
-}
-@mixin hook-card-title(){
- font-size: 1.125rem;
-}
-
-
-
-.list-featured>li:first-child {
- margin-top: $list-large-margin-top;
-}
-
-
-@mixin hook-base-body(){
- //filter: blur(7px);
- -moz-osx-font-smoothing: grayscale;
- -webkit-font-smoothing: antialiased;
-
-}
-@mixin hook-base-misc(){
- input[type="submit" i]{
- -webkit-appearance:none;
- }
-}
-@mixin hook-card(){
- border: solid 1px lighten($global-border, 10%);
- &:hover {
- border-color: darken($global-border, 10%);
- }
-}
-@mixin hook-card-body(){
- > p {
- font-size: $global-small-font-size;
- }
- > span {
- color: $global-primary-background;
- }
-}
-
-@mixin hook-card-misc(){
- .uk-position-cover {
- z-index: 1;
- }
- .card-category {
- h3:nth-child(2n) {
- margin-top: 0 !important;
- }
- }
- .card-post {
- .uk-card-header{
- padding-top: $global-medium-margin;
- padding-bottom: 0;
- }
- .uk-card-body{
- padding-top: $global-medium-margin / 2;
- padding-bottom: $global-medium-margin / 2;
- }
- .uk-card-footer{
- padding-bottom: $global-medium-margin * 0.8;
- padding-top: 0;
- }
- }
-}
-
-@mixin hook-form(){
- border: solid 1px $global-border;
-}
-
-@mixin hook-offcanvas-bar(){
- font-weight: 500;
-}
-
-@mixin hook-list-misc(){
- .uk-list {
- margin: 0;
- }
-}
-
-@mixin hook-article(){
- .share {
- }
- figure, .uk-slideshow {
- margin-top: $global-medium-margin * 1.1;
- margin-bottom: $global-medium-margin * 1.5;
- }
- figure {
- img + div .uk-overlay-icon {
- color: rgba(255, 255, 255, 0);
- }
- img:hover + div .uk-overlay-icon {
- color: rgba(255, 255, 255, 1);
- }
- figcaption {
- margin-left: 0;
- span {
- padding-right: 20px;
- margin-bottom: -43px;
- margin-top: 20px;
- border-right: solid 2px $global-muted-color;
- font-style: italic;
- font-size: 0.8rem;
- line-height: 1.8;
- }
- }
- }
- blockquote {
- border-left: solid 2px $global-muted-color;
- padding-left: $base-margin-vertical;
- line-height: 1.7;
- margin-top: $global-medium-margin;
- margin-bottom: $global-medium-margin;
- }
- .highlight,
- .highlighter-rouge {
- margin-top: $global-medium-margin;
- margin-bottom: $global-medium-margin;
- }
-}
-@mixin hook-article-title(){
- margin-bottom: $global-margin;
-}
-@mixin hook-article-meta(){
- a {
- color: $article-meta-color;
- &:hover {
- color: $global-primary-background;
- }
- }
- .avatar {
- margin-right: 10px;
- float: left;
- }
-}
-@mixin hook-article-misc(){
- .article-content {
- line-height: 1.8;
- }
- .avatar {
- border-radius: 50%;
- }
- .paginate-post .uk-text-small {
- line-height: 1.75;
- }
-}
-
-//
-// Utility
-//
-// ========================================================================
-@mixin hook-utility-misc(){
- .remove-underline, .remove-underline:hover{
- text-decoration: none;
- }
- .link-dark {
- color: $color-main !important;
- }
- .uk-container.uk-container-xsmall {
- max-width: 700px;
- }
- .hvr-forward {
- display: inline-block;
- vertical-align: middle;
- -webkit-transform: perspective(1px) translateZ(0);
- transform: perspective(1px) translateZ(0);
- box-shadow: 0 0 1px transparent;
- -webkit-transition-duration: 0.3s;
- transition-duration: 0.3s;
- -webkit-transition-property: transform;
- transition-property: transform;
- }
- .hvr-forward:active,
- .hvr-forward:focus,
- .hvr-forward:hover {
- -webkit-transform: translateX(6px);
- transform: translateX(6px);
- }
- .hvr-back {
- display: inline-block;
- vertical-align: middle;
- -webkit-transform: perspective(1px) translateZ(0);
- transform: perspective(1px) translateZ(0);
- box-shadow: 0 0 1px transparent;
- -webkit-transition-duration: 0.3s;
- transition-duration: 0.3s;
- -webkit-transition-property: transform;
- transition-property: transform;
- }
- .hvr-back:hover,
- .hvr-back:focus,
- .hvr-back:active {
- -webkit-transform: translateX(-6px);
- transform: translateX(-6px);
- }
- .social-networks {
- margin-top: $global-large-margin;
- }
- header {
- .uk-logo {
- color: $global-primary-background;
- &:hover {
- color: $global-primary-background;
- }
- }
- }
- .section-title {
- margin-bottom: $global-medium-margin;
- ~ .section-title {
- margin-top: $global-medium-margin;
- }
- }
- @media (min-width: $breakpoint-medium) {
- .section-title {
- ~ .section-title {
- margin-top: $global-large-margin;
- }
- }
- }
- .section-hero {
- .searchBox {
- max-width: 550px;
- margin: 60px auto 0 auto;
- .uk-search-input {
- height: 50px;
- border-radius: 50px;
- color: $global-muted-color;
- font-style: normal;
- &:focus {
- background: #ffffff;
- }
- }
- .uk-search-icon {
- width: 50px;
- color: $global-muted-color;
- }
-
- }
- }
- footer {
- .uk-subnav>.uk-active>a {
- color: $global-muted-color;
- }
- }
- #markdown-toc {
- padding: 0 0 0 $global-margin;
- border-left: solid 2px $global-muted-color;
- list-style: none;
- margin-bottom: $global-medium-margin;
- > li > :last-child {
- margin-bottom: 0;
- }
- ul {
- margin: 0;
- padding-left: $global-margin;
- list-style: none;
- }
- >li:nth-child(n+2), >li>ul {
- margin-top: 5px;
- }
- a {
- color: $global-muted-color;
- }
-
- }
- .uk-article-content .no_toc {
- margin-top: $global-medium-margin;
- margin-bottom: $global-medium-margin;
- }
- #searchBox-results, #searchBox-results {
- margin: 10px 0 0 0;
- z-index: 1;
- li {
- margin: 0;
- padding: 20px 25px 0;
- background: #fff;
- line-height: 1.4;
- border-left: solid 1px $global-border;
- border-right: solid 1px $global-border;
- &:first-child {
- border-top-left-radius: 5px;
- border-top-right-radius: 5px;
- border-top: solid 1px $global-border;
- }
- &:last-child {
- border-bottom-left-radius: 5px;
- border-bottom-right-radius: 5px;
- padding-bottom: 25px;
- border-bottom: solid 1px $global-border;
- }
- a:hover {
- text-decoration: none;
- }
- }
- }
-
-}
-
-
-$tm-timeline-border-width: 4px;
-$tm-timeline-dot-diameter: 20px;
-
-@media (min-width: $breakpoint-small) {
- .tm-timeline {
- box-sizing: border-box;
- * {
- box-sizing: border-box;
- }
- position: relative;
-
- &:before {
- content: '';
- position: absolute;
- top: 0;
- left: calc(30% - 2px);
- bottom: 0;
- width: $tm-timeline-border-width;
- background: $color-main;
- }
-
- &:after {
- content: "";
- display: table;
- clear: both;
- }
- }
-
- .tm-timeline-entry {
- + .tm-timeline-entry{
- margin-top: $global-large-margin;
- }
- clear: both;
- text-align: left;
- position: relative;
-
- &:after {
- display: block;
- content: "";
- clear: both;
- }
-
- .tm-timeline-time {
- float: left;
- width: 30%;
- padding-right: $global-large-margin;
- text-align: right;
- position: relative;
-
- &:before {
- content: '';
- position: absolute;
- width: $tm-timeline-dot-diameter;
- height: $tm-timeline-dot-diameter;
- border: $tm-timeline-border-width solid $color-main;
- background-color: #fff;
- border-radius: 100%;
- top: 0;
- right: - 14px;
- z-index: 99;
- }
-
- h5 {
- margin: 3px 0 0;
- }
- }
-
- .tm-timeline-body {
- float: right;
- width: 70%;
- padding-left: $global-large-margin;
- margin-top: -2px;
- h3 {
- margin: 0 0 15px;
- span {
- font-size: .7rem;
- margin-bottom: 4px;
- padding: 0 5px;
- }
- }
-
- }
- }
-}
diff --git a/_sass/theme/uikit.scss b/_sass/theme/uikit.scss
deleted file mode 100644
index 59e87618e9..0000000000
--- a/_sass/theme/uikit.scss
+++ /dev/null
@@ -1,92 +0,0 @@
-// Import UIkit components
-
-// Base
-@import "../uikit/components/variables.scss";
-@import "../uikit/components/mixin.scss";
-@import "../uikit/components/base.scss";
-
-// Elements
-@import "../uikit/components/link.scss";
-@import "../uikit/components/heading.scss";
-@import "../uikit/components/divider.scss";
-@import "../uikit/components/list.scss";
-// @import "../uikit/components/description-list.scss";
-// @import "../uikit/components/table.scss";
-@import "../uikit/components/icon.scss";
-// @import "../uikit/components/form-range.scss";
-@import "../uikit/components/form.scss"; // After: Icon, Form Range
-@import "../uikit/components/button.scss";
-
-// Layout
-@import "../uikit/components/section.scss";
-@import "../uikit/components/container.scss";
-@import "../uikit/components/grid.scss";
-@import "../uikit/components/tile.scss";
-@import "../uikit/components/card.scss";
-
-// Common
-@import "../uikit/components/close.scss"; // After: Icon
-// @import "../uikit/components/spinner.scss"; // After: Icon
-@import "../uikit/components/totop.scss"; // After: Icon
-// @import "../uikit/components/marker.scss"; // After: Icon
-// @import "../uikit/components/alert.scss"; // After: Close
-// @import "../uikit/components/badge.scss";
-@import "../uikit/components/label.scss";
-@import "../uikit/components/overlay.scss"; // After: Icon
-@import "../uikit/components/article.scss"; // After: Subnav
-// @import "../uikit/components/comment.scss"; // After: Subnav
-@import "../uikit/components/search.scss"; // After: Icon
-
-// Navs
-@import "../uikit/components/nav.scss";
-@import "../uikit/components/navbar.scss"; // After: Card, Grid, Nav, Icon, Search
-@import "../uikit/components/subnav.scss";
-// @import "../uikit/components/breadcrumb.scss";
-@import "../uikit/components/pagination.scss";
-// @import "../uikit/components/tab.scss";
-// @import "../uikit/components/slidenav.scss"; // After: Icon
-// @import "../uikit/components/dotnav.scss";
-// @import "../uikit/components/thumbnav.scss";
-
-// JavaScript
-// @import "../uikit/components/accordion.scss";
-@import "../uikit/components/drop.scss"; // After: Card
-@import "../uikit/components/dropdown.scss"; // After: Card
-// @import "../uikit/components/modal.scss"; // After: Close
-@import "../uikit/components/lightbox.scss"; // After: Close
-@import "../uikit/components/slideshow.scss";
-@import "../uikit/components/sticky.scss";
-@import "../uikit/components/offcanvas.scss";
-// @import "../uikit/components/switcher.scss";
-// Scrollspy
-// Toggle
-// Scroll
-
-// Additional
-// @import "../uikit/components/iconnav.scss";
-// @import "../uikit/components/notification.scss";
-// @import "../uikit/components/tooltip.scss";
-// @import "../uikit/components/placeholder.scss";
-// @import "../uikit/components/progress.scss";
-// @import "../uikit/components/sortable.scss";
-// @import "../uikit/components/countdown.scss";
-
-// Utilities
-@import "../uikit/components/animation.scss";
-@import "../uikit/components/width.scss";
-@import "../uikit/components/text.scss";
-@import "../uikit/components/column.scss";
-@import "../uikit/components/cover.scss";
-// @import "../uikit/components/background.scss";
-@import "../uikit/components/align.scss";
-@import "../uikit/components/utility.scss";
-@import "../uikit/components/flex.scss"; // After: Utility
-@import "../uikit/components/margin.scss";
-@import "../uikit/components/padding.scss";
-@import "../uikit/components/position.scss";
-// @import "../uikit/components/transition.scss";
-@import "../uikit/components/visibility.scss";
-// @import "../uikit/components/inverse.scss";
-
-// Need to be loaded last
-@import "../uikit/components/print.scss";
diff --git a/_sass/theme/variables.scss b/_sass/theme/variables.scss
deleted file mode 100644
index a4d98d34d5..0000000000
--- a/_sass/theme/variables.scss
+++ /dev/null
@@ -1,90 +0,0 @@
-// Color scheme variables
-
-// Main content
-$color-main: #0F1214;
-
-// Secondary content
-$global-muted-color: #7a838a;
-
-// Accent color
-$global-primary-background: $color-main;
-
-// Link and botton hover
-$color-hover: #000;
-
-// Standard UIkit
-//$global-muted-background: ;
-$global-border: #c4c7ca;
-
-// Global
-$global-font-family: system-ui;
-$global-link-color: $global-muted-color;
-$global-link-hover-color: $color-hover;
-
-$global-xxlarge-font-size: 1.875rem;;
-$global-xlarge-font-size: 1.625rem;
-$global-large-font-size: 1.375rem;
-$global-medium-font-size: 1.125rem;
-$global-small-font-size: 0.875rem;
-
-// Base
-$base-body-color: $color-main;
-$base-heading-color: $color-main;
-$link-muted-hover-color: $color-main;
-$button-primary-hover-background: $color-hover;
-$base-hr-border: lighten($global-border, 13%);
-$text-lead-font-size: 1.125rem;
-$base-heading-font-weight: bold;
-$base-heading-margin-top: 50px;
-// $base-body-font-weight: 300;
-$base-h2-line-height: 1.4;
-$base-link-hover-text-decoration: underline;
-// $base-h1-font-size: $global-xxlarge-font-size !default;
-// $base-h2-font-size: $global-xlarge-font-size !default;
-// $base-h3-font-size: $global-large-font-size !default;
-// $base-h4-font-size: $global-medium-font-size !default;
-// $base-h5-font-size: $global-font-size !default;
-// $base-h6-font-size: $global-small-font-size !default;
-
-// Navbar
-$navbar-background: #fff;
-$navbar-nav-item-color: $global-muted-color;
-$navbar-nav-item-hover-color: $color-main;
-$navbar-nav-item-active-color: $color-main;
-$navbar-toggle-color: $global-muted-color;
-$navbar-toggle-hover-color: $color-main;
-
-// Subnav
-$subnav-item-color: $global-muted-color;
-$subnav-item-hover-color: $color-main;
-
-// Pagination links
-$pagination-item-color: $color-main;
-$pagination-item-hover-color: $color-main;
-
-$article-meta-font-size: 0.8125rem;
-$article-meta-line-height: 1.3;
-
-$container-max-width: 1100px;
-$container-small-max-width: 800px;
-
-$card-small-body-padding-horizontal: 25px;
-$card-small-body-padding-vertical: 25px;
-
-$article-title-line-height: 1.4;
-$article-title-font-size: 1.875rem;
-$offcanvas-bar-color-mode: dark;
-$offcanvas-bar-background: #fff;
-
-$heading-hero-font-size: 2.375rem;
-$heading-hero-line-height: 1.3;
-$heading-hero-font-size-s: 2.9375rem;
-$heading-hero-line-height-s: 1.3;
-$heading-hero-font-size-m: 3.625rem;
-$heading-hero-line-height-m: 1.4;
-
-$navbar-nav-item-text-transform: none;
-
-$subnav-item-text-transform: none;
-
-$search-default-border: darken($global-border, 15%);
diff --git a/_sass/uikit/components/_import.components.scss b/_sass/uikit/components/_import.components.scss
deleted file mode 100644
index 445384fa54..0000000000
--- a/_sass/uikit/components/_import.components.scss
+++ /dev/null
@@ -1,56 +0,0 @@
-// Base
-@import "variables.scss";
-@import "mixin.scss";
-@import "base.scss";
-
-// Elements
-@import "link.scss";
-@import "heading.scss";
-@import "divider.scss";
-@import "list.scss";
-@import "description-list.scss";
-@import "table.scss";
-@import "icon.scss";
-@import "form.scss"; // After: Icon
-@import "button.scss";
-
-// Layout
-@import "section.scss";
-@import "container.scss";
-@import "grid.scss";
-@import "tile.scss";
-@import "card.scss";
-
-// Common
-@import "close.scss"; // After: Icon
-@import "spinner.scss"; // After: Icon
-@import "totop.scss"; // After: Icon
-@import "alert.scss"; // After: Close
-@import "badge.scss";
-@import "label.scss";
-@import "overlay.scss"; // After: Icon
-@import "article.scss"; // After: Subnav
-@import "comment.scss"; // After: Subnav
-@import "search.scss"; // After: Icon
-
-// Navs
-@import "nav.scss";
-@import "navbar.scss"; // After: Card, Grid, Nav, Icon, Search
-@import "subnav.scss";
-@import "breadcrumb.scss";
-@import "pagination.scss";
-@import "tab.scss";
-@import "slidenav.scss"; // After: Icon
-@import "dotnav.scss";
-
-// JavaScript
-@import "accordion.scss";
-@import "drop.scss"; // After: Card
-@import "dropdown.scss"; // After: Card
-@import "modal.scss"; // After: Close
-@import "sticky.scss";
-@import "offcanvas.scss";
-@import "switcher.scss";
-// Scrollspy
-// Toggle
-// Scroll
diff --git a/_sass/uikit/components/_import.scss b/_sass/uikit/components/_import.scss
deleted file mode 100644
index b3749a2984..0000000000
--- a/_sass/uikit/components/_import.scss
+++ /dev/null
@@ -1,91 +0,0 @@
-// Base
-@import "variables.scss";
-@import "mixin.scss";
-@import "base.scss";
-
-// Elements
-@import "link.scss";
-@import "heading.scss";
-@import "divider.scss";
-@import "list.scss";
-@import "description-list.scss";
-@import "table.scss";
-@import "icon.scss";
-@import "form-range.scss";
-@import "form.scss"; // After: Icon, Form Range
-@import "button.scss";
-
-// Layout
-@import "section.scss";
-@import "container.scss";
-@import "grid.scss";
-@import "tile.scss";
-@import "card.scss";
-
-// Common
-@import "close.scss"; // After: Icon
-@import "spinner.scss"; // After: Icon
-@import "totop.scss"; // After: Icon
-@import "marker.scss"; // After: Icon
-@import "alert.scss"; // After: Close
-@import "badge.scss";
-@import "label.scss";
-@import "overlay.scss"; // After: Icon
-@import "article.scss"; // After: Subnav
-@import "comment.scss"; // After: Subnav
-@import "search.scss"; // After: Icon
-
-// Navs
-@import "nav.scss";
-@import "navbar.scss"; // After: Card, Grid, Nav, Icon, Search
-@import "subnav.scss";
-@import "breadcrumb.scss";
-@import "pagination.scss";
-@import "tab.scss";
-@import "slidenav.scss"; // After: Icon
-@import "dotnav.scss";
-@import "thumbnav.scss";
-
-// JavaScript
-@import "accordion.scss";
-@import "drop.scss"; // After: Card
-@import "dropdown.scss"; // After: Card
-@import "modal.scss"; // After: Close
-@import "lightbox.scss"; // After: Close
-@import "slideshow.scss";
-@import "slider.scss";
-@import "sticky.scss";
-@import "offcanvas.scss";
-@import "switcher.scss";
-// Scrollspy
-// Toggle
-// Scroll
-
-// Additional
-@import "iconnav.scss";
-@import "notification.scss";
-@import "tooltip.scss";
-@import "placeholder.scss";
-@import "progress.scss";
-@import "sortable.scss";
-@import "countdown.scss";
-
-// Utilities
-@import "animation.scss";
-@import "width.scss";
-@import "text.scss";
-@import "column.scss";
-@import "cover.scss";
-@import "background.scss";
-@import "align.scss";
-@import "utility.scss";
-@import "flex.scss"; // After: Utility
-@import "margin.scss";
-@import "padding.scss";
-@import "position.scss";
-@import "transition.scss";
-@import "visibility.scss";
-@import "inverse.scss";
-
-// Need to be loaded last
-@import "print.scss";
diff --git a/_sass/uikit/components/_import.utilities.scss b/_sass/uikit/components/_import.utilities.scss
deleted file mode 100644
index bea39e5c72..0000000000
--- a/_sass/uikit/components/_import.utilities.scss
+++ /dev/null
@@ -1,19 +0,0 @@
-// Utilities
-@import "animation.scss";
-@import "width.scss";
-@import "text.scss";
-@import "column.scss";
-@import "cover.scss";
-@import "background.scss";
-@import "align.scss";
-@import "utility.scss";
-@import "flex.scss"; // After: Utility
-@import "margin.scss";
-@import "padding.scss";
-@import "position.scss";
-@import "transition.scss";
-@import "visibility.scss";
-@import "inverse.scss";
-
-// Need to be loaded last
-@import "print.scss";
diff --git a/_sass/uikit/components/accordion.scss b/_sass/uikit/components/accordion.scss
deleted file mode 100644
index bfb0e815d9..0000000000
--- a/_sass/uikit/components/accordion.scss
+++ /dev/null
@@ -1,118 +0,0 @@
-// Name: Accordion
-// Description: Component to create accordions
-//
-// Component: `uk-accordion`
-//
-// Sub-objects: `uk-accordion-title`
-// `uk-accordion-content`
-//
-// States: `uk-open`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$accordion-item-margin-top: $global-margin !default;
-
-$accordion-title-font-size: $global-medium-font-size !default;
-$accordion-title-line-height: 1.4 !default;
-$accordion-title-color: $global-emphasis-color !default;
-$accordion-title-hover-color: $global-color !default;
-
-$accordion-content-margin-top: $global-margin !default;
-
-
-/* ========================================================================
- Component: Accordion
- ========================================================================== */
-
-.uk-accordion {
- padding: 0;
- list-style: none;
- @if(mixin-exists(hook-accordion)) {@include hook-accordion();}
-}
-
-
-/* Item
- ========================================================================== */
-
-.uk-accordion > :nth-child(n+2) {
- margin-top: $accordion-item-margin-top;
- @if(mixin-exists(hook-accordion-item)) {@include hook-accordion-item();}
-}
-
-
-/* Title
- ========================================================================== */
-
-.uk-accordion-title {
- display: block;
- font-size: $accordion-title-font-size;
- line-height: $accordion-title-line-height;
- color: $accordion-title-color;
- @if(mixin-exists(hook-accordion-title)) {@include hook-accordion-title();}
-}
-
-/* Hover + Focus */
-.uk-accordion-title:hover,
-.uk-accordion-title:focus {
- color: $accordion-title-hover-color;
- text-decoration: none;
- outline: none;
- @if(mixin-exists(hook-accordion-title-hover)) {@include hook-accordion-title-hover();}
-}
-
-
-/* Content
- ========================================================================== */
-
-.uk-accordion-content {
- margin-top: $accordion-content-margin-top;
- @if(mixin-exists(hook-accordion-content)) {@include hook-accordion-content();}
-}
-
-/*
- * Micro clearfix
- */
-
-.uk-accordion-content::before,
-.uk-accordion-content::after {
- content: "";
- display: table;
-}
-
-.uk-accordion-content::after { clear: both; }
-
-/*
- * Remove margin from the last-child
- */
-
- .uk-accordion-content > :last-child { margin-bottom: 0; }
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-accordion-misc)) {@include hook-accordion-misc();}
-
-// @mixin hook-accordion(){}
-// @mixin hook-accordion-item(){}
-// @mixin hook-accordion-title(){}
-// @mixin hook-accordion-title-hover(){}
-// @mixin hook-accordion-content(){}
-// @mixin hook-accordion-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-$inverse-accordion-title-color: $inverse-global-emphasis-color !default;
-$inverse-accordion-title-hover-color: $inverse-global-inverse-color !default;
-
-
-
-// @mixin hook-inverse-accordion-item(){}
-// @mixin hook-inverse-accordion-title(){}
-// @mixin hook-inverse-accordion-title-hover(){}
\ No newline at end of file
diff --git a/_sass/uikit/components/alert.scss b/_sass/uikit/components/alert.scss
deleted file mode 100644
index 8922cc8543..0000000000
--- a/_sass/uikit/components/alert.scss
+++ /dev/null
@@ -1,147 +0,0 @@
-// Name: Alert
-// Description: Component to create alert messages
-//
-// Component: `uk-alert`
-//
-// Adopted: `uk-alert-close`
-//
-// Modifiers: `uk-alert-primary`
-// `uk-alert-success`
-// `uk-alert-warning`
-// `uk-alert-danger`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$alert-margin-vertical: $global-margin !default;
-$alert-padding: $global-small-gutter !default;
-$alert-padding-right: $alert-padding + 14px !default;
-$alert-background: $global-muted-background !default;
-$alert-color: $global-color !default;
-
-$alert-close-top: $alert-padding + 5px !default;
-$alert-close-right: $alert-padding !default;
-
-$alert-primary-background: lighten(mix(white, $global-primary-background, 40%), 20%) !default;
-$alert-primary-color: $global-primary-background !default;
-
-$alert-success-background: lighten(mix(white, $global-success-background, 40%), 25%) !default;
-$alert-success-color: $global-success-background !default;
-
-$alert-warning-background: lighten(mix(white, $global-warning-background, 45%), 15%) !default;
-$alert-warning-color: $global-warning-background !default;
-
-$alert-danger-background: lighten(mix(white, $global-danger-background, 40%), 20%) !default;
-$alert-danger-color: $global-danger-background !default;
-
-
-/* ========================================================================
- Component: Alert
- ========================================================================== */
-
-.uk-alert {
- position: relative;
- margin-bottom: $alert-margin-vertical;
- padding: $alert-padding $alert-padding-right $alert-padding $alert-padding;
- background: $alert-background;
- color: $alert-color;
- @if(mixin-exists(hook-alert)) {@include hook-alert();}
-}
-
-/* Add margin if adjacent element */
-* + .uk-alert { margin-top: $alert-margin-vertical; }
-
-/*
- * Remove margin from the last-child
- */
-
-.uk-alert > :last-child { margin-bottom: 0; }
-
-
-/* Close
- * Adopts `uk-close`
- ========================================================================== */
-
-.uk-alert-close {
- position: absolute;
- top: $alert-close-top;
- right: $alert-close-right;
- @if(mixin-exists(hook-alert-close)) {@include hook-alert-close();}
-}
-
-/*
- * Remove margin from adjacent element
- */
-
-.uk-alert-close:first-child + * { margin-top: 0; }
-
-/*
- * Hover + Focus
- */
-
-.uk-alert-close:hover,
-.uk-alert-close:focus {
- @if(mixin-exists(hook-alert-close-hover)) {@include hook-alert-close-hover();}
-}
-
-
-/* Style modifiers
- ========================================================================== */
-
-/*
- * Primary
- */
-
-.uk-alert-primary {
- background: $alert-primary-background;
- color: $alert-primary-color;
- @if(mixin-exists(hook-alert-primary)) {@include hook-alert-primary();}
-}
-
-/*
- * Success
- */
-
-.uk-alert-success {
- background: $alert-success-background;
- color: $alert-success-color;
- @if(mixin-exists(hook-alert-success)) {@include hook-alert-success();}
-}
-
-/*
- * Warning
- */
-
-.uk-alert-warning {
- background: $alert-warning-background;
- color: $alert-warning-color;
- @if(mixin-exists(hook-alert-warning)) {@include hook-alert-warning();}
-}
-
-/*
- * Danger
- */
-
-.uk-alert-danger {
- background: $alert-danger-background;
- color: $alert-danger-color;
- @if(mixin-exists(hook-alert-danger)) {@include hook-alert-danger();}
-}
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-alert-misc)) {@include hook-alert-misc();}
-
-// @mixin hook-alert(){}
-// @mixin hook-alert-close(){}
-// @mixin hook-alert-close-hover(){}
-// @mixin hook-alert-primary(){}
-// @mixin hook-alert-success(){}
-// @mixin hook-alert-warning(){}
-// @mixin hook-alert-danger(){}
-// @mixin hook-alert-misc(){}
\ No newline at end of file
diff --git a/_sass/uikit/components/align.scss b/_sass/uikit/components/align.scss
deleted file mode 100644
index bee6702bca..0000000000
--- a/_sass/uikit/components/align.scss
+++ /dev/null
@@ -1,142 +0,0 @@
-// Name: Align
-// Description: Utilities to align embedded content
-//
-// Component: `uk-align-left-*`
-// `uk-align-right-*`
-// `uk-align-center`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$align-margin-horizontal: $global-gutter !default;
-$align-margin-vertical: $global-gutter !default;
-
-$align-margin-horizontal-l: $global-medium-gutter !default;
-
-
-/* ========================================================================
- Component: Align
- ========================================================================== */
-
-/*
- * Default
- */
-
-[class*='uk-align'] {
- display: block;
- margin-bottom: $align-margin-vertical;
-}
-
-* + [class*='uk-align'] { margin-top: $align-margin-vertical; }
-
-/*
- * Center
- */
-
-.uk-align-center {
- margin-left: auto;
- margin-right: auto;
-}
-
-/*
- * Left/Right
- */
-
-.uk-align-left {
- margin-top: 0;
- margin-right: $align-margin-horizontal;
- float: left;
-}
-
-.uk-align-right {
- margin-top: 0;
- margin-left: $align-margin-horizontal;
- float: right;
-}
-
-/* Phone landscape and bigger */
-@media (min-width: $breakpoint-small) {
-
- .uk-align-left\@s {
- margin-top: 0;
- margin-right: $align-margin-horizontal;
- float: left;
- }
-
- .uk-align-right\@s {
- margin-top: 0;
- margin-left: $align-margin-horizontal;
- float: right;
- }
-
-}
-
-/* Tablet landscape and bigger */
-@media (min-width: $breakpoint-medium) {
-
- .uk-align-left\@m {
- margin-top: 0;
- margin-right: $align-margin-horizontal;
- float: left;
- }
-
- .uk-align-right\@m {
- margin-top: 0;
- margin-left: $align-margin-horizontal;
- float: right;
- }
-
-}
-
-/* Desktop and bigger */
-@media (min-width: $breakpoint-large) {
-
- .uk-align-left\@l {
- margin-top: 0;
- float: left;
- }
-
- .uk-align-right\@l {
- margin-top: 0;
- float: right;
- }
-
- .uk-align-left,
- .uk-align-left\@s,
- .uk-align-left\@m,
- .uk-align-left\@l { margin-right: $align-margin-horizontal-l; }
-
- .uk-align-right,
- .uk-align-right\@s,
- .uk-align-right\@m,
- .uk-align-right\@l { margin-left: $align-margin-horizontal-l; }
-
-}
-
-/* Large screen and bigger */
-@media (min-width: $breakpoint-xlarge) {
-
- .uk-align-left\@xl {
- margin-top: 0;
- margin-right: $align-margin-horizontal-l;
- float: left;
- }
-
- .uk-align-right\@xl {
- margin-top: 0;
- margin-left: $align-margin-horizontal-l;
- float: right;
- }
-
-}
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-align-misc)) {@include hook-align-misc();}
-
-// @mixin hook-align-misc(){}
\ No newline at end of file
diff --git a/_sass/uikit/components/animation.scss b/_sass/uikit/components/animation.scss
deleted file mode 100644
index c1d91928fa..0000000000
--- a/_sass/uikit/components/animation.scss
+++ /dev/null
@@ -1,390 +0,0 @@
-// Name: Animation
-// Description: Utilities for keyframe animations
-//
-// Component: `uk-animation-*`
-//
-// Modifiers: `uk-animation-reverse`
-// `uk-animation-fast`
-// `uk-animation-fade`
-// `uk-animation-scale-up`
-// `uk-animation-scale-down`
-// `uk-animation-slide-top-*`
-// `uk-animation-slide-bottom-*`
-// `uk-animation-slide-left-*`
-// `uk-animation-slide-right-*`
-// `uk-animation-kenburns`
-// `uk-animation-shake`
-//
-// Sub-objects: `uk-animation-toggle`
-//
-// States: `uk-hover`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$animation-duration: 0.5s !default;
-$animation-fade-duration: 0.8s !default;
-$animation-kenburns-duration: 15s !default;
-$animation-fast-duration: 0.1s !default;
-
-$animation-slide-small-translate: 10px !default;
-$animation-slide-medium-translate: 50px !default;
-
-
-/* ========================================================================
- Component: Animation
- ========================================================================== */
-
-[class*='uk-animation-'] {
- animation-duration: $animation-duration;
- animation-timing-function: ease-out;
- animation-fill-mode: both;
-}
-
-
-/* Direction modifier
- ========================================================================== */
-
-.uk-animation-reverse {
- animation-direction: reverse;
- animation-timing-function: ease-in;
-}
-
-
-/* Animations for scrollspy
- ========================================================================== */
-
-/*
- * Fade
- */
-
-.uk-animation-fade {
- animation-name: uk-fade;
- animation-duration: $animation-fade-duration;
- animation-timing-function: linear;
-}
-
-/*
- * Scale
- */
-
-.uk-animation-scale-up { animation-name: uk-fade-scale-02; }
-.uk-animation-scale-down { animation-name: uk-fade-scale-18; }
-
-/*
- * Slide
- */
-
-.uk-animation-slide-top { animation-name: uk-fade-top; }
-.uk-animation-slide-bottom { animation-name: uk-fade-bottom; }
-.uk-animation-slide-left { animation-name: uk-fade-left; }
-.uk-animation-slide-right { animation-name: uk-fade-right; }
-
-/*
- * Slide Small
- */
-
-.uk-animation-slide-top-small { animation-name: uk-fade-top-small; }
-.uk-animation-slide-bottom-small { animation-name: uk-fade-bottom-small; }
-.uk-animation-slide-left-small { animation-name: uk-fade-left-small; }
-.uk-animation-slide-right-small { animation-name: uk-fade-right-small; }
-
-/*
- * Slide Medium
- */
-
-.uk-animation-slide-top-medium { animation-name: uk-fade-top-medium; }
-.uk-animation-slide-bottom-medium { animation-name: uk-fade-bottom-medium; }
-.uk-animation-slide-left-medium { animation-name: uk-fade-left-medium; }
-.uk-animation-slide-right-medium { animation-name: uk-fade-right-medium; }
-
-/*
- * Kenburns
- */
-
-.uk-animation-kenburns {
- animation-name: uk-scale-kenburns;
- animation-duration: $animation-kenburns-duration;
-}
-
-/*
- * Shake
- */
-
-.uk-animation-shake { animation-name: uk-shake; }
-
-
-/* Duration modifier
- ========================================================================== */
-
-.uk-animation-fast { animation-duration: $animation-fast-duration; }
-
-
-/* Enable animation only on hover
-========================================================================== */
-
-/*
- * Note: Firefox and IE needs this because animations are not triggered when switching between display `none` and `block`
- */
-
-.uk-animation-toggle:not(:hover):not(.uk-hover) [class*='uk-animation-'] { animation-name: none; }
-
-
-/* Keyframes used by animation classes
- ========================================================================== */
-
-/*
- * Fade
- */
-
-@keyframes uk-fade {
- 0% { opacity: 0; }
- 100% { opacity: 1; }
-}
-
-/*
- * Slide Top
- */
-
-@keyframes uk-fade-top {
- 0% {
- opacity: 0;
- transform: translateY(-100%);
- }
- 100% {
- opacity: 1;
- transform: translateY(0);
- }
-}
-
-/*
- * Slide Bottom
- */
-
-@keyframes uk-fade-bottom {
- 0% {
- opacity: 0;
- transform: translateY(100%);
- }
- 100% {
- opacity: 1;
- transform: translateY(0);
- }
-}
-
-/*
- * Slide Left
- */
-
-@keyframes uk-fade-left {
- 0% {
- opacity: 0;
- transform: translateX(-100%);
- }
- 100% {
- opacity: 1;
- transform: translateX(0);
- }
-}
-
-/*
- * Slide Right
- */
-
-@keyframes uk-fade-right {
- 0% {
- opacity: 0;
- transform: translateX(100%);
- }
- 100% {
- opacity: 1;
- transform: translateX(0);
- }
-}
-
-/*
- * Slide Top Small
- */
-
-@keyframes uk-fade-top-small {
- 0% {
- opacity: 0;
- transform: translateY(-$animation-slide-small-translate);
- }
- 100% {
- opacity: 1;
- transform: translateY(0);
- }
-}
-
-/*
- * Slide Bottom Small
- */
-
-@keyframes uk-fade-bottom-small {
- 0% {
- opacity: 0;
- transform: translateY($animation-slide-small-translate);
- }
- 100% {
- opacity: 1;
- transform: translateY(0);
- }
-}
-
-/*
- * Slide Left Small
- */
-
-@keyframes uk-fade-left-small {
- 0% {
- opacity: 0;
- transform: translateX(-$animation-slide-small-translate);
- }
- 100% {
- opacity: 1;
- transform: translateX(0);
- }
-}
-
-/*
- * Slide Right Small
- */
-
-@keyframes uk-fade-right-small {
- 0% {
- opacity: 0;
- transform: translateX($animation-slide-small-translate);
- }
- 100% {
- opacity: 1;
- transform: translateX(0);
- }
-}
-
-/*
- * Slide Top Medium
- */
-
-@keyframes uk-fade-top-medium {
- 0% {
- opacity: 0;
- transform: translateY(-$animation-slide-medium-translate);
- }
- 100% {
- opacity: 1;
- transform: translateY(0);
- }
-}
-
-/*
- * Slide Bottom Medium
- */
-
-@keyframes uk-fade-bottom-medium {
- 0% {
- opacity: 0;
- transform: translateY($animation-slide-medium-translate);
- }
- 100% {
- opacity: 1;
- transform: translateY(0);
- }
-}
-
-/*
- * Slide Left Medium
- */
-
-@keyframes uk-fade-left-medium {
- 0% {
- opacity: 0;
- transform: translateX(-$animation-slide-medium-translate);
- }
- 100% {
- opacity: 1;
- transform: translateX(0);
- }
-}
-
-/*
- * Slide Right Medium
- */
-
-@keyframes uk-fade-right-medium {
- 0% {
- opacity: 0;
- transform: translateX($animation-slide-medium-translate);
- }
- 100% {
- opacity: 1;
- transform: translateX(0);
- }
-}
-
-/*
- * Scale Up
- */
-
-@keyframes uk-fade-scale-02 {
- 0% {
- opacity: 0;
- transform: scale(0.2);
- }
- 100% {
- opacity: 1;
- transform: scale(1);
- }
-}
-
-/*
- * Scale Down
- */
-
-@keyframes uk-fade-scale-18 {
- 0% {
- opacity: 0;
- transform: scale(1.8);
- }
- 100% {
- opacity: 1;
- transform: scale(1);
- }
-}
-
-/*
- * Kenburns
- */
-
-@keyframes uk-scale-kenburns {
- 0% { transform: scale(1); }
- 100% { transform: scale(1.2); }
-}
-
-/*
- * Shake
- */
-
-@keyframes uk-shake {
- 0%, 100% { transform: translateX(0); }
- 10% { transform: translateX(-9px); }
- 20% { transform: translateX(8px); }
- 30% { transform: translateX(-7px); }
- 40% { transform: translateX(6px); }
- 50% { transform: translateX(-5px); }
- 60% { transform: translateX(4px); }
- 70% { transform: translateX(-3px); }
- 80% { transform: translateX(2px); }
- 90% { transform: translateX(-1px); }
-}
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-animation-misc)) {@include hook-animation-misc();}
-
-// @mixin hook-animation-misc(){}
diff --git a/_sass/uikit/components/article.scss b/_sass/uikit/components/article.scss
deleted file mode 100644
index 9cc470f2c7..0000000000
--- a/_sass/uikit/components/article.scss
+++ /dev/null
@@ -1,102 +0,0 @@
-// Name: Article
-// Description: Component to create articles
-//
-// Component: `uk-article`
-//
-// Sub-objects: `uk-article-title`
-// `uk-article-meta`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$article-margin-top: $global-large-margin !default;
-
-$article-title-font-size: $global-xxlarge-font-size !default;
-$article-title-line-height: 1.2 !default;
-
-$article-meta-font-size: $global-small-font-size !default;
-$article-meta-line-height: 1.4 !default;
-$article-meta-color: $global-muted-color !default;
-
-
-/* ========================================================================
- Component: Article
- ========================================================================== */
-
-.uk-article {
- @if(mixin-exists(hook-article)) {@include hook-article();}
-}
-
-/*
- * Micro clearfix
- */
-
-.uk-article::before,
-.uk-article::after {
- content: "";
- display: table;
-}
-
-.uk-article::after { clear: both; }
-
-/*
- * Remove margin from the last-child
- */
-
-.uk-article > :last-child { margin-bottom: 0; }
-
-
-/* Adjacent sibling
- ========================================================================== */
-
-.uk-article + .uk-article {
- margin-top: $article-margin-top;
- @if(mixin-exists(hook-article-adjacent)) {@include hook-article-adjacent();}
-}
-
-
-/* Title
- ========================================================================== */
-
-.uk-article-title {
- font-size: $article-title-font-size;
- line-height: $article-title-line-height;
- @if(mixin-exists(hook-article-title)) {@include hook-article-title();}
-}
-
-
-/* Meta
- ========================================================================== */
-
-.uk-article-meta {
- font-size: $article-meta-font-size;
- line-height: $article-meta-line-height;
- color: $article-meta-color;
- @if(mixin-exists(hook-article-meta)) {@include hook-article-meta();}
-}
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-article-misc)) {@include hook-article-misc();}
-
-// @mixin hook-article(){}
-// @mixin hook-article-adjacent(){}
-// @mixin hook-article-title(){}
-// @mixin hook-article-meta(){}
-// @mixin hook-article-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-$inverse-article-meta-color: $inverse-global-muted-color !default;
-
-
-
-// @mixin hook-inverse-article-title(){}
-// @mixin hook-inverse-article-meta(){}
\ No newline at end of file
diff --git a/_sass/uikit/components/background.scss b/_sass/uikit/components/background.scss
deleted file mode 100644
index ca7a344a10..0000000000
--- a/_sass/uikit/components/background.scss
+++ /dev/null
@@ -1,136 +0,0 @@
-// Name: Background
-// Description: Utilities for backgrounds
-//
-// Component: `uk-background-*`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$background-default-background: $global-background !default;
-$background-muted-background: $global-muted-background !default;
-$background-primary-background: $global-primary-background !default;
-$background-secondary-background: $global-secondary-background !default;
-
-
-/* ========================================================================
- Component: Background
- ========================================================================== */
-
-
-/* Color
- ========================================================================== */
-
-.uk-background-default { background-color: $background-default-background; }
-.uk-background-muted { background-color: $background-muted-background; }
-.uk-background-primary { background-color: $background-primary-background; }
-.uk-background-secondary { background-color: $background-secondary-background; }
-
-
-/* Size
- ========================================================================== */
-
-.uk-background-cover,
-.uk-background-contain {
- background-position: 50% 50%;
- background-repeat: no-repeat;
-}
-
-.uk-background-cover { background-size: cover; }
-.uk-background-contain { background-size: contain; }
-
-
-/* Position
- ========================================================================== */
-
-.uk-background-top-left { background-position: 0 0; }
-.uk-background-top-center { background-position: 50% 0; }
-.uk-background-top-right { background-position: 100% 0; }
-.uk-background-center-left { background-position: 0 50%; }
-.uk-background-center-center { background-position: 50% 50%; }
-.uk-background-center-right { background-position: 100% 50%; }
-.uk-background-bottom-left { background-position: 0 100%; }
-.uk-background-bottom-center { background-position: 50% 100%; }
-.uk-background-bottom-right { background-position: 100% 100%; }
-
-
-/* Repeat
- ========================================================================== */
-
-.uk-background-norepeat { background-repeat: no-repeat; }
-
-
-/* Attachment
- ========================================================================== */
-
-.uk-background-fixed { background-attachment: fixed; }
-
-/*
- * Exclude touch devices because `fixed` doesn't work on iOS and Android
- */
-
-@media (pointer: coarse) {
- .uk-background-fixed { background-attachment: scroll; }
-}
-
-
-/* Image
- ========================================================================== */
-
-/* Phone portrait and smaller */
-@media (max-width: $breakpoint-xsmall-max) {
-
- .uk-background-image\@s { background-image: none !important; }
-
-}
-
-/* Phone landscape and smaller */
-@media (max-width: $breakpoint-small-max) {
-
- .uk-background-image\@m { background-image: none !important; }
-
-}
-
-/* Tablet landscape and smaller */
-@media (max-width: $breakpoint-medium-max) {
-
- .uk-background-image\@l { background-image: none !important; }
-
-}
-
-/* Desktop and smaller */
-@media (max-width: $breakpoint-large-max) {
-
- .uk-background-image\@xl {background-image: none !important; }
-
-}
-
-
-/* Blend modes
- ========================================================================== */
-
-.uk-background-blend-multiply { background-blend-mode: multiply; }
-.uk-background-blend-screen { background-blend-mode: screen; }
-.uk-background-blend-overlay { background-blend-mode: overlay; }
-.uk-background-blend-darken { background-blend-mode: darken; }
-.uk-background-blend-lighten { background-blend-mode: lighten; }
-.uk-background-blend-color-dodge { background-blend-mode: color-dodge; }
-.uk-background-blend-color-burn { background-blend-mode: color-burn; }
-.uk-background-blend-hard-light { background-blend-mode: hard-light; }
-.uk-background-blend-soft-light { background-blend-mode: soft-light; }
-.uk-background-blend-difference { background-blend-mode: difference; }
-.uk-background-blend-exclusion { background-blend-mode: exclusion; }
-.uk-background-blend-hue { background-blend-mode: hue; }
-.uk-background-blend-saturation { background-blend-mode: saturation; }
-.uk-background-blend-color { background-blend-mode: color; }
-.uk-background-blend-luminosity { background-blend-mode: luminosity; }
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-background-misc)) {@include hook-background-misc();}
-
-// @mixin hook-background-misc(){}
diff --git a/_sass/uikit/components/badge.scss b/_sass/uikit/components/badge.scss
deleted file mode 100644
index d076c5d06b..0000000000
--- a/_sass/uikit/components/badge.scss
+++ /dev/null
@@ -1,83 +0,0 @@
-// Name: Badge
-// Description: Component to create notification badges
-
-// Component: `uk-badge`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$badge-size: 22px !default;
-$badge-padding-vertical: 0 !default;
-$badge-padding-horizontal: 5px !default;
-$badge-border-radius: 500px !default;
-$badge-background: $global-primary-background !default;
-$badge-color: $global-inverse-color !default;
-$badge-font-size: $global-small-font-size !default;
-
-$badge-hover-color: $global-inverse-color !default;
-
-
-/* ========================================================================
- Component: Badge
- ========================================================================== */
-
-/*
- * 1. Style
- * 2. Center child vertically and horizontally
- */
-
-.uk-badge {
- box-sizing: border-box;
- min-width: $badge-size;
- height: $badge-size;
- padding: $badge-padding-vertical $badge-padding-horizontal;
- border-radius: $badge-border-radius;
- vertical-align: middle;
- /* 1 */
- background: $badge-background;
- color: $badge-color;
- font-size: $badge-font-size;
- /* 2 */
- display: inline-flex;
- justify-content: center;
- align-items: center;
- @if(mixin-exists(hook-badge)) {@include hook-badge();}
-}
-
-/*
- * Required for `a`
- */
-
-.uk-badge:hover,
-.uk-badge:focus {
- color: $badge-hover-color;
- text-decoration: none;
- outline: none;
- @if(mixin-exists(hook-badge-hover)) {@include hook-badge-hover();}
-}
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-badge-misc)) {@include hook-badge-misc();}
-
-// @mixin hook-badge(){}
-// @mixin hook-badge-hover(){}
-// @mixin hook-badge-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-$inverse-badge-background: $inverse-global-primary-background !default;
-$inverse-badge-color: $inverse-global-inverse-color !default;
-$inverse-badge-hover-color: $inverse-global-inverse-color !default;
-
-
-
-// @mixin hook-inverse-badge(){}
-// @mixin hook-inverse-badge-hover(){}
\ No newline at end of file
diff --git a/_sass/uikit/components/base.scss b/_sass/uikit/components/base.scss
deleted file mode 100644
index 138ecbb404..0000000000
--- a/_sass/uikit/components/base.scss
+++ /dev/null
@@ -1,612 +0,0 @@
-// Name: Base
-// Description: Default values for HTML elements
-//
-// Component: `uk-link`
-// `uk-h1`, `uk-h2`, `uk-h3`, `uk-h4`, `uk-h5`, `uk-h6`
-// `uk-hr`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$base-body-background: $global-background !default;
-$base-body-font-family: $global-font-family !default;
-$base-body-font-weight: normal !default;
-$base-body-font-size: $global-font-size !default;
-$base-body-line-height: $global-line-height !default;
-$base-body-color: $global-color !default;
-
-$base-link-color: $global-link-color !default;
-$base-link-text-decoration: none !default;
-$base-link-hover-color: $global-link-hover-color !default;
-$base-link-hover-text-decoration: underline !default;
-
-$base-strong-font-weight: bolder !default;
-$base-code-font-size: $global-small-font-size !default;
-$base-code-font-family: Consolas, monaco, monospace !default;
-$base-code-color: $global-danger-background !default;
-$base-em-color: $global-danger-background !default;
-$base-ins-background: #ffd !default;
-$base-ins-color: $global-color !default;
-$base-mark-background: #ffd !default;
-$base-mark-color: $global-color !default;
-$base-quote-font-style: italic !default;
-$base-small-font-size: 80% !default;
-
-$base-margin-vertical: $global-margin !default;
-
-$base-heading-font-family: $global-font-family !default;
-$base-heading-font-weight: normal !default;
-$base-heading-color: $global-emphasis-color !default;
-$base-heading-text-transform: none !default;
-$base-heading-margin-top: $global-medium-margin !default;
-$base-h1-font-size: $global-xxlarge-font-size !default;
-$base-h1-line-height: 1.2 !default;
-$base-h2-font-size: $global-xlarge-font-size !default;
-$base-h2-line-height: 1.3 !default;
-$base-h3-font-size: $global-large-font-size !default;
-$base-h3-line-height: 1.4 !default;
-$base-h4-font-size: $global-medium-font-size !default;
-$base-h4-line-height: 1.4 !default;
-$base-h5-font-size: $global-font-size !default;
-$base-h5-line-height: 1.4 !default;
-$base-h6-font-size: $global-small-font-size !default;
-$base-h6-line-height: 1.4 !default;
-
-$base-list-padding-left: 30px !default;
-
-$base-hr-margin-vertical: $global-margin !default;
-$base-hr-border-width: $global-border-width !default;
-$base-hr-border: $global-border !default;
-
-$base-blockquote-font-size: $global-medium-font-size !default;
-$base-blockquote-line-height: 1.5 !default;
-$base-blockquote-font-style: italic !default;
-$base-blockquote-margin-vertical: $global-margin !default;
-$base-blockquote-footer-margin-top: $global-small-margin !default;
-$base-blockquote-footer-font-size: $global-small-font-size !default;
-$base-blockquote-footer-line-height: 1.5 !default;
-
-$base-pre-font-size: $global-small-font-size !default;
-$base-pre-line-height: 1.5 !default;
-$base-pre-font-family: $base-code-font-family !default;
-$base-pre-color: $global-color !default;
-
-$base-selection-background: #39f !default;
-$base-selection-color: $global-inverse-color !default;
-
-
-/* ========================================================================
- Component: Base
- ========================================================================== */
-
-/*
- * 1. Set `font-size` to support `rem` units
- * Not using `font` property because a leading hyphen (e.g. -apple-system) causes the font to break in IE11 and Edge
- * 2. Prevent adjustments of font size after orientation changes in iOS.
- * 3. Style
- */
-
-html {
- /* 1 */
- font-family: $base-body-font-family;
- font-size: $base-body-font-size;
- font-weight: $base-body-font-weight;
- line-height: $base-body-line-height;
- /* 2 */
- -webkit-text-size-adjust: 100%;
- /* 3 */
- background: $base-body-background;
- color: $base-body-color;
- @if(mixin-exists(hook-base-body)) {@include hook-base-body();}
-}
-
-/*
- * Remove the margin in all browsers.
- */
-
-body { margin: 0; }
-
-
-/* Links
- ========================================================================== */
-
-/*
- * Remove gaps in links underline in iOS 8+ and Safari 8+.
- */
-
-a { -webkit-text-decoration-skip: objects; }
-
-/*
- * Remove the outline on focused links when they are also active or hovered
- */
-
-a:active,
-a:hover { outline: none; }
-
-/*
- * Style
- */
-
-a,
-.uk-link {
- color: $base-link-color;
- text-decoration: $base-link-text-decoration;
- cursor: pointer;
- @if(mixin-exists(hook-base-link)) {@include hook-base-link();}
-}
-
-a:hover,
-.uk-link:hover {
- color: $base-link-hover-color;
- text-decoration: $base-link-hover-text-decoration;
- @if(mixin-exists(hook-base-link-hover)) {@include hook-base-link-hover();}
-}
-
-
-/* Text-level semantics
- ========================================================================== */
-
-/*
- * 1. Remove the bottom border in Chrome 57-.
- * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
- */
-
-abbr[title] {
- /* 1 */
- border-bottom: none;
- /* 2 */
- text-decoration: underline;
- text-decoration: underline dotted;
-}
-
-
-/*
- * Add the correct font weight in Chrome, Edge, and Safari.
- */
-
-b,
-strong { font-weight: $base-strong-font-weight; }
-
-/*
- * 1. Consolas has a better baseline in running text compared to `Courier`
- * 2. Correct the odd `em` font sizing in all browsers.
- * 3. Style
- */
-
-:not(pre) > code,
-:not(pre) > kbd,
-:not(pre) > samp {
- /* 1 */
- font-family: $base-code-font-family;
- /* 2 */
- font-size: $base-code-font-size;
- /* 3 */
- color: $base-code-color;
- white-space: nowrap;
- @if(mixin-exists(hook-base-code)) {@include hook-base-code();}
-}
-
-/*
- * Emphasize
- */
-
-em { color: $base-em-color; }
-
-/*
- * Insert
- */
-
-ins {
- background: $base-ins-background;
- color: $base-ins-color;
- text-decoration: none;
-}
-
-/*
- * Mark
- */
-
-mark {
- background: $base-mark-background;
- color: $base-mark-color;
-}
-
-/*
- * Quote
- */
-
-q { font-style: $base-quote-font-style; }
-
-/*
- * Add the correct font size in all browsers.
- */
-
-small { font-size: $base-small-font-size; }
-
-/*
- * Prevents `sub` and `sup` affecting `line-height` in all browsers.
- */
-
-sub,
-sup {
- font-size: 75%;
- line-height: 0;
- position: relative;
- vertical-align: baseline;
-}
-
-sup { top: -0.5em; }
-sub { bottom: -0.25em; }
-
-
-/* Embedded content
- ========================================================================== */
-
-/*
- * Remove the gap between embedded content and the bottom of their containers.
- */
-
-audio,
-canvas,
-iframe,
-img,
-svg,
-video { vertical-align: middle; }
-
-/*
- * Responsiveness
- * 1. Set a maximum width
- * 2. Auto scale the height. Only needed if `height` attribute is present
- * 2. Corrects `max-width` behavior if padding and border are used
- */
-
-audio,
-canvas,
-img,
-video {
- /* 1 */
- max-width: 100%;
- /* 2 */
- height: auto;
- /* 3 */
- box-sizing: border-box;
-}
-
-/*
- * Hide the overflow in IE.
- */
-
-svg:not(:root) { overflow: hidden; }
-
-
-/* Block elements
- ========================================================================== */
-
-/*
- * Margins
- */
-
-p,
-ul,
-ol,
-dl,
-pre,
-address,
-fieldset,
-figure { margin: 0 0 $base-margin-vertical 0; }
-
-/* Add margin if adjacent element */
-* + p,
-* + ul,
-* + ol,
-* + dl,
-* + pre,
-* + address,
-* + fieldset,
-* + figure { margin-top: $base-margin-vertical; }
-
-
-/* Headings
- ========================================================================== */
-
-h1, .uk-h1,
-h2, .uk-h2,
-h3, .uk-h3,
-h4, .uk-h4,
-h5, .uk-h5,
-h6, .uk-h6 {
- margin: 0 0 $base-margin-vertical 0;
- font-family: $base-heading-font-family;
- font-weight: $base-heading-font-weight;
- color: $base-heading-color;
- text-transform: $base-heading-text-transform;
- @if(mixin-exists(hook-base-heading)) {@include hook-base-heading();}
-}
-
-/* Add margin if adjacent element */
-* + h1, * + .uk-h1,
-* + h2, * + .uk-h2,
-* + h3, * + .uk-h3,
-* + h4, * + .uk-h4,
-* + h5, * + .uk-h5,
-* + h6, * + .uk-h6 { margin-top: $base-heading-margin-top; }
-
-/*
- * Sizes
- */
-
-h1, .uk-h1 {
- font-size: $base-h1-font-size;
- line-height: $base-h1-line-height;
- @if(mixin-exists(hook-base-h1)) {@include hook-base-h1();}
-}
-
-h2, .uk-h2 {
- font-size: $base-h2-font-size;
- line-height: $base-h2-line-height;
- @if(mixin-exists(hook-base-h2)) {@include hook-base-h2();}
-}
-
-h3, .uk-h3 {
- font-size: $base-h3-font-size;
- line-height: $base-h3-line-height;
- @if(mixin-exists(hook-base-h3)) {@include hook-base-h3();}
-}
-
-h4, .uk-h4 {
- font-size: $base-h4-font-size;
- line-height: $base-h4-line-height;
- @if(mixin-exists(hook-base-h4)) {@include hook-base-h4();}
-}
-
-h5, .uk-h5 {
- font-size: $base-h5-font-size;
- line-height: $base-h5-line-height;
- @if(mixin-exists(hook-base-h5)) {@include hook-base-h5();}
-}
-
-h6, .uk-h6 {
- font-size: $base-h6-font-size;
- line-height: $base-h6-line-height;
- @if(mixin-exists(hook-base-h6)) {@include hook-base-h6();}
-}
-
-
-/* Lists
- ========================================================================== */
-
-ul,
-ol { padding-left: $base-list-padding-left; }
-
-/*
- * Reset margin for nested lists
- */
-
-ul > li > ul,
-ul > li > ol,
-ol > li > ol,
-ol > li > ul { margin: 0; }
-
-
-/* Description lists
- ========================================================================== */
-
-dt { font-weight: bold; }
-dd { margin-left: 0; }
-
-
-/* Horizontal rules
- ========================================================================== */
-
-/*
- * 1. Add the correct box sizing and height in Firefox.
- * 2. Show the overflow in Edge and IE.
- * 3. Add the correct text-align in Edge and IE.
- * 4. Style
- */
-
-hr, .uk-hr {
- /* 1 */
- box-sizing: content-box;
- height: 0;
- /* 2 */
- overflow: visible;
- /* 3 */
- text-align: inherit;
- /* 4 */
- margin: 0 0 $base-hr-margin-vertical 0;
- border: 0;
- border-top: $base-hr-border-width solid $base-hr-border;
- @if(mixin-exists(hook-base-hr)) {@include hook-base-hr();}
-}
-
-/* Add margin if adjacent element */
-* + hr,
-* + .uk-hr { margin-top: $base-hr-margin-vertical }
-
-
-/* Address
- ========================================================================== */
-
-address { font-style: normal; }
-
-
-/* Blockquotes
- ========================================================================== */
-
-blockquote {
- margin: 0 0 $base-blockquote-margin-vertical 0;
- font-size: $base-blockquote-font-size;
- line-height: $base-blockquote-line-height;
- font-style: $base-blockquote-font-style;
- @if(mixin-exists(hook-base-blockquote)) {@include hook-base-blockquote();}
-}
-
-/* Add margin if adjacent element */
-* + blockquote { margin-top: $base-blockquote-margin-vertical; }
-
-/*
- * Content
- */
-
-blockquote p:last-of-type { margin-bottom: 0; }
-
-blockquote footer {
- margin-top: $base-blockquote-footer-margin-top;
- font-size: $base-blockquote-footer-font-size;
- line-height: $base-blockquote-footer-line-height;
- @if(mixin-exists(hook-base-blockquote-footer)) {@include hook-base-blockquote-footer();}
-}
-
-
-/* Preformatted text
- ========================================================================== */
-
-/*
- * 1. Contain overflow in all browsers.
- */
-
-pre {
- font: $base-pre-font-size unquote("/") $base-pre-line-height $base-pre-font-family;
- color: $base-pre-color;
- -moz-tab-size: 4;
- tab-size: 4;
- /* 1 */
- overflow: auto;
- @if(mixin-exists(hook-base-pre)) {@include hook-base-pre();}
-}
-
-pre code { font-family: $base-pre-font-family; }
-
-
-/* Selection pseudo-element
- ========================================================================== */
-
-::-moz-selection {
- background: $base-selection-background;
- color: $base-selection-color;
- text-shadow: none;
-}
-
-::selection {
- background: $base-selection-background;
- color: $base-selection-color;
- text-shadow: none;
-}
-
-
-/* HTML5 elements
- ========================================================================== */
-
-/*
- * 1. Add the correct display in Edge, IE 10+, and Firefox.
- * 2. Add the correct display in IE.
- */
-
-details, /* 1 */
-main { /* 2 */
- display: block;
-}
-
-/*
- * Add the correct display in all browsers.
- */
-
-summary { display: list-item; }
-
-/*
- * Add the correct display in IE.
- */
-
-template { display: none; }
-
-
-/* Iframe
- ========================================================================== */
-
-iframe { border: 0; }
-
-
-/* Prevent the 300ms delay for touchscreen interactions
- ========================================================================== */
-
-/*
- * Most browsers prevent the 300ms delay automatically for sites that use the `width=device-width` property.
- * For Safari on iOS 9.3+, IE 11 and Edge on desktops and IE 11 on Windows Phone 8.1 it must be applied manually.
- */
-
-a,
-area,
-button,
-input,
-label,
-select,
-summary,
-textarea { touch-action: manipulation; }
-
-
-/* Pass media breakpoints to JS
- ========================================================================== */
-
-/*
- * Breakpoints
- */
-
-.var-media-s::before { content: '#{$breakpoint-small}'; }
-.var-media-m::before { content: '#{$breakpoint-medium}'; }
-.var-media-l::before { content: '#{$breakpoint-large}'; }
-.var-media-xl::before { content: '#{$breakpoint-xlarge}'; }
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-base-misc)) {@include hook-base-misc();}
-
-// @mixin hook-base-body(){}
-// @mixin hook-base-link(){}
-// @mixin hook-base-link-hover(){}
-// @mixin hook-base-code(){}
-// @mixin hook-base-heading(){}
-// @mixin hook-base-h1(){}
-// @mixin hook-base-h2(){}
-// @mixin hook-base-h3(){}
-// @mixin hook-base-h4(){}
-// @mixin hook-base-h5(){}
-// @mixin hook-base-h6(){}
-// @mixin hook-base-hr(){}
-// @mixin hook-base-blockquote(){}
-// @mixin hook-base-blockquote-footer(){}
-// @mixin hook-base-pre(){}
-// @mixin hook-base-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-$inverse-base-color: $inverse-global-color !default;
-$inverse-base-link-color: $inverse-global-emphasis-color !default;
-$inverse-base-link-hover-color: $inverse-global-emphasis-color !default;
-$inverse-base-code-color: $inverse-global-color !default;
-$inverse-base-em-color: $inverse-global-emphasis-color !default;
-$inverse-base-heading-color: $inverse-global-emphasis-color !default;
-$inverse-base-hr-border: $inverse-global-border !default;
-
-
-
-// @mixin hook-inverse-base-link(){}
-// @mixin hook-inverse-base-link-hover(){}
-// @mixin hook-inverse-base-code(){}
-// @mixin hook-inverse-base-heading(){}
-// @mixin hook-inverse-base-h1(){}
-// @mixin hook-inverse-base-h2(){}
-// @mixin hook-inverse-base-h3(){}
-// @mixin hook-inverse-base-h4(){}
-// @mixin hook-inverse-base-h5(){}
-// @mixin hook-inverse-base-h6(){}
-// @mixin hook-inverse-base-blockquote(){}
-// @mixin hook-inverse-base-blockquote-footer(){}
-// @mixin hook-inverse-base-hr(){}
diff --git a/_sass/uikit/components/breadcrumb.scss b/_sass/uikit/components/breadcrumb.scss
deleted file mode 100644
index 1f4ca50238..0000000000
--- a/_sass/uikit/components/breadcrumb.scss
+++ /dev/null
@@ -1,122 +0,0 @@
-// Name: Breadcrumb
-// Description: Component to create a breadcrumb navigation
-//
-// Component: `uk-breadcrumb`
-//
-// States: `uk-disabled`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$breadcrumb-item-font-size: $global-small-font-size !default;
-$breadcrumb-item-color: $global-muted-color !default;
-$breadcrumb-item-hover-color: $global-color !default;
-$breadcrumb-item-hover-text-decoration: none !default;
-$breadcrumb-item-active-color: $global-color !default;
-
-$breadcrumb-divider: "/" !default;
-$breadcrumb-divider-margin-horizontal: 20px !default;
-$breadcrumb-divider-color: $global-muted-color !default;
-
-
-/* ========================================================================
- Component: Breadcrumb
- ========================================================================== */
-
-/*
- * 1. Allow items to wrap into the next line
- * 2. Reset list
- */
-
-.uk-breadcrumb {
- display: flex;
- /* 1 */
- flex-wrap: wrap;
- /* 2 */
- padding: 0;
- list-style: none;
- @if(mixin-exists(hook-breadcrumb)) {@include hook-breadcrumb();}
-}
-
-/*
- * Space is allocated solely based on content dimensions: 0 0 auto
- */
-
-.uk-breadcrumb > * { flex: none; }
-
-
-/* Items
- ========================================================================== */
-
-.uk-breadcrumb > * > * {
- display: inline-block;
- font-size: $breadcrumb-item-font-size;
- color: $breadcrumb-item-color;
- @if(mixin-exists(hook-breadcrumb-item)) {@include hook-breadcrumb-item();}
-}
-
-/* Hover + Focus */
-.uk-breadcrumb > * > :hover,
-.uk-breadcrumb > * > :focus {
- color: $breadcrumb-item-hover-color;
- text-decoration: $breadcrumb-item-hover-text-decoration;
- @if(mixin-exists(hook-breadcrumb-item-hover)) {@include hook-breadcrumb-item-hover();}
-}
-
-/* Disabled */
-.uk-breadcrumb > .uk-disabled > * {
- @if(mixin-exists(hook-breadcrumb-item-disabled)) {@include hook-breadcrumb-item-disabled();}
-}
-
-/* Active */
-.uk-breadcrumb > :last-child > * {
- color: $breadcrumb-item-active-color;
- @if(mixin-exists(hook-breadcrumb-item-active)) {@include hook-breadcrumb-item-active();}
-}
-
-/*
- * Divider
- * `nth-child` makes it also work without JS if it's only one row
- */
-
-.uk-breadcrumb > :nth-child(n+2):not(.uk-first-column)::before {
- content: $breadcrumb-divider;
- display: inline-block;
- margin: 0 $breadcrumb-divider-margin-horizontal;
- color: $breadcrumb-divider-color;
- @if(mixin-exists(hook-breadcrumb-divider)) {@include hook-breadcrumb-divider();}
-}
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-breadcrumb-misc)) {@include hook-breadcrumb-misc();}
-
-// @mixin hook-breadcrumb(){}
-// @mixin hook-breadcrumb-item(){}
-// @mixin hook-breadcrumb-item-hover(){}
-// @mixin hook-breadcrumb-item-disabled(){}
-// @mixin hook-breadcrumb-item-active(){}
-// @mixin hook-breadcrumb-divider(){}
-// @mixin hook-breadcrumb-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-$inverse-breadcrumb-item-color: $inverse-global-muted-color !default;
-$inverse-breadcrumb-item-hover-color: $inverse-global-color !default;
-$inverse-breadcrumb-item-active-color: $inverse-global-color !default;
-$inverse-breadcrumb-divider-color: $inverse-global-muted-color !default;
-
-
-
-// @mixin hook-inverse-breadcrumb-item(){}
-// @mixin hook-inverse-breadcrumb-item-hover(){}
-// @mixin hook-inverse-breadcrumb-item-disabled(){}
-// @mixin hook-inverse-breadcrumb-item-active(){}
-// @mixin hook-inverse-breadcrumb-divider(){}
diff --git a/_sass/uikit/components/button.scss b/_sass/uikit/components/button.scss
deleted file mode 100644
index f65e1c2230..0000000000
--- a/_sass/uikit/components/button.scss
+++ /dev/null
@@ -1,451 +0,0 @@
-// Name: Button
-// Description: Styles for buttons
-//
-// Component: `uk-button`
-//
-// Sub-objects: `uk-button-group`
-//
-// Modifiers: `uk-button-default`
-// `uk-button-primary`
-// `uk-button-secondary`
-// `uk-button-danger`
-// `uk-button-text`
-// `uk-button-link`
-// `uk-button-small`
-// `uk-button-large`
-//
-// States: `uk-active`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$button-line-height: $global-control-height !default;
-$button-small-line-height: $global-control-small-height !default;
-$button-large-line-height: $global-control-large-height !default;
-
-$button-font-size: $global-font-size !default;
-$button-small-font-size: $global-small-font-size !default;
-$button-large-font-size: $global-medium-font-size !default;
-
-$button-padding-horizontal: $global-gutter !default;
-$button-small-padding-horizontal: $global-small-gutter !default;
-$button-large-padding-horizontal: $global-medium-gutter !default;
-
-$button-default-background: $global-muted-background !default;
-$button-default-color: $global-emphasis-color !default;
-$button-default-hover-background: darken($button-default-background, 5%) !default;
-$button-default-hover-color: $global-emphasis-color !default;
-$button-default-active-background: darken($button-default-background, 10%) !default;
-$button-default-active-color: $global-emphasis-color !default;
-
-$button-primary-background: $global-primary-background !default;
-$button-primary-color: $global-inverse-color !default;
-$button-primary-hover-background: darken($button-primary-background, 5%) !default;
-$button-primary-hover-color: $global-inverse-color !default;
-$button-primary-active-background: darken($button-primary-background, 10%) !default;
-$button-primary-active-color: $global-inverse-color !default;
-
-$button-secondary-background: $global-secondary-background !default;
-$button-secondary-color: $global-inverse-color !default;
-$button-secondary-hover-background: darken($button-secondary-background, 5%) !default;
-$button-secondary-hover-color: $global-inverse-color !default;
-$button-secondary-active-background: darken($button-secondary-background, 10%) !default;
-$button-secondary-active-color: $global-inverse-color !default;
-
-$button-danger-background: $global-danger-background !default;
-$button-danger-color: $global-inverse-color !default;
-$button-danger-hover-background: darken($button-danger-background, 5%) !default;
-$button-danger-hover-color: $global-inverse-color !default;
-$button-danger-active-background: darken($button-danger-background, 10%) !default;
-$button-danger-active-color: $global-inverse-color !default;
-
-$button-disabled-background: $global-muted-background !default;
-$button-disabled-color: $global-muted-color !default;
-
-$button-text-line-height: $global-line-height !default;
-$button-text-color: $global-muted-color !default;
-$button-text-hover-color: $global-color !default;
-$button-text-disabled-color: $global-muted-color !default;
-
-$button-link-line-height: $global-line-height !default;
-$button-link-color: $global-link-color !default;
-$button-link-hover-color: $global-link-hover-color !default;
-$button-link-hover-text-decoration: underline !default;
-$button-link-disabled-color: $global-muted-color !default;
-
-
-/* ========================================================================
- Component: Button
- ========================================================================== */
-
-/*
- * 1. Remove margins in Chrome, Safari and Opera.
- * 2. Remove borders for `button`.
- * 3. Remove border-radius in Chrome.
- * 4. Address `overflow` set to `hidden` in IE.
- * 5. Correct `font` properties and `color` not being inherited for `button`.
- * 6. Remove the inheritance of text transform in Edge, Firefox, and IE.
- * 7. Style
- * 8. `line-height` is used to create a height because it also centers the text vertically for `a` elements.
- * Better would be to use height and flexbox to center the text vertically but flexbox doesn't work in Firefox on `button` elements.
- * 9. Align text if button has a width
- * 10. Required for `a`.
- */
-
-.uk-button {
- /* 1 */
- margin: 0;
- /* 2 */
- border: none;
- /* 3 */
- border-radius: 0;
- /* 4 */
- overflow: visible;
- /* 5 */
- font: inherit;
- color: inherit;
- /* 6 */
- text-transform: none;
- /* 7 */
- display: inline-block;
- box-sizing: border-box;
- padding: 0 $button-padding-horizontal;
- vertical-align: middle;
- font-size: $button-font-size;
- /* 8 */
- line-height: $button-line-height;
- /* 9 */
- text-align: center;
- /* 10 */
- text-decoration: none;
- @if(mixin-exists(hook-button)) {@include hook-button();}
-}
-
-.uk-button:not(:disabled) { cursor: pointer; }
-
-/*
- * Remove the inner border and padding in Firefox.
- */
-
-.uk-button::-moz-focus-inner {
- border: 0;
- padding: 0;
-}
-
-/* Hover */
-.uk-button:hover {
- /* 8 */
- text-decoration: none;
- @if(mixin-exists(hook-button-hover)) {@include hook-button-hover();}
-}
-
-/* Focus */
-.uk-button:focus {
- outline: none;
- @if(mixin-exists(hook-button-focus)) {@include hook-button-focus();}
-}
-
-/* OnClick + Active */
-.uk-button:active,
-.uk-button.uk-active {
- @if(mixin-exists(hook-button-active)) {@include hook-button-active();}
-}
-
-
-/* Style modifiers
- ========================================================================== */
-
-/*
- * Default
- */
-
-.uk-button-default {
- background-color: $button-default-background;
- color: $button-default-color;
- @if(mixin-exists(hook-button-default)) {@include hook-button-default();}
-}
-
-/* Hover + Focus */
-.uk-button-default:hover,
-.uk-button-default:focus {
- background-color: $button-default-hover-background;
- color: $button-default-hover-color;
- @if(mixin-exists(hook-button-default-hover)) {@include hook-button-default-hover();}
-}
-
-/* OnClick + Active */
-.uk-button-default:active,
-.uk-button-default.uk-active {
- background-color: $button-default-active-background;
- color: $button-default-active-color;
- @if(mixin-exists(hook-button-default-active)) {@include hook-button-default-active();}
-}
-
-/*
- * Primary
- */
-
-.uk-button-primary {
- background-color: $button-primary-background;
- color: $button-primary-color;
- @if(mixin-exists(hook-button-primary)) {@include hook-button-primary();}
-}
-
-/* Hover + Focus */
-.uk-button-primary:hover,
-.uk-button-primary:focus {
- background-color: $button-primary-hover-background;
- color: $button-primary-hover-color;
- @if(mixin-exists(hook-button-primary-hover)) {@include hook-button-primary-hover();}
-}
-
-/* OnClick + Active */
-.uk-button-primary:active,
-.uk-button-primary.uk-active {
- background-color: $button-primary-active-background;
- color: $button-primary-active-color;
- @if(mixin-exists(hook-button-primary-active)) {@include hook-button-primary-active();}
-}
-
-/*
- * Secondary
- */
-
-.uk-button-secondary {
- background-color: $button-secondary-background;
- color: $button-secondary-color;
- @if(mixin-exists(hook-button-secondary)) {@include hook-button-secondary();}
-}
-
-/* Hover + Focus */
-.uk-button-secondary:hover,
-.uk-button-secondary:focus {
- background-color: $button-secondary-hover-background;
- color: $button-secondary-hover-color;
- @if(mixin-exists(hook-button-secondary-hover)) {@include hook-button-secondary-hover();}
-}
-
-/* OnClick + Active */
-.uk-button-secondary:active,
-.uk-button-secondary.uk-active {
- background-color: $button-secondary-active-background;
- color: $button-secondary-active-color;
- @if(mixin-exists(hook-button-secondary-active)) {@include hook-button-secondary-active();}
-}
-
-/*
- * Danger
- */
-
-.uk-button-danger {
- background-color: $button-danger-background;
- color: $button-danger-color;
- @if(mixin-exists(hook-button-danger)) {@include hook-button-danger();}
-}
-
-/* Hover + Focus */
-.uk-button-danger:hover,
-.uk-button-danger:focus {
- background-color: $button-danger-hover-background;
- color: $button-danger-hover-color;
- @if(mixin-exists(hook-button-danger-hover)) {@include hook-button-danger-hover();}
-}
-
-/* OnClick + Active */
-.uk-button-danger:active,
-.uk-button-danger.uk-active {
- background-color: $button-danger-active-background;
- color: $button-danger-active-color;
- @if(mixin-exists(hook-button-danger-active)) {@include hook-button-danger-active();}
-}
-
-/*
- * Disabled
- * The same for all style modifiers
- */
-
-.uk-button-default:disabled,
-.uk-button-primary:disabled,
-.uk-button-secondary:disabled,
-.uk-button-danger:disabled {
- background-color: $button-disabled-background;
- color: $button-disabled-color;
- @if(mixin-exists(hook-button-disabled)) {@include hook-button-disabled();}
-}
-
-
-/* Size modifiers
- ========================================================================== */
-
-.uk-button-small {
- padding: 0 $button-small-padding-horizontal;
- line-height: $button-small-line-height;
- font-size: $button-small-font-size;
- @if(mixin-exists(hook-button-small)) {@include hook-button-small();}
-}
-
-.uk-button-large {
- padding: 0 $button-large-padding-horizontal;
- line-height: $button-large-line-height;
- font-size: $button-large-font-size;
- @if(mixin-exists(hook-button-large)) {@include hook-button-large();}
-}
-
-
-/* Text modifiers
- ========================================================================== */
-
-/*
- * Text
- * 1. Reset
- * 2. Style
- */
-
-.uk-button-text {
- /* 1 */
- padding: 0;
- line-height: $button-text-line-height;
- background: none;
- /* 2 */
- color: $button-text-color;
- @if(mixin-exists(hook-button-text)) {@include hook-button-text();}
-}
-
-/* Hover + Focus */
-.uk-button-text:hover,
-.uk-button-text:focus {
- color: $button-text-hover-color;
- @if(mixin-exists(hook-button-text-hover)) {@include hook-button-text-hover();}
-}
-
-/* Disabled */
-.uk-button-text:disabled {
- color: $button-text-disabled-color;
- @if(mixin-exists(hook-button-text-disabled)) {@include hook-button-text-disabled();}
-}
-
-/*
- * Link
- * 1. Reset
- * 2. Style
- */
-
-.uk-button-link {
- /* 1 */
- padding: 0;
- line-height: $button-link-line-height;
- background: none;
- /* 2 */
- color: $button-link-color;
- @if(mixin-exists(hook-button-link)) {@include hook-button-link();}
-}
-
-/* Hover + Focus */
-.uk-button-link:hover,
-.uk-button-link:focus {
- color: $button-link-hover-color;
- text-decoration: $button-link-hover-text-decoration;
-}
-
-/* Disabled */
-.uk-button-link:disabled {
- color: $button-link-disabled-color;
- text-decoration: none;
-}
-
-
-/* Group
- ========================================================================== */
-
-/*
- * 1. Using `flex` instead of `inline-block` to prevent whitespace betweent child elements
- * 2. Behave like button
- * 3. Create position context
- */
-
-.uk-button-group {
- /* 1 */
- display: inline-flex;
- /* 2 */
- vertical-align: middle;
- /* 3 */
- position: relative;
-}
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-button-misc)) {@include hook-button-misc();}
-
-// @mixin hook-button(){}
-// @mixin hook-button-hover(){}
-// @mixin hook-button-focus(){}
-// @mixin hook-button-active(){}
-// @mixin hook-button-default(){}
-// @mixin hook-button-default-hover(){}
-// @mixin hook-button-default-active(){}
-// @mixin hook-button-primary(){}
-// @mixin hook-button-primary-hover(){}
-// @mixin hook-button-primary-active(){}
-// @mixin hook-button-secondary(){}
-// @mixin hook-button-secondary-hover(){}
-// @mixin hook-button-secondary-active(){}
-// @mixin hook-button-danger(){}
-// @mixin hook-button-danger-hover(){}
-// @mixin hook-button-danger-active(){}
-// @mixin hook-button-disabled(){}
-// @mixin hook-button-small(){}
-// @mixin hook-button-large(){}
-// @mixin hook-button-text(){}
-// @mixin hook-button-text-hover(){}
-// @mixin hook-button-text-disabled(){}
-// @mixin hook-button-link(){}
-// @mixin hook-button-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-$inverse-button-default-background: $inverse-global-primary-background !default;
-$inverse-button-default-color: $inverse-global-inverse-color !default;
-$inverse-button-default-hover-background: darken($inverse-button-default-background, 5%) !default;
-$inverse-button-default-hover-color: $inverse-global-inverse-color !default;
-$inverse-button-default-active-background: darken($inverse-button-default-background, 10%) !default;
-$inverse-button-default-active-color: $inverse-global-inverse-color !default;
-$inverse-button-primary-background: $inverse-global-primary-background !default;
-$inverse-button-primary-color: $inverse-global-inverse-color !default;
-$inverse-button-primary-hover-background: darken($inverse-button-primary-background, 5%) !default;
-$inverse-button-primary-hover-color: $inverse-global-inverse-color !default;
-$inverse-button-primary-active-background: darken($inverse-button-primary-background, 10%) !default;
-$inverse-button-primary-active-color: $inverse-global-inverse-color !default;
-$inverse-button-secondary-background: $inverse-global-primary-background !default;
-$inverse-button-secondary-color: $inverse-global-inverse-color !default;
-$inverse-button-secondary-hover-background: darken($inverse-button-secondary-background, 5%) !default;
-$inverse-button-secondary-hover-color: $inverse-global-inverse-color !default;
-$inverse-button-secondary-active-background: darken($inverse-button-secondary-background, 10%) !default;
-$inverse-button-secondary-active-color: $inverse-global-inverse-color !default;
-$inverse-button-text-color: $inverse-global-muted-color !default;
-$inverse-button-text-hover-color: $inverse-global-color !default;
-$inverse-button-text-disabled-color: $inverse-global-muted-color !default;
-$inverse-button-link-color: $inverse-global-muted-color !default;
-$inverse-button-link-hover-color: $inverse-global-color !default;
-
-
-
-// @mixin hook-inverse-button-default(){}
-// @mixin hook-inverse-button-default-hover(){}
-// @mixin hook-inverse-button-default-active(){}
-// @mixin hook-inverse-button-primary(){}
-// @mixin hook-inverse-button-primary-hover(){}
-// @mixin hook-inverse-button-primary-active(){}
-// @mixin hook-inverse-button-secondary(){}
-// @mixin hook-inverse-button-secondary-hover(){}
-// @mixin hook-inverse-button-secondary-active(){}
-// @mixin hook-inverse-button-text(){}
-// @mixin hook-inverse-button-text-hover(){}
-// @mixin hook-inverse-button-text-disabled(){}
-// @mixin hook-inverse-button-link(){}
diff --git a/_sass/uikit/components/card.scss b/_sass/uikit/components/card.scss
deleted file mode 100644
index e332a03f54..0000000000
--- a/_sass/uikit/components/card.scss
+++ /dev/null
@@ -1,363 +0,0 @@
-// Name: Card
-// Description: Component to create boxed content containers
-//
-// Component: `uk-card`
-//
-// Sub-objects: `uk-card-body`
-// `uk-card-header`
-// `uk-card-footer`
-// `uk-card-media-*`
-// `uk-card-title`
-// `uk-card-badge`
-//
-// Modifiers: `uk-card-hover`
-// `uk-card-default`
-// `uk-card-primary`
-// `uk-card-secondary`
-// `uk-card-small`
-// `uk-card-large`
-//
-// Uses: `uk-grid-stack`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$card-body-padding-horizontal: $global-gutter !default;
-$card-body-padding-vertical: $global-gutter !default;
-
-$card-body-padding-horizontal-l: $global-medium-gutter !default;
-$card-body-padding-vertical-l: $global-medium-gutter !default;
-
-$card-header-padding-horizontal: $global-gutter !default;
-$card-header-padding-vertical: round($global-gutter / 2) !default;
-
-$card-header-padding-horizontal-l: $global-medium-gutter !default;
-$card-header-padding-vertical-l: round($global-medium-gutter / 2) !default;
-
-$card-footer-padding-horizontal: $global-gutter !default;
-$card-footer-padding-vertical: ($global-gutter / 2) !default;
-
-$card-footer-padding-horizontal-l: $global-medium-gutter !default;
-$card-footer-padding-vertical-l: round($global-medium-gutter / 2) !default;
-
-$card-title-font-size: $global-large-font-size !default;
-$card-title-line-height: 1.4 !default;
-
-$card-badge-top: $global-gutter !default;
-$card-badge-right: $card-badge-top !default;
-
-$card-hover-background: $global-muted-background !default;
-
-$card-default-background: $global-muted-background !default;
-$card-default-color: $global-color !default;
-$card-default-title-color: $global-emphasis-color !default;
-$card-default-hover-background: darken($card-default-background, 5%) !default;
-
-$card-primary-background: $global-primary-background !default;
-$card-primary-color: $global-inverse-color !default;
-$card-primary-title-color: $card-primary-color !default;
-$card-primary-hover-background: darken($card-primary-background, 5%) !default;
-$card-primary-color-mode: light !default;
-
-$card-secondary-background: $global-secondary-background !default;
-$card-secondary-color: $global-inverse-color !default;
-$card-secondary-title-color: $card-secondary-color !default;
-$card-secondary-hover-background: darken($card-secondary-background, 5%) !default;
-$card-secondary-color-mode: light !default;
-
-$card-small-body-padding-horizontal: $global-margin !default;
-$card-small-body-padding-vertical: $global-margin !default;
-$card-small-header-padding-horizontal: $global-margin !default;
-$card-small-header-padding-vertical: round($global-margin / 1.5) !default;
-$card-small-footer-padding-horizontal: $global-margin !default;
-$card-small-footer-padding-vertical: round($global-margin / 1.5) !default;
-
-$card-large-body-padding-horizontal-l: $global-large-gutter !default;
-$card-large-body-padding-vertical-l: $global-large-gutter !default;
-$card-large-header-padding-horizontal-l: $global-large-gutter !default;
-$card-large-header-padding-vertical-l: round($global-large-gutter / 2) !default;
-$card-large-footer-padding-horizontal-l: $global-large-gutter !default;
-$card-large-footer-padding-vertical-l: round($global-large-gutter / 2) !default;
-
-
-/* ========================================================================
- Component: Card
- ========================================================================== */
-
-.uk-card {
- position: relative;
- box-sizing: border-box;
- @if(mixin-exists(hook-card)) {@include hook-card();}
-}
-
-
-/* Sections
- ========================================================================== */
-
-.uk-card-body {
- padding: $card-body-padding-vertical $card-body-padding-horizontal;
- @if(mixin-exists(hook-card-body)) {@include hook-card-body();}
-}
-
-.uk-card-header {
- padding: $card-header-padding-vertical $card-header-padding-horizontal;
- @if(mixin-exists(hook-card-header)) {@include hook-card-header();}
-}
-
-.uk-card-footer {
- padding: $card-footer-padding-vertical $card-footer-padding-horizontal;
- @if(mixin-exists(hook-card-footer)) {@include hook-card-footer();}
-}
-
-/* Desktop and bigger */
-@media (min-width: $breakpoint-large) {
-
- .uk-card-body { padding: $card-body-padding-vertical-l $card-body-padding-horizontal-l; }
-
- .uk-card-header { padding: $card-header-padding-vertical-l $card-header-padding-horizontal-l; }
-
- .uk-card-footer { padding: $card-footer-padding-vertical-l $card-footer-padding-horizontal-l; }
-
-}
-
-/*
- * Micro clearfix
- */
-
-.uk-card-body::before,
-.uk-card-body::after,
-.uk-card-header::before,
-.uk-card-header::after,
-.uk-card-footer::before,
-.uk-card-footer::after {
- content: "";
- display: table;
-}
-
-.uk-card-body::after,
-.uk-card-header::after,
-.uk-card-footer::after { clear: both; }
-
-/*
- * Remove margin from the last-child
- */
-
-.uk-card-body > :last-child,
-.uk-card-header > :last-child,
-.uk-card-footer > :last-child { margin-bottom: 0; }
-
-
-/* Media
- ========================================================================== */
-
-/*
- * Reserved alignment modifier to style the media element, e.g. with `border-radius`
- * Implemented by the theme
- */
-
-[class*='uk-card-media'] {
- @if(mixin-exists(hook-card-media)) {@include hook-card-media();}
-}
-
-.uk-card-media-top,
-.uk-grid-stack > .uk-card-media-left,
-.uk-grid-stack > .uk-card-media-right {
- @if(mixin-exists(hook-card-media-top)) {@include hook-card-media-top();}
-}
-
-.uk-card-media-bottom {
- @if(mixin-exists(hook-card-media-bottom)) {@include hook-card-media-bottom();}
-}
-
-:not(.uk-grid-stack) > .uk-card-media-left {
- @if(mixin-exists(hook-card-media-left)) {@include hook-card-media-left();}
-}
-
-:not(.uk-grid-stack) > .uk-card-media-right {
- @if(mixin-exists(hook-card-media-right)) {@include hook-card-media-right();}
-}
-
-
-/* Title
- ========================================================================== */
-
-.uk-card-title {
- font-size: $card-title-font-size;
- line-height: $card-title-line-height;
- @if(mixin-exists(hook-card-title)) {@include hook-card-title();}
-}
-
-
-/* Badge
- ========================================================================== */
-
-.uk-card-badge {
- position: absolute;
- top: $card-badge-top;
- right: $card-badge-right;
- z-index: 1;
- @if(mixin-exists(hook-card-badge)) {@include hook-card-badge();}
-}
-
-/*
- * Remove margin from adjacent element
- */
-
-.uk-card-badge:first-child + * { margin-top: 0; }
-
-
-/* Hover modifier
- ========================================================================== */
-
-.uk-card-hover:not(.uk-card-default):not(.uk-card-primary):not(.uk-card-secondary):hover {
- background: $card-hover-background;
- @if(mixin-exists(hook-card-hover)) {@include hook-card-hover();}
-}
-
-
-/* Style modifiers
- ========================================================================== */
-
-/*
- * Default
- * Note: Header and Footer are only implemented for the default style
- */
-
-.uk-card-default {
- background: $card-default-background;
- color: $card-default-color;
- @if(mixin-exists(hook-card-default)) {@include hook-card-default();}
-}
-
-.uk-card-default .uk-card-title {
- color: $card-default-title-color;
- @if(mixin-exists(hook-card-default-title)) {@include hook-card-default-title();}
-}
-
-.uk-card-default.uk-card-hover:hover {
- background-color: $card-default-hover-background;
- @if(mixin-exists(hook-card-default-hover)) {@include hook-card-default-hover();}
-}
-
-.uk-card-default .uk-card-header {
- @if(mixin-exists(hook-card-default-header)) {@include hook-card-default-header();}
-}
-
-.uk-card-default .uk-card-footer {
- @if(mixin-exists(hook-card-default-footer)) {@include hook-card-default-footer();}
-}
-
-/*
- * Primary
- */
-
-.uk-card-primary {
- background: $card-primary-background;
- color: $card-primary-color;
- @if(mixin-exists(hook-card-primary)) {@include hook-card-primary();}
-}
-
-.uk-card-primary .uk-card-title {
- color: $card-primary-title-color;
- @if(mixin-exists(hook-card-primary-title)) {@include hook-card-primary-title();}
-}
-
-.uk-card-primary.uk-card-hover:hover {
- background-color: $card-primary-hover-background;
- @if(mixin-exists(hook-card-primary-hover)) {@include hook-card-primary-hover();}
-}
-
-// Color Mode
-@if ( $card-primary-color-mode == light ) { .uk-card-primary.uk-card-body { @extend .uk-light !optional;} }
-@if ( $card-primary-color-mode == light ) { .uk-card-primary > :not([class*='uk-card-media']) { @extend .uk-light !optional;} }
-@if ( $card-primary-color-mode == dark ) { .uk-card-primary.uk-card-body { @extend .uk-dark !optional;} }
-@if ( $card-primary-color-mode == dark ) { .uk-card-primary > :not([class*='uk-card-media']) { @extend .uk-dark !optional;} }
-
-/*
- * Secondary
- */
-
-.uk-card-secondary {
- background: $card-secondary-background;
- color: $card-secondary-color;
- @if(mixin-exists(hook-card-secondary)) {@include hook-card-secondary();}
-}
-
-.uk-card-secondary .uk-card-title {
- color: $card-secondary-title-color;
- @if(mixin-exists(hook-card-secondary-title)) {@include hook-card-secondary-title();}
-}
-
-.uk-card-secondary.uk-card-hover:hover {
- background-color: $card-secondary-hover-background;
- @if(mixin-exists(hook-card-secondary-hover)) {@include hook-card-secondary-hover();}
-}
-
-// Color Mode
-@if ( $card-secondary-color-mode == light ) { .uk-card-secondary.uk-card-body { @extend .uk-light !optional;} }
-@if ( $card-secondary-color-mode == light ) { .uk-card-secondary > :not([class*='uk-card-media']) { @extend .uk-light !optional;} }
-@if ( $card-secondary-color-mode == dark ) { .uk-card-secondary.uk-card-body { @extend .uk-dark !optional;} }
-@if ( $card-secondary-color-mode == dark ) { .uk-card-secondary > :not([class*='uk-card-media']) { @extend .uk-dark !optional;} }
-
-
-/* Size modifier
- ========================================================================== */
-
-/*
- * Small
- */
-
-.uk-card-small.uk-card-body,
-.uk-card-small .uk-card-body { padding: $card-small-body-padding-vertical $card-small-body-padding-horizontal; }
-
-.uk-card-small .uk-card-header { padding: $card-small-header-padding-vertical $card-small-header-padding-horizontal; }
-.uk-card-small .uk-card-footer { padding: $card-small-footer-padding-vertical $card-small-footer-padding-horizontal; }
-
-/*
- * Large
- */
-
-/* Desktop and bigger */
-@media (min-width: $breakpoint-large) {
-
- .uk-card-large.uk-card-body,
- .uk-card-large .uk-card-body { padding: $card-large-body-padding-vertical-l $card-large-body-padding-horizontal-l; }
-
- .uk-card-large .uk-card-header { padding: $card-large-header-padding-vertical-l $card-large-header-padding-horizontal-l; }
- .uk-card-large .uk-card-footer { padding: $card-large-footer-padding-vertical-l $card-large-footer-padding-horizontal-l; }
-
-}
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-card-misc)) {@include hook-card-misc();}
-
-// @mixin hook-card(){}
-// @mixin hook-card-body(){}
-// @mixin hook-card-header(){}
-// @mixin hook-card-footer(){}
-// @mixin hook-card-media(){}
-// @mixin hook-card-media-top(){}
-// @mixin hook-card-media-bottom(){}
-// @mixin hook-card-media-left(){}
-// @mixin hook-card-media-right(){}
-// @mixin hook-card-title(){}
-// @mixin hook-card-badge(){}
-// @mixin hook-card-hover(){}
-// @mixin hook-card-default(){}
-// @mixin hook-card-default-title(){}
-// @mixin hook-card-default-hover(){}
-// @mixin hook-card-default-header(){}
-// @mixin hook-card-default-footer(){}
-// @mixin hook-card-primary(){}
-// @mixin hook-card-primary-title(){}
-// @mixin hook-card-primary-hover(){}
-// @mixin hook-card-secondary(){}
-// @mixin hook-card-secondary-title(){}
-// @mixin hook-card-secondary-hover(){}
-// @mixin hook-card-misc(){}
diff --git a/_sass/uikit/components/close.scss b/_sass/uikit/components/close.scss
deleted file mode 100644
index 32e2775642..0000000000
--- a/_sass/uikit/components/close.scss
+++ /dev/null
@@ -1,57 +0,0 @@
-// Name: Close
-// Description: Component to create a close button
-//
-// Component: `uk-close`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$close-color: $global-muted-color !default;
-$close-hover-color: $global-color !default;
-
-
-/* ========================================================================
- Component: Close
- ========================================================================== */
-
-/*
- * Adopts `uk-icon`
- */
-
-.uk-close {
- color: $close-color;
- @if(mixin-exists(hook-close)) {@include hook-close();}
-}
-
-/* Hover + Focus */
-.uk-close:hover,
-.uk-close:focus {
- color: $close-hover-color;
- outline: none;
- @if(mixin-exists(hook-close-hover)) {@include hook-close-hover();}
-}
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-close-misc)) {@include hook-close-misc();}
-
-// @mixin hook-close(){}
-// @mixin hook-close-hover(){}
-// @mixin hook-close-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-$inverse-close-color: $inverse-global-muted-color !default;
-$inverse-close-hover-color: $inverse-global-color !default;
-
-
-
-// @mixin hook-inverse-close(){}
-// @mixin hook-inverse-close-hover(){}
diff --git a/_sass/uikit/components/column.scss b/_sass/uikit/components/column.scss
deleted file mode 100644
index 54bae26e37..0000000000
--- a/_sass/uikit/components/column.scss
+++ /dev/null
@@ -1,138 +0,0 @@
-// Name: Column
-// Description: Utilities for text columns
-//
-// Component: `uk-column-*`
-//
-// Sub-objects: `uk-column-span`
-//
-// Modifiers: `uk-column-divider`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$column-gutter: $global-gutter !default;
-$column-gutter-l: $global-medium-gutter !default;
-
-$column-divider-rule-color: $global-border !default;
-$column-divider-rule-width: 1px !default;
-
-
-/* ========================================================================
- Component: Column
- ========================================================================== */
-
-[class*='uk-column-'] { column-gap: $column-gutter; }
-
-/* Desktop and bigger */
-@media (min-width: $breakpoint-large) {
-
- [class*='uk-column-'] { column-gap: $column-gutter-l; }
-
-}
-
-/*
- * Fix image 1px line wrapping into the next column in Chrome
- */
-
-[class*='uk-column-'] img { transform: translate3d(0,0,0); }
-
-
-/* Divider
- ========================================================================== */
-
-/*
- * 1. Double the column gap
- */
-
-.uk-column-divider {
- column-rule: $column-divider-rule-width solid $column-divider-rule-color;
- /* 1 */
- column-gap: ($column-gutter * 2);
-}
-
-/* Desktop and bigger */
-@media (min-width: $breakpoint-large) {
-
- .uk-column-divider {
- column-gap: ($column-gutter-l * 2);
- }
-
-}
-
-
-/* Width modifiers
- ========================================================================== */
-
-.uk-column-1-2 { column-count: 2;}
-.uk-column-1-3 { column-count: 3; }
-.uk-column-1-4 { column-count: 4; }
-.uk-column-1-5 { column-count: 5; }
-.uk-column-1-6 { column-count: 6; }
-
-/* Phone landscape and bigger */
-@media (min-width: $breakpoint-small) {
-
- .uk-column-1-2\@s { column-count: 2; }
- .uk-column-1-3\@s { column-count: 3; }
- .uk-column-1-4\@s { column-count: 4; }
- .uk-column-1-5\@s { column-count: 5; }
- .uk-column-1-6\@s { column-count: 6; }
-
-}
-
-/* Tablet landscape and bigger */
-@media (min-width: $breakpoint-medium) {
-
- .uk-column-1-2\@m { column-count: 2; }
- .uk-column-1-3\@m { column-count: 3; }
- .uk-column-1-4\@m { column-count: 4; }
- .uk-column-1-5\@m { column-count: 5; }
- .uk-column-1-6\@m { column-count: 6; }
-
-}
-
-/* Desktop and bigger */
-@media (min-width: $breakpoint-large) {
-
- .uk-column-1-2\@l { column-count: 2; }
- .uk-column-1-3\@l { column-count: 3; }
- .uk-column-1-4\@l { column-count: 4; }
- .uk-column-1-5\@l { column-count: 5; }
- .uk-column-1-6\@l { column-count: 6; }
-
-}
-
-/* Large screen and bigger */
-@media (min-width: $breakpoint-xlarge) {
-
- .uk-column-1-2\@xl { column-count: 2; }
- .uk-column-1-3\@xl { column-count: 3; }
- .uk-column-1-4\@xl { column-count: 4; }
- .uk-column-1-5\@xl { column-count: 5; }
- .uk-column-1-6\@xl { column-count: 6; }
-
-}
-
-/* Make element span across all columns
- * Does not work in Firefox yet
- ========================================================================== */
-
-.uk-column-span { column-span: all; }
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-column-misc)) {@include hook-column-misc();}
-
-// @mixin hook-column-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-$inverse-column-divider-rule-color: $inverse-global-border !default;
-
diff --git a/_sass/uikit/components/comment.scss b/_sass/uikit/components/comment.scss
deleted file mode 100644
index 8583dd8a0d..0000000000
--- a/_sass/uikit/components/comment.scss
+++ /dev/null
@@ -1,171 +0,0 @@
-// Name: Comment
-// Description: Component to create nested comments
-//
-// Component: `uk-comment`
-//
-// Sub-objects: `uk-comment-body`
-// `uk-comment-header`
-// `uk-comment-title`
-// `uk-comment-meta`
-// `uk-comment-avatar`
-// `uk-comment-list`
-//
-// Modifier: `uk-comment-primary`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$comment-header-margin-bottom: $global-margin !default;
-
-$comment-title-font-size: $global-medium-font-size !default;
-$comment-title-line-height: 1.4 !default;
-
-$comment-meta-font-size: $global-small-font-size !default;
-$comment-meta-line-height: 1.4 !default;
-$comment-meta-color: $global-muted-color !default;
-
-$comment-list-margin-top: $global-large-margin !default;
-$comment-list-padding-left: 30px !default;
-$comment-list-padding-left-m: 100px !default;
-
-
-/* ========================================================================
- Component: Comment
- ========================================================================== */
-
-.uk-comment {
- @if(mixin-exists(hook-comment)) {@include hook-comment();}
-}
-
-
-/* Sections
- ========================================================================== */
-
-.uk-comment-body {
- @if(mixin-exists(hook-comment-body)) {@include hook-comment-body();}
-}
-
-.uk-comment-header {
- margin-bottom: $comment-header-margin-bottom;
- @if(mixin-exists(hook-comment-header)) {@include hook-comment-header();}
-}
-
-/*
- * Micro clearfix
- */
-
-.uk-comment-body::before,
-.uk-comment-body::after,
-.uk-comment-header::before,
-.uk-comment-header::after {
- content: "";
- display: table;
-}
-
-.uk-comment-body::after,
-.uk-comment-header::after { clear: both; }
-
-/*
- * Remove margin from the last-child
- */
-
-.uk-comment-body > :last-child,
-.uk-comment-header > :last-child { margin-bottom: 0; }
-
-
-/* Title
- ========================================================================== */
-
-.uk-comment-title {
- font-size: $comment-title-font-size;
- line-height: $comment-title-line-height;
- @if(mixin-exists(hook-comment-title)) {@include hook-comment-title();}
-}
-
-
-/* Meta
- ========================================================================== */
-
-.uk-comment-meta {
- font-size: $comment-meta-font-size;
- line-height: $comment-meta-line-height;
- color: $comment-meta-color;
- @if(mixin-exists(hook-comment-meta)) {@include hook-comment-meta();}
-}
-
-
-/* Avatar
- ========================================================================== */
-
-.uk-comment-avatar {
- @if(mixin-exists(hook-comment-avatar)) {@include hook-comment-avatar();}
-}
-
-
-/* List
- ========================================================================== */
-
-.uk-comment-list {
- padding: 0;
- list-style: none;
-}
-
-/* Adjacent siblings */
-.uk-comment-list > :nth-child(n+2) {
- margin-top: $comment-list-margin-top;
- @if(mixin-exists(hook-comment-list-adjacent)) {@include hook-comment-list-adjacent();}
-}
-
-/*
- * Sublists
- * Note: General sibling selector allows reply block between comment and sublist
- */
-
-.uk-comment-list .uk-comment ~ ul {
- margin: $comment-list-margin-top 0 0 0;
- padding-left: $comment-list-padding-left;
- list-style: none;
- @if(mixin-exists(hook-comment-list-sub)) {@include hook-comment-list-sub();}
-}
-
-/* Tablet and bigger */
-@media (min-width: $breakpoint-medium) {
-
- .uk-comment-list .uk-comment ~ ul { padding-left: $comment-list-padding-left-m; }
-
-}
-
-/* Adjacent siblings */
-.uk-comment-list .uk-comment ~ ul > :nth-child(n+2) {
- margin-top: $comment-list-margin-top;
- @if(mixin-exists(hook-comment-list-sub-adjacent)) {@include hook-comment-list-sub-adjacent();}
-}
-
-
-/* Style modifier
- ========================================================================== */
-
-.uk-comment-primary {
- @if(mixin-exists(hook-comment-primary)) {@include hook-comment-primary();}
-}
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-comment-misc)) {@include hook-comment-misc();}
-
-// @mixin hook-comment(){}
-// @mixin hook-comment-body(){}
-// @mixin hook-comment-header(){}
-// @mixin hook-comment-title(){}
-// @mixin hook-comment-meta(){}
-// @mixin hook-comment-avatar(){}
-// @mixin hook-comment-list-adjacent(){}
-// @mixin hook-comment-list-sub(){}
-// @mixin hook-comment-list-sub-adjacent(){}
-// @mixin hook-comment-primary(){}
-// @mixin hook-comment-misc(){}
\ No newline at end of file
diff --git a/_sass/uikit/components/container.scss b/_sass/uikit/components/container.scss
deleted file mode 100644
index c518d6d7f6..0000000000
--- a/_sass/uikit/components/container.scss
+++ /dev/null
@@ -1,106 +0,0 @@
-// Name: Container
-// Description: Component to align and center your site and grid content
-//
-// Component: `uk-container`
-//
-// Modifier: `uk-container-small`
-// `uk-container-large`
-// `uk-container-expand`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$container-max-width: 1200px !default;
-$container-small-max-width: 900px !default;
-$container-large-max-width: 1600px !default;
-
-$container-padding-horizontal: 15px !default;
-$container-padding-horizontal-s: $global-gutter !default;
-$container-padding-horizontal-m: $global-medium-gutter !default;
-
-
-/* ========================================================================
- Component: Container
- ========================================================================== */
-
-/*
- * 1. Box sizing has to be `content-box` so the max-width is always the same and
- * unaffected by the padding on different breakpoints. It's important for the size modifiers.
- */
-
-.uk-container {
- box-sizing: content-box; /* 1 */
- max-width: $container-max-width;
- margin-left: auto;
- margin-right: auto;
- padding-left: $container-padding-horizontal;
- padding-right: $container-padding-horizontal;
-}
-
-/* Phone landscape and bigger */
-@media (min-width: $breakpoint-small) {
-
- .uk-container {
- padding-left: $container-padding-horizontal-s;
- padding-right: $container-padding-horizontal-s;
- }
-
-}
-
-/* Tablet landscape and bigger */
-@media (min-width: $breakpoint-medium) {
-
- .uk-container {
- padding-left: $container-padding-horizontal-m;
- padding-right: $container-padding-horizontal-m;
- }
-
-}
-
-/*
- * Micro clearfix
- */
-
-.uk-container::before,
-.uk-container::after {
- content: "";
- display: table;
-}
-
-.uk-container::after { clear: both; }
-
-/*
- * Remove margin from the last-child
- */
-
-.uk-container > :last-child { margin-bottom: 0; }
-
-/*
- * Remove padding from nested containers
- */
-
-.uk-container .uk-container {
- padding-left: 0;
- padding-right: 0;
-}
-
-
-/* Size modifier
- ========================================================================== */
-
-.uk-container-small { max-width: $container-small-max-width; }
-
-.uk-container-large { max-width: $container-large-max-width; }
-
-.uk-container-expand { max-width: none; }
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-container-misc)) {@include hook-container-misc();}
-
-// @mixin hook-container-misc(){}
\ No newline at end of file
diff --git a/_sass/uikit/components/countdown.scss b/_sass/uikit/components/countdown.scss
deleted file mode 100644
index 3f53e70c71..0000000000
--- a/_sass/uikit/components/countdown.scss
+++ /dev/null
@@ -1,126 +0,0 @@
-// Name: Countdown
-// Description: Component to create countdown timers
-//
-// Component: `uk-countdown`
-//
-// Sub-objects: `uk-countdown-number`
-// `uk-countdown-separator`
-// `uk-countdown-label`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$countdown-item-line-height: 70px !default;
-
-$countdown-number-font-size: 2rem !default; // 32px
-$countdown-number-font-size-s: 4rem !default; // 64px
-$countdown-number-font-size-m: 6rem !default; // 96px
-
-$countdown-separator-font-size: 1rem !default; // 16px
-$countdown-separator-font-size-s: 2rem !default; // 32px
-$countdown-separator-font-size-m: 3rem !default; // 48px
-
-
-/* ========================================================================
- Component: Countdown
- ========================================================================== */
-
-.uk-countdown {
- @if(mixin-exists(hook-countdown)) {@include hook-countdown();}
-}
-
-
-/* Item
- ========================================================================== */
-
-/*
- * 1. Center numbers and separators vertically
- */
-
-.uk-countdown-number,
-.uk-countdown-separator {
- /* 1 */
- line-height: $countdown-item-line-height;
- @if(mixin-exists(hook-countdown-item)) {@include hook-countdown-item();}
-}
-
-
-/* Number
- ========================================================================== */
-
-.uk-countdown-number {
- font-size: $countdown-number-font-size;
- @if(mixin-exists(hook-countdown-number)) {@include hook-countdown-number();}
-}
-
-/* Phone landscape and bigger */
-@media (min-width: $breakpoint-small) {
-
- .uk-countdown-number { font-size: $countdown-number-font-size-s; }
-
-}
-
-/* Tablet landscape and bigger */
-@media (min-width: $breakpoint-medium) {
-
- .uk-countdown-number { font-size: $countdown-number-font-size-m; }
-
-}
-
-
-/* Separator
- ========================================================================== */
-
-.uk-countdown-separator {
- font-size: $countdown-separator-font-size;
- @if(mixin-exists(hook-countdown-separator)) {@include hook-countdown-separator();}
-}
-
-/* Phone landscape and bigger */
-@media (min-width: $breakpoint-small) {
-
- .uk-countdown-separator { font-size: $countdown-separator-font-size-s; }
-
-}
-
-/* Tablet landscape and bigger */
-@media (min-width: $breakpoint-medium) {
-
- .uk-countdown-separator { font-size: $countdown-separator-font-size-m; }
-
-}
-
-
-/* Label
- ========================================================================== */
-
-.uk-countdown-label {
- @if(mixin-exists(hook-countdown-label)) {@include hook-countdown-label();}
-}
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-countdown-misc)) {@include hook-countdown-misc();}
-
-// @mixin hook-countdown(){}
-// @mixin hook-countdown-item(){}
-// @mixin hook-countdown-number(){}
-// @mixin hook-countdown-separator(){}
-// @mixin hook-countdown-label(){}
-// @mixin hook-countdown-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-
-
-// @mixin hook-inverse-countdown-item(){}
-// @mixin hook-inverse-countdown-number(){}
-// @mixin hook-inverse-countdown-separator(){}
-// @mixin hook-inverse-countdown-label(){}
diff --git a/_sass/uikit/components/cover.scss b/_sass/uikit/components/cover.scss
deleted file mode 100644
index b44a6847d5..0000000000
--- a/_sass/uikit/components/cover.scss
+++ /dev/null
@@ -1,57 +0,0 @@
-// Name: Cover
-// Description: Utilities to let embedded content cover their container in a centered position
-//
-// Component: `uk-cover`
-//
-// Sub-object: `uk-cover-container`
-//
-// ========================================================================
-
-
-/* ========================================================================
- Component: Cover
- ========================================================================== */
-
-/*
- * Works with iframes and embedded content
- * 1. Reset responsiveness for embedded content
- * 2. Center object
- * Note: Percent values on the `top` property only works if this element
- * is absolute positioned or if the container has a height
- */
-
-.uk-cover {
- /* 1 */
- max-width: none;
- /* 2 */
- position: absolute;
- left: 50%;
- top: 50%;
- transform: translate(-50%,-50%);
-}
-
-iframe.uk-cover { pointer-events: none; }
-
-
-/* Container
- ========================================================================== */
-
-/*
- * 1. Parent container which clips resized object
- * 2. Needed if the child is positioned absolute. See note above
- */
-
-.uk-cover-container {
- /* 1 */
- overflow: hidden;
- /* 2 */
- position: relative;
-}
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-cover-misc)) {@include hook-cover-misc();}
-
-// @mixin hook-cover-misc(){}
\ No newline at end of file
diff --git a/_sass/uikit/components/description-list.scss b/_sass/uikit/components/description-list.scss
deleted file mode 100644
index 6683286dfd..0000000000
--- a/_sass/uikit/components/description-list.scss
+++ /dev/null
@@ -1,71 +0,0 @@
-// Name: Description list
-// Description: Styles for description lists
-//
-// Component: `uk-description-list`
-//
-// Modifiers: `uk-description-list-divider`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$description-list-term-color: $global-emphasis-color !default;
-$description-list-term-margin-top: $global-margin !default;
-
-$description-list-divider-term-margin-top: $global-margin !default;
-$description-list-divider-term-border-width: $global-border-width !default;
-$description-list-divider-term-border: $global-border !default;
-
-
-/* ========================================================================
- Component: Description list
- ========================================================================== */
-
-/*
- * Term
- */
-
-.uk-description-list > dt {
- color: $description-list-term-color;
- @if(mixin-exists(hook-description-list-term)) {@include hook-description-list-term();}
-}
-
-.uk-description-list > dt:nth-child(n+2) {
- margin-top: $description-list-term-margin-top;
-}
-
-/*
- * Description
- */
-
-.uk-description-list > dd {
- @if(mixin-exists(hook-description-list-description)) {@include hook-description-list-description();}
-}
-
-
-/* Style modifier
- ========================================================================== */
-
-/*
- * Line
- */
-
-.uk-description-list-divider > dt:nth-child(n+2) {
- margin-top: $description-list-divider-term-margin-top;
- padding-top: $description-list-divider-term-margin-top;
- border-top: $description-list-divider-term-border-width solid $description-list-divider-term-border;
- @if(mixin-exists(hook-description-list-divider-term)) {@include hook-description-list-divider-term();}
-}
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-description-list-misc)) {@include hook-description-list-misc();}
-
-// @mixin hook-description-list-term(){}
-// @mixin hook-description-list-description(){}
-// @mixin hook-description-list-divider-term(){}
-// @mixin hook-description-list-misc(){}
\ No newline at end of file
diff --git a/_sass/uikit/components/divider.scss b/_sass/uikit/components/divider.scss
deleted file mode 100644
index b51708cf43..0000000000
--- a/_sass/uikit/components/divider.scss
+++ /dev/null
@@ -1,129 +0,0 @@
-// Name: Divider
-// Description: Styles for dividers
-//
-// Component: `uk-divider-icon`
-// `uk-divider-small`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$divider-margin-vertical: $global-margin !default;
-
-$divider-icon-width: 50px !default;
-$divider-icon-height: 20px !default;
-$divider-icon-color: $global-border !default;
-$divider-icon-line-top: 50% !default;
-$divider-icon-line-width: 100% !default;
-$divider-icon-line-border-width: $global-border-width !default;
-$divider-icon-line-border: $global-border !default;
-
-$internal-divider-icon-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2220%22%20height%3D%2220%22%20viewBox%3D%220%200%2020%2020%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Ccircle%20fill%3D%22none%22%20stroke%3D%22#000%22%20stroke-width%3D%222%22%20cx%3D%2210%22%20cy%3D%2210%22%20r%3D%227%22%20%2F%3E%0A%3C%2Fsvg%3E%0A" !default;
-
-$divider-small-width: 100px !default;
-$divider-small-border-width: $global-border-width !default;
-$divider-small-border: $global-border !default;
-
-
-/* ========================================================================
- Component: Divider
- ========================================================================== */
-
-/*
- * 1. Reset default `hr`
- * 2. Set margin if a `div` is used for semantical reason
- */
-
-[class*='uk-divider'] {
- /* 1 */
- border: none;
- /* 2 */
- margin-bottom: $divider-margin-vertical;
-}
-
-/* Add margin if adjacent element */
-* + [class*='uk-divider'] { margin-top: $divider-margin-vertical; }
-
-
-/* Icon
- ========================================================================== */
-
-.uk-divider-icon {
- position: relative;
- height: $divider-icon-height;
- @include svg-fill($internal-divider-icon-image, "#000", $divider-icon-color);
- background-repeat: no-repeat;
- background-position: 50% 50%;
- @if(mixin-exists(hook-divider-icon)) {@include hook-divider-icon();}
-}
-
-.uk-divider-icon::before,
-.uk-divider-icon::after {
- content: "";
- position: absolute;
- top: $divider-icon-line-top;
- max-width: unquote('calc(50% - (#{$divider-icon-width} / 2))');
- border-bottom: $divider-icon-line-border-width solid $divider-icon-line-border;
- @if(mixin-exists(hook-divider-icon-line)) {@include hook-divider-icon-line();}
-}
-
-.uk-divider-icon::before {
- right: unquote('calc(50% + (#{$divider-icon-width} / 2))');
- width: $divider-icon-line-width;
- @if(mixin-exists(hook-divider-icon-line-left)) {@include hook-divider-icon-line-left();}
-}
-
-.uk-divider-icon::after {
- left: unquote('calc(50% + (#{$divider-icon-width} / 2))');
- width: $divider-icon-line-width;
- @if(mixin-exists(hook-divider-icon-line-right)) {@include hook-divider-icon-line-right();}
-}
-
-
-/* Small
- ========================================================================== */
-
-/*
- * Reset child height, caused by `inline-block`
- */
-
-.uk-divider-small { line-height: 0; }
-
-.uk-divider-small::after {
- content: "";
- display: inline-block;
- width: $divider-small-width;
- max-width: 100%;
- border-top: $divider-small-border-width solid $divider-small-border;
- vertical-align: top;
- @if(mixin-exists(hook-divider-small)) {@include hook-divider-small();}
-}
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-divider-misc)) {@include hook-divider-misc();}
-
-// @mixin hook-divider-icon(){}
-// @mixin hook-divider-icon-line(){}
-// @mixin hook-divider-icon-line-left(){}
-// @mixin hook-divider-icon-line-right(){}
-// @mixin hook-divider-small(){}
-// @mixin hook-divider-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-$inverse-divider-icon-color: $inverse-global-border !default;
-$inverse-divider-icon-line-border: $inverse-global-border !default;
-$inverse-divider-small-border: $inverse-global-border !default;
-
-
-
-// @mixin hook-inverse-divider-icon(){}
-// @mixin hook-inverse-divider-icon-line(){}
-// @mixin hook-inverse-divider-small(){}
diff --git a/_sass/uikit/components/dotnav.scss b/_sass/uikit/components/dotnav.scss
deleted file mode 100644
index f1f2a4029c..0000000000
--- a/_sass/uikit/components/dotnav.scss
+++ /dev/null
@@ -1,157 +0,0 @@
-// Name: Dotnav
-// Description: Component to create dot navigations
-//
-// Component: `uk-dotnav`
-//
-// Modifier: `uk-dotnav-vertical`
-//
-// States: `uk-active`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$dotnav-margin-horizontal: 12px !default;
-$dotnav-margin-vertical: $dotnav-margin-horizontal !default;
-
-$dotnav-item-width: 10px !default;
-$dotnav-item-height: $dotnav-item-width !default;
-$dotnav-item-border-radius: 50% !default;
-
-$dotnav-item-background: rgba($global-color, 0.2) !default;
-$dotnav-item-hover-background: rgba($global-color, 0.6) !default;
-$dotnav-item-onclick-background: rgba($global-color, 0.2) !default;
-$dotnav-item-active-background: rgba($global-color, 0.6) !default;
-
-
-/* ========================================================================
- Component: Dotnav
- ========================================================================== */
-
-/*
- * 1. Allow items to wrap into the next line
- * 2. Reset list
- * 3. Gutter
- */
-
-.uk-dotnav {
- display: flex;
- /* 1 */
- flex-wrap: wrap;
- /* 2 */
- margin: 0;
- padding: 0;
- list-style: none;
- /* 3 */
- margin-left: (-$dotnav-margin-horizontal);
- @if(mixin-exists(hook-dotnav)) {@include hook-dotnav();}
-}
-
-/*
- * 1. Space is allocated solely based on content dimensions: 0 0 auto
- * 2. Gutter
- */
-
-.uk-dotnav > * {
- /* 1 */
- flex: none;
- /* 2 */
- padding-left: $dotnav-margin-horizontal;
-}
-
-
-/* Items
- ========================================================================== */
-
-/*
- * Items
- * 1. Hide text if present
- */
-
-.uk-dotnav > * > * {
- display: block;
- box-sizing: border-box;
- width: $dotnav-item-width;
- height: $dotnav-item-height;
- border-radius: $dotnav-item-border-radius;
- background: $dotnav-item-background;
- /* 1 */
- text-indent: 100%;
- overflow: hidden;
- white-space: nowrap;
- @if(mixin-exists(hook-dotnav-item)) {@include hook-dotnav-item();}
-}
-
-/* Hover + Focus */
-.uk-dotnav > * > :hover,
-.uk-dotnav > * > :focus {
- background-color: $dotnav-item-hover-background;
- outline: none;
- @if(mixin-exists(hook-dotnav-item-hover)) {@include hook-dotnav-item-hover();}
-}
-
-/* OnClick */
-.uk-dotnav > * > :active {
- background-color: $dotnav-item-onclick-background;
- @if(mixin-exists(hook-dotnav-item-onclick)) {@include hook-dotnav-item-onclick();}
-}
-
-/* Active */
-.uk-dotnav > .uk-active > * {
- background-color: $dotnav-item-active-background;
- @if(mixin-exists(hook-dotnav-item-active)) {@include hook-dotnav-item-active();}
-}
-
-
-/* Modifier: 'uk-dotnav-vertical'
- ========================================================================== */
-
-/*
- * 1. Change direction
- * 2. Gutter
- */
-
-.uk-dotnav-vertical {
- /* 1 */
- flex-direction: column;
- /* 2 */
- margin-left: 0;
- margin-top: (-$dotnav-margin-vertical);
-}
-
-/* 2 */
-.uk-dotnav-vertical > * {
- padding-left: 0;
- padding-top: $dotnav-margin-vertical;
-}
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-dotnav-misc)) {@include hook-dotnav-misc();}
-
-// @mixin hook-dotnav(){}
-// @mixin hook-dotnav-item(){}
-// @mixin hook-dotnav-item-hover(){}
-// @mixin hook-dotnav-item-onclick(){}
-// @mixin hook-dotnav-item-active(){}
-// @mixin hook-dotnav-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-$inverse-dotnav-item-background: rgba($inverse-global-color, 0.5) !default;
-$inverse-dotnav-item-hover-background: rgba($inverse-global-color, 0.9) !default;
-$inverse-dotnav-item-onclick-background: rgba($inverse-global-color, 0.5) !default;
-$inverse-dotnav-item-active-background: rgba($inverse-global-color, 0.9) !default;
-
-
-
-// @mixin hook-inverse-dotnav-item(){}
-// @mixin hook-inverse-dotnav-item-hover(){}
-// @mixin hook-inverse-dotnav-item-onclick(){}
-// @mixin hook-inverse-dotnav-item-active(){}
\ No newline at end of file
diff --git a/_sass/uikit/components/drop.scss b/_sass/uikit/components/drop.scss
deleted file mode 100644
index fb5e9e8c5a..0000000000
--- a/_sass/uikit/components/drop.scss
+++ /dev/null
@@ -1,74 +0,0 @@
-// Name: Drop
-// Description: Component to position any element next to any other element.
-//
-// Component: `uk-drop`
-//
-// Modifiers: `uk-drop-top-*`
-// `uk-drop-bottom-*`
-// `uk-drop-left-*`
-// `uk-drop-right-*`
-// `uk-drop-stack`
-// `uk-drop-grid`
-//
-// States: `uk-open`
-//
-// Uses: Animation
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$drop-z-index: $global-z-index + 20 !default;
-$drop-width: 300px !default;
-$drop-margin: $global-margin !default;
-
-
-/* ========================================================================
- Component: Drop
- ========================================================================== */
-
-/*
- * 1. Hide by default
- * 2. Set position
- * 3. Set a default width
- */
-
-.uk-drop {
- /* 1 */
- display: none;
- /* 2 */
- position: absolute;
- z-index: $drop-z-index;
- /* 3 */
- box-sizing: border-box;
- width: $drop-width;
-}
-
-/* Show */
-.uk-drop.uk-open { display: block; }
-
-
-/* Direction / Alignment modifiers
- ========================================================================== */
-
-/* Direction */
-[class*='uk-drop-top'] { margin-top: (-$drop-margin); }
-[class*='uk-drop-bottom'] { margin-top: $drop-margin; }
-[class*='uk-drop-left'] { margin-left: (-$drop-margin); }
-[class*='uk-drop-right'] { margin-left: $drop-margin; }
-
-
-/* Grid modifiers
- ========================================================================== */
-
-.uk-drop-stack .uk-drop-grid > * { width: 100% !important; }
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-drop-misc)) {@include hook-drop-misc();}
-
-// @mixin hook-drop-misc(){}
diff --git a/_sass/uikit/components/dropdown.scss b/_sass/uikit/components/dropdown.scss
deleted file mode 100644
index 49bb12776a..0000000000
--- a/_sass/uikit/components/dropdown.scss
+++ /dev/null
@@ -1,150 +0,0 @@
-// Name: Dropdown
-// Description: Component to create dropdown menus
-//
-// Component: `uk-dropdown`
-//
-// Adopted: `uk-dropdown-nav`
-//
-// Modifiers: `uk-dropdown-top-*`
-// `uk-dropdown-bottom-*`
-// `uk-dropdown-left-*`
-// `uk-dropdown-right-*`
-// `uk-dropdown-stack`
-// `uk-dropdown-grid`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$dropdown-z-index: $global-z-index + 20 !default;
-$dropdown-min-width: 200px !default;
-$dropdown-padding: 15px !default;
-$dropdown-background: $global-muted-background !default;
-$dropdown-color: $global-color !default;
-$dropdown-margin: $global-small-margin !default;
-
-$dropdown-nav-item-color: $global-muted-color !default;
-$dropdown-nav-item-hover-color: $global-color !default;
-$dropdown-nav-header-color: $global-emphasis-color !default;
-$dropdown-nav-divider-border-width: $global-border-width !default;
-$dropdown-nav-divider-border: $global-border !default;
-$dropdown-nav-sublist-item-color: $global-muted-color !default;
-$dropdown-nav-sublist-item-hover-color: $global-color !default;
-
-
-/* ========================================================================
- Component: Dropdown
- ========================================================================== */
-
-/*
- * 1. Hide by default
- * 2. Set position
- * 3. Set a default width
- * 4. Style
- */
-
-.uk-dropdown {
- /* 1 */
- display: none;
- /* 2 */
- position: absolute;
- z-index: $dropdown-z-index;
- /* 3 */
- box-sizing: border-box;
- min-width: $dropdown-min-width;
- /* 4 */
- padding: $dropdown-padding;
- background: $dropdown-background;
- color: $dropdown-color;
- @if(mixin-exists(hook-dropdown)) {@include hook-dropdown();}
-}
-
-/* Show */
-.uk-dropdown.uk-open { display: block; }
-
-
-/* Nav
- * Adopts `uk-nav`
- ========================================================================== */
-
-.uk-dropdown-nav {
- white-space: nowrap;
- @if(mixin-exists(hook-dropdown-nav)) {@include hook-dropdown-nav();}
-}
-
-/*
- * Items
- */
-
-.uk-dropdown-nav > li > a {
- color: $dropdown-nav-item-color;
- @if(mixin-exists(hook-dropdown-nav-item)) {@include hook-dropdown-nav-item();}
-}
-
-/* Hover + Focus + Active */
-.uk-dropdown-nav > li > a:hover,
-.uk-dropdown-nav > li > a:focus,
-.uk-dropdown-nav > li.uk-active > a {
- color: $dropdown-nav-item-hover-color;
- @if(mixin-exists(hook-dropdown-nav-item-hover)) {@include hook-dropdown-nav-item-hover();}
-}
-
-/*
- * Header
- */
-
-.uk-dropdown-nav .uk-nav-header {
- color: $dropdown-nav-header-color;
- @if(mixin-exists(hook-dropdown-nav-header)) {@include hook-dropdown-nav-header();}
-}
-
-/*
- * Divider
- */
-
-.uk-dropdown-nav .uk-nav-divider {
- border-top: $dropdown-nav-divider-border-width solid $dropdown-nav-divider-border;
- @if(mixin-exists(hook-dropdown-nav-divider)) {@include hook-dropdown-nav-divider();}
-}
-
-/*
- * Sublists
- */
-
-.uk-dropdown-nav .uk-nav-sub a { color: $dropdown-nav-sublist-item-color; }
-
-.uk-dropdown-nav .uk-nav-sub a:hover,
-.uk-dropdown-nav .uk-nav-sub a:focus { color: $dropdown-nav-sublist-item-hover-color; }
-
-
-/* Direction / Alignment modifiers
- ========================================================================== */
-
-/* Direction */
-[class*='uk-dropdown-top'] { margin-top: (-$dropdown-margin); }
-[class*='uk-dropdown-bottom'] { margin-top: $dropdown-margin; }
-[class*='uk-dropdown-left'] { margin-left: (-$dropdown-margin); }
-[class*='uk-dropdown-right'] { margin-left: $dropdown-margin; }
-
-
-/* Grid modifiers
- ========================================================================== */
-
-.uk-dropdown-stack .uk-dropdown-grid > * { width: 100% !important; }
-
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-dropdown-misc)) {@include hook-dropdown-misc();}
-
-// @mixin hook-dropdown(){}
-// @mixin hook-dropdown-nav(){}
-// @mixin hook-dropdown-nav-item(){}
-// @mixin hook-dropdown-nav-item-hover(){}
-// @mixin hook-dropdown-nav-header(){}
-// @mixin hook-dropdown-nav-divider(){}
-// @mixin hook-dropdown-misc(){}
diff --git a/_sass/uikit/components/flex.scss b/_sass/uikit/components/flex.scss
deleted file mode 100644
index 1301fc4335..0000000000
--- a/_sass/uikit/components/flex.scss
+++ /dev/null
@@ -1,209 +0,0 @@
-// Name: Flex
-// Description: Utilities for layouts based on flexbox
-//
-// Component: `uk-flex-*`
-//
-// ========================================================================
-
-
-/* ========================================================================
- Component: Flex
- ========================================================================== */
-
-.uk-flex { display: flex; }
-.uk-flex-inline { display: inline-flex; }
-
-/*
- * Remove pseudo elements created by micro clearfix as precaution
- */
-
-.uk-flex::before,
-.uk-flex::after,
-.uk-flex-inline::before,
-.uk-flex-inline::after { display: none; }
-
-
-/* Alignment
- ========================================================================== */
-
-/*
- * Align items along the main axis of the current line of the flex container
- * Row: Horizontal
- */
-
-// Default
-.uk-flex-left { justify-content: flex-start; }
-.uk-flex-center { justify-content: center; }
-.uk-flex-right { justify-content: flex-end; }
-.uk-flex-between { justify-content: space-between; }
-.uk-flex-around { justify-content: space-around; }
-
-
-/* Phone landscape and bigger */
-@media (min-width: $breakpoint-small) {
-
- .uk-flex-left\@s { justify-content: flex-start; }
- .uk-flex-center\@s { justify-content: center; }
- .uk-flex-right\@s { justify-content: flex-end; }
- .uk-flex-between\@s { justify-content: space-between; }
- .uk-flex-around\@s { justify-content: space-around; }
-
-}
-
-/* Tablet landscape and bigger */
-@media (min-width: $breakpoint-medium) {
-
- .uk-flex-left\@m { justify-content: flex-start; }
- .uk-flex-center\@m { justify-content: center; }
- .uk-flex-right\@m { justify-content: flex-end; }
- .uk-flex-between\@m { justify-content: space-between; }
- .uk-flex-around\@m { justify-content: space-around; }
-
-}
-
-/* Desktop and bigger */
-@media (min-width: $breakpoint-large) {
-
- .uk-flex-left\@l { justify-content: flex-start; }
- .uk-flex-center\@l { justify-content: center; }
- .uk-flex-right\@l { justify-content: flex-end; }
- .uk-flex-between\@l { justify-content: space-between; }
- .uk-flex-around\@l { justify-content: space-around; }
-
-}
-
-/* Large screen and bigger */
-@media (min-width: $breakpoint-xlarge) {
-
- .uk-flex-left\@xl { justify-content: flex-start; }
- .uk-flex-center\@xl { justify-content: center; }
- .uk-flex-right\@xl { justify-content: flex-end; }
- .uk-flex-between\@xl { justify-content: space-between; }
- .uk-flex-around\@xl { justify-content: space-around; }
-
-}
-
-/*
- * Align items in the cross axis of the current line of the flex container
- * Row: Vertical
- */
-
-// Default
-.uk-flex-stretch { align-items: stretch; }
-.uk-flex-top { align-items: flex-start; }
-.uk-flex-middle { align-items: center; }
-.uk-flex-bottom { align-items: flex-end; }
-
-
-/* Direction
- ========================================================================== */
-
-// Default
-.uk-flex-row { flex-direction: row; }
-.uk-flex-row-reverse { flex-direction: row-reverse; }
-.uk-flex-column { flex-direction: column; }
-.uk-flex-column-reverse { flex-direction: column-reverse; }
-
-
-/* Wrap
- ========================================================================== */
-
-// Default
-.uk-flex-nowrap { flex-wrap: nowrap; }
-.uk-flex-wrap { flex-wrap: wrap; }
-.uk-flex-wrap-reverse { flex-wrap: wrap-reverse; }
-
-/*
- * Aligns items within the flex container when there is extra space in the cross-axis
- * Only works if there is more than one line of flex items
- */
-
-// Default
-.uk-flex-wrap-stretch { align-content: stretch; }
-.uk-flex-wrap-top { align-content: flex-start; }
-.uk-flex-wrap-middle { align-content: center; }
-.uk-flex-wrap-bottom { align-content: flex-end; }
-.uk-flex-wrap-between { align-content: space-between; }
-.uk-flex-wrap-around { align-content: space-around; }
-
-
-/* Item ordering
- ========================================================================== */
-
-/*
- * Default is 0
- */
-
-.uk-flex-first { order: -1;}
-.uk-flex-last { order: 99;}
-
-
-/* Phone landscape and bigger */
-@media (min-width: $breakpoint-small) {
-
- .uk-flex-first\@s { order: -1; }
- .uk-flex-last\@s { order: 99; }
-
-}
-
-/* Tablet landscape and bigger */
-@media (min-width: $breakpoint-medium) {
-
- .uk-flex-first\@m { order: -1; }
- .uk-flex-last\@m { order: 99; }
-
-}
-
-/* Desktop and bigger */
-@media (min-width: $breakpoint-large) {
-
- .uk-flex-first\@l { order: -1; }
- .uk-flex-last\@l { order: 99; }
-
-}
-
-/* Large screen and bigger */
-@media (min-width: $breakpoint-xlarge) {
-
- .uk-flex-first\@xl { order: -1; }
- .uk-flex-last\@xl { order: 99; }
-
-}
-
-
-/* Item dimensions
- ========================================================================== */
-
-/*
- * Initial: 0 1 auto
- * Content dimensions, but shrinks
- */
-
-/*
- * No Flex: 0 0 auto
- * Content dimensions
- */
-
-.uk-flex-none { flex: none; }
-
-/*
- * Relative Flex: 1 1 auto
- * Space is allocated considering content
- */
-
-.uk-flex-auto { flex: auto; }
-
-/*
- * Absolute Flex: 1 1 0%
- * Space is allocated solely based on flex
- */
-
-.uk-flex-1 { flex: 1; }
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-flex-misc)) {@include hook-flex-misc();}
-
-// @mixin hook-flex-misc(){}
\ No newline at end of file
diff --git a/_sass/uikit/components/form-range.scss b/_sass/uikit/components/form-range.scss
deleted file mode 100644
index f7a22a5d50..0000000000
--- a/_sass/uikit/components/form-range.scss
+++ /dev/null
@@ -1,185 +0,0 @@
-// Name: Form Range
-// Description: Styles for the range input type
-//
-// Component: `uk-range`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$form-range-thumb-height: 15px !default;
-$form-range-thumb-border-radius: 500px !default;
-$form-range-thumb-background: $global-color !default;
-
-$form-range-track-height: 3px !default;
-$form-range-track-background: darken($global-muted-background, 5%) !default;
-$form-range-track-focus-background: darken($global-muted-background, 15%) !default;
-
-
-/* ========================================================================
- Component: Form Range
- ========================================================================== */
-
-/*
- * 1. Normalize and defaults
- * 2. Prevent content overflow if a fixed width is used
- * 3. Take the full width
- * 4. Remove default style
- * 5. Remove white background in Chrome
- * 6. Remove padding in IE11
- */
-
-.uk-range {
- /* 1 */
- box-sizing: border-box;
- margin: 0;
- vertical-align: middle;
- /* 2 */
- max-width: 100%;
- /* 3 */
- width: 100%;
- /* 4 */
- -webkit-appearance: none;
- /* 5 */
- background: transparent;
- /* 6 */
- padding: 0;
- @if(mixin-exists(hook-form-range)) {@include hook-form-range();}
-}
-
-/* Focus */
-.uk-range:focus { outline: none; }
-.uk-range::-moz-focus-outer { border: none; }
-
-/* IE11 Reset */
-.uk-range::-ms-track {
- height: $form-range-thumb-height;
- background: transparent;
- border-color: transparent;
- color: transparent;
-}
-
-/*
- * Improves consistency of cursor style for clickable elements
- */
-
-.uk-range:not(:disabled)::-webkit-slider-thumb { cursor: pointer; }
-.uk-range:not(:disabled)::-moz-range-thumb { cursor: pointer; }
-.uk-range:not(:disabled)::-ms-thumb { cursor: pointer; }
-
-
-/* Thumb
- ========================================================================== */
-
-/*
- * 1. Reset
- * 2. Style
- */
-
-/* Webkit */
-.uk-range::-webkit-slider-thumb {
- /* 1 */
- -webkit-appearance: none;
- margin-top: (floor($form-range-thumb-height / 2) * -1);
- /* 2 */
- height: $form-range-thumb-height;
- width: $form-range-thumb-height;
- border-radius: $form-range-thumb-border-radius;
- background: $form-range-thumb-background;
- @if(mixin-exists(hook-form-range-thumb)) {@include hook-form-range-thumb();}
-}
-
-/* Firefox */
-.uk-range::-moz-range-thumb {
- /* 1 */
- border: none;
- /* 2 */
- height: $form-range-thumb-height;
- width: $form-range-thumb-height;
- border-radius: $form-range-thumb-border-radius;
- background: $form-range-thumb-background;
- @if(mixin-exists(hook-form-range-thumb)) {@include hook-form-range-thumb();}
-}
-
-/* Edge */
-.uk-range::-ms-thumb {
- /* 1 */
- margin-top: 0;
-}
-
-/* IE11 */
-.uk-range::-ms-thumb {
- /* 1 */
- border: none;
- /* 2 */
- height: $form-range-thumb-height;
- width: $form-range-thumb-height;
- border-radius: $form-range-thumb-border-radius;
- background: $form-range-thumb-background;
- @if(mixin-exists(hook-form-range-thumb)) {@include hook-form-range-thumb();}
-}
-
-/* Edge + IE11 */
-.uk-range::-ms-tooltip { display: none; }
-
-
-/* Track
- ========================================================================== */
-
-/*
- * 1. Safari doesn't have a focus state. Using active instead.
- */
-
-/* Webkit */
-.uk-range::-webkit-slider-runnable-track {
- height: $form-range-track-height;
- background: $form-range-track-background;
- @if(mixin-exists(hook-form-range-track)) {@include hook-form-range-track();}
-}
-
-.uk-range:focus::-webkit-slider-runnable-track,
-/* 1 */
-.uk-range:active::-webkit-slider-runnable-track {
- background: $form-range-track-focus-background;
- @if(mixin-exists(hook-form-range-track-focus)) {@include hook-form-range-track-focus();}
-}
-
-/* Firefox */
-.uk-range::-moz-range-track {
- height: $form-range-track-height;
- background: $form-range-track-background;
- @if(mixin-exists(hook-form-range-track)) {@include hook-form-range-track();}
-}
-
-.uk-range:focus::-moz-range-track {
- background: $form-range-track-focus-background;
- @if(mixin-exists(hook-form-range-track-focus)) {@include hook-form-range-track-focus();}
-}
-
-/* Edge */
-.uk-range::-ms-fill-lower,
-.uk-range::-ms-fill-upper {
- height: $form-range-track-height;
- background: $form-range-track-background;
- @if(mixin-exists(hook-form-range-track)) {@include hook-form-range-track();}
-}
-
-.uk-range:focus::-ms-fill-lower,
-.uk-range:focus::-ms-fill-upper {
- background: $form-range-track-focus-background;
- @if(mixin-exists(hook-form-range-track-focus)) {@include hook-form-range-track-focus();}
-}
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-form-range-misc)) {@include hook-form-range-misc();}
-
-// @mixin hook-form-range(){}
-// @mixin hook-form-range-thumb(){}
-// @mixin hook-form-range-track(){}
-// @mixin hook-form-range-track-focus(){}
-// @mixin hook-form-range-misc(){}
diff --git a/_sass/uikit/components/form.scss b/_sass/uikit/components/form.scss
deleted file mode 100644
index e731cffb63..0000000000
--- a/_sass/uikit/components/form.scss
+++ /dev/null
@@ -1,756 +0,0 @@
-// Name: Form
-// Description: Styles for forms
-//
-// Component: `uk-form-*`
-// `uk-input`
-// `uk-select`
-// `uk-textarea`
-// `uk-radio`
-// `uk-checkbox`
-// `uk-legend`
-// `uk-fieldset`
-//
-// Sub-objects: `uk-form-custom`
-// `uk-form-stacked`
-// `uk-form-horizontal`
-// `uk-form-label`
-// `uk-form-controls`
-// `uk-form-icon`
-// `uk-form-icon-flip`
-//
-// Modifiers: `uk-form-small`
-// `uk-form-large`
-// `uk-form-danger`
-// `uk-form-success`
-// `uk-form-blank`
-// `uk-form-width-xsmall`
-// `uk-form-width-small`
-// `uk-form-width-medium`
-// `uk-form-width-large`
-// `uk-form-controls-text`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$form-height: $global-control-height !default;
-$form-line-height: $form-height !default;
-$form-padding-horizontal: 10px !default;
-$form-padding-vertical: 4px !default;
-
-$form-background: $global-muted-background !default;
-$form-color: $global-color !default;
-
-$form-focus-background: $global-muted-background !default;
-$form-focus-color: $global-color !default;
-
-$form-disabled-background: $global-muted-background !default;
-$form-disabled-color: $global-muted-color !default;
-
-$form-placeholder-color: $global-muted-color !default;
-
-$form-small-height: $global-control-small-height !default;
-$form-small-padding-horizontal: 8px !default;
-$form-small-line-height: $form-small-height !default;
-$form-small-font-size: $global-small-font-size !default;
-
-$form-large-height: $global-control-large-height !default;
-$form-large-padding-horizontal: 12px !default;
-$form-large-line-height: $form-large-height !default;
-$form-large-font-size: $global-medium-font-size !default;
-
-$form-danger-color: $global-danger-background !default;
-$form-success-color: $global-success-background !default;
-
-$form-width-xsmall: 50px !default;
-$form-width-small: 130px !default;
-$form-width-medium: 200px !default;
-$form-width-large: 500px !default;
-
-$form-select-padding-right: 20px !default;
-$form-select-icon-color: $global-color !default;
-$form-select-disabled-icon-color: $global-muted-color !default;
-
-$form-radio-size: 16px !default;
-$form-radio-margin-top: -4px !default;
-$form-radio-background: darken($global-muted-background, 5%) !default;
-
-$form-radio-checked-background: $global-primary-background !default;
-$form-radio-checked-icon-color: $global-inverse-color !default;
-
-$form-radio-checked-focus-background: darken($global-primary-background, 10%) !default;
-
-$form-radio-disabled-background: $global-muted-background !default;
-$form-radio-disabled-icon-color: $global-muted-color !default;
-
-$form-legend-font-size: $global-large-font-size !default;
-$form-legend-line-height: 1.4 !default;
-
-$form-stacked-margin-bottom: $global-small-margin !default;
-
-$form-horizontal-label-width: 200px !default;
-$form-horizontal-label-margin-top: 7px !default;
-$form-horizontal-controls-margin-left: 215px !default;
-$form-horizontal-controls-text-padding-top: 7px !default;
-
-$form-icon-width: $form-height !default;
-$form-icon-font-size: $global-font-size !default;
-$form-icon-color: $global-muted-color !default;
-$form-icon-hover-color: $global-color !default;
-
-$internal-form-select-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2224%22%20height%3D%2216%22%20viewBox%3D%220%200%2024%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22#000%22%20points%3D%2212%201%209%206%2015%206%22%20%2F%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22#000%22%20points%3D%2212%2013%209%208%2015%208%22%20%2F%3E%0A%3C%2Fsvg%3E%0A" !default;
-$internal-form-radio-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Ccircle%20fill%3D%22#000%22%20cx%3D%228%22%20cy%3D%228%22%20r%3D%222%22%20%2F%3E%0A%3C%2Fsvg%3E" !default;
-$internal-form-checkbox-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2214%22%20height%3D%2211%22%20viewBox%3D%220%200%2014%2011%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22#000%22%20points%3D%2212%201%205%207.5%202%205%201%205.5%205%2010%2013%201.5%22%20%2F%3E%0A%3C%2Fsvg%3E%0A" !default;
-$internal-form-checkbox-indeterminate-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Crect%20fill%3D%22#000%22%20x%3D%223%22%20y%3D%228%22%20width%3D%2210%22%20height%3D%221%22%20%2F%3E%0A%3C%2Fsvg%3E" !default;
-
-
-/* ========================================================================
- Component: Form
- ========================================================================== */
-
-/*
- * 1. Define consistent box sizing.
- * Default is `content-box` with following exceptions set to `border-box`
- * `select`, `input[type="checkbox"]` and `input[type="radio"]`
- * `input[type="search"]` in Chrome, Safari and Opera
- * `input[type="color"]` in Firefox
- * 2. Address margins set differently in Firefox/IE and Chrome/Safari/Opera.
- * 3. Remove `border-radius` in iOS.
- * 4. Change font properties to `inherit` in all browsers.
- */
-
-.uk-input,
-.uk-select,
-.uk-textarea,
-.uk-radio,
-.uk-checkbox {
- /* 1 */
- box-sizing: border-box;
- /* 2 */
- margin: 0;
- /* 3 */
- border-radius: 0;
- /* 4 */
- font: inherit;
-}
-
-/*
- * Show the overflow in Edge.
- */
-
-.uk-input { overflow: visible; }
-
-/*
- * Remove the inheritance of text transform in Firefox.
- */
-
-.uk-select { text-transform: none; }
-
-/*
- * 1. Change font properties to `inherit` in all browsers
- * 2. Don't inherit the `font-weight` and use `bold` instead.
- * NOTE: Both declarations don't work in Chrome, Safari and Opera.
- */
-
-.uk-select optgroup {
- /* 1 */
- font: inherit;
- /* 2 */
- font-weight: bold;
-}
-
-/*
- * Remove the default vertical scrollbar in IE 10+.
- */
-
-.uk-textarea { overflow: auto; }
-
-/*
- * Remove the inner padding and cancel buttons in Chrome on OS X and Safari on OS X.
- */
-
-.uk-input[type="search"]::-webkit-search-cancel-button,
-.uk-input[type="search"]::-webkit-search-decoration { -webkit-appearance: none; }
-
-
-/*
- * Correct the cursor style of increment and decrement buttons in Chrome.
- */
-
-.uk-input[type="number"]::-webkit-inner-spin-button,
-.uk-input[type="number"]::-webkit-outer-spin-button { height: auto; }
-
-/*
- * Removes placeholder transparency in Firefox.
- */
-
-.uk-input::-moz-placeholder,
-.uk-textarea::-moz-placeholder { opacity: 1; }
-
-/*
- * Improves consistency of cursor style for clickable elements
- */
-
-.uk-radio:not(:disabled),
-.uk-checkbox:not(:disabled) { cursor: pointer; }
-
-/*
- * Define consistent border, margin, and padding.
- */
-
-.uk-fieldset {
- border: none;
- margin: 0;
- padding: 0;
-}
-
-
-/* Input, select and textarea
- * Allowed: `text`, `password`, `datetime`, `datetime-local`, `date`, `month`,
- `time`, `week`, `number`, `email`, `url`, `search`, `tel`, `color`
- * Disallowed: `range`, `radio`, `checkbox`, `file`, `submit`, `reset` and `image`
- ========================================================================== */
-
-/*
- * Remove default style in iOS.
- */
-
-.uk-input,
-.uk-textarea { -webkit-appearance: none; }
-
-/*
- * 1. Prevent content overflow if a fixed width is used
- * 2. Take the full width
- * 3. Reset default
- * 4. Style
- */
-
-.uk-input,
-.uk-select,
-.uk-textarea {
- /* 1 */
- max-width: 100%;
- /* 2 */
- width: 100%;
- /* 3 */
- border: 0 none;
- /* 4 */
- padding: 0 $form-padding-horizontal;
- background: $form-background;
- color: $form-color;
- @if(mixin-exists(hook-form)) {@include hook-form();}
-}
-
-/*
- * Single-line
- * 1. Allow any element to look like an `input` or `select` element
- * 2. Make sure line-height is not larger than height
- * Also needed to center the text vertically
- */
-
-.uk-input,
-.uk-select:not([multiple]):not([size]) {
- height: $form-height;
- vertical-align: middle;
- /* 1 */
- display: inline-block;
- @if(mixin-exists(hook-form-single-line)) {@include hook-form-single-line();}
-}
-
-/* 2 */
-.uk-input:not(input),
-.uk-select:not(select) { line-height: $form-line-height; }
-
-/*
- * Multi-line
- */
-
-.uk-select[multiple],
-.uk-select[size],
-.uk-textarea {
- padding-top: $form-padding-vertical;
- padding-bottom: $form-padding-vertical;
- vertical-align: top;
- @if(mixin-exists(hook-form-multi-line)) {@include hook-form-multi-line();}
-}
-
-/* Focus */
-.uk-input:focus,
-.uk-select:focus,
-.uk-textarea:focus {
- outline: none;
- background-color: $form-focus-background;
- color: $form-focus-color;
- @if(mixin-exists(hook-form-focus)) {@include hook-form-focus();}
-}
-
-/* Disabled */
-.uk-input:disabled,
-.uk-select:disabled,
-.uk-textarea:disabled {
- background-color: $form-disabled-background;
- color: $form-disabled-color;
- @if(mixin-exists(hook-form-disabled)) {@include hook-form-disabled();}
-}
-
-/*
- * Placeholder
- */
-
-.uk-input:-ms-input-placeholder { color: $form-placeholder-color !important; }
-.uk-input::placeholder { color: $form-placeholder-color; }
-
-.uk-textarea:-ms-input-placeholder { color: $form-placeholder-color !important; }
-.uk-textarea::placeholder { color: $form-placeholder-color; }
-
-
-/* Style modifier (`uk-input`, `uk-select` and `uk-textarea`)
- ========================================================================== */
-
-/*
- * Small
- */
-
-.uk-form-small { font-size: $form-small-font-size; }
-
-.uk-form-small:not(textarea):not([multiple]):not([size]) {
- height: $form-small-height;
- padding-left: $form-small-padding-horizontal;
- padding-right: $form-small-padding-horizontal;
-}
-
-.uk-form-small:not(select):not(input):not(textarea) { line-height: $form-small-line-height; }
-
-/*
- * Large
- */
-
-.uk-form-large { font-size: $form-large-font-size; }
-
-.uk-form-large:not(textarea):not([multiple]):not([size]) {
- height: $form-large-height;
- padding-left: $form-large-padding-horizontal;
- padding-right: $form-large-padding-horizontal;
-}
-
-.uk-form-large:not(select):not(input):not(textarea) { line-height: $form-large-line-height; }
-
-
-/* Style modifier (`uk-input`, `uk-select` and `uk-textarea`)
- ========================================================================== */
-
-/*
- * Error
- */
-
-.uk-form-danger,
-.uk-form-danger:focus {
- color: $form-danger-color;
- @if(mixin-exists(hook-form-danger)) {@include hook-form-danger();}
-}
-
-/*
- * Success
- */
-
-.uk-form-success,
-.uk-form-success:focus {
- color: $form-success-color;
- @if(mixin-exists(hook-form-success)) {@include hook-form-success();}
-}
-
-/*
- * Blank
- */
-
-.uk-form-blank {
- background: none;
- @if(mixin-exists(hook-form-blank)) {@include hook-form-blank();}
-}
-
-.uk-form-blank:focus {
- @if(mixin-exists(hook-form-blank-focus)) {@include hook-form-blank-focus();}
-}
-
-
-/* Width modifiers (`uk-input`, `uk-select` and `uk-textarea`)
- ========================================================================== */
-
-/*
- * Fixed widths
- * Different widths for mini sized `input` and `select` elements
- */
-
-input.uk-form-width-xsmall { width: $form-width-xsmall; }
-
-select.uk-form-width-xsmall { width: ($form-width-xsmall + 25px); }
-
-.uk-form-width-small { width: $form-width-small; }
-
-.uk-form-width-medium { width: $form-width-medium; }
-
-.uk-form-width-large { width: $form-width-large; }
-
-
-/* Select
- ========================================================================== */
-
-/*
- * 1. Remove default style. Also works in Firefox
- * 2. Style
- * 3. Remove default style in IE 10/11
- */
-
-.uk-select:not([multiple]):not([size]) {
- /* 1 */
- -webkit-appearance: none;
- -moz-appearance: none;
- /* 2 */
- padding-right: $form-select-padding-right;
- @include svg-fill($internal-form-select-image, "#000", $form-select-icon-color);
- background-repeat: no-repeat;
- background-position: 100% 50%;
-}
-
-/* 3 */
-.uk-select:not([multiple]):not([size])::-ms-expand { display: none; }
-
-/*
- * Disabled
- */
-
-.uk-select:not([multiple]):not([size]):disabled { @include svg-fill($internal-form-select-image, "#000", $form-select-disabled-icon-color); }
-
-
-/* Radio and checkbox
- * Note: Does not work in IE11
- ========================================================================== */
-
-/*
- * 1. Style
- * 2. Make box more robust so it clips the child element
- * 3. Vertical alignment
- * 4. Remove default style
- * 5. Fix black background on iOS
- * 6. Center icons
- */
-
-.uk-radio,
-.uk-checkbox {
- /* 1 */
- display: inline-block;
- height: $form-radio-size;
- width: $form-radio-size;
- /* 2 */
- overflow: hidden;
- /* 3 */
- margin-top: $form-radio-margin-top;
- vertical-align: middle;
- /* 4 */
- -webkit-appearance: none;
- -moz-appearance: none;
- /* 5 */
- background-color: $form-radio-background;
- /* 6 */
- background-repeat: no-repeat;
- background-position: 50% 50%;
- @if(mixin-exists(hook-form-radio)) {@include hook-form-radio();}
-}
-
-.uk-radio { border-radius: 50%; }
-
-/* Focus */
-.uk-radio:focus,
-.uk-checkbox:focus {
- outline: none;
- @if(mixin-exists(hook-form-radio-focus)) {@include hook-form-radio-focus();}
-}
-
-/*
- * Checked
- */
-
-.uk-radio:checked,
-.uk-checkbox:checked,
-.uk-checkbox:indeterminate {
- background-color: $form-radio-checked-background;
- @if(mixin-exists(hook-form-radio-checked)) {@include hook-form-radio-checked();}
-}
-
-/* Focus */
-.uk-radio:checked:focus,
-.uk-checkbox:checked:focus,
-.uk-checkbox:indeterminate:focus {
- background-color: $form-radio-checked-focus-background;
- @if(mixin-exists(hook-form-radio-checked-focus)) {@include hook-form-radio-checked-focus();}
-}
-
-/*
- * Icons
- */
-
-.uk-radio:checked { @include svg-fill($internal-form-radio-image, "#000", $form-radio-checked-icon-color); }
-.uk-checkbox:checked { @include svg-fill($internal-form-checkbox-image, "#000", $form-radio-checked-icon-color); }
-.uk-checkbox:indeterminate { @include svg-fill($internal-form-checkbox-indeterminate-image, "#000", $form-radio-checked-icon-color); }
-
-/*
- * Disabled
- */
-
-.uk-radio:disabled,
-.uk-checkbox:disabled {
- background-color: $form-radio-disabled-background;
- @if(mixin-exists(hook-form-radio-disabled)) {@include hook-form-radio-disabled();}
-}
-
-.uk-radio:disabled:checked { @include svg-fill($internal-form-radio-image, "#000", $form-radio-disabled-icon-color); }
-.uk-checkbox:disabled:checked { @include svg-fill($internal-form-checkbox-image, "#000", $form-radio-disabled-icon-color); }
-.uk-checkbox:disabled:indeterminate { @include svg-fill($internal-form-checkbox-indeterminate-image, "#000", $form-radio-disabled-icon-color); }
-
-
-/* Legend
- ========================================================================== */
-
-/*
- * Legend
- * 1. Behave like block element
- * 2. Correct the color inheritance from `fieldset` elements in IE.
- * 3. Remove padding so people aren't caught out if they zero out fieldsets.
- * 4. Style
- */
-
-.uk-legend {
- /* 1 */
- width: 100%;
- /* 2 */
- color: inherit;
- /* 3 */
- padding: 0;
- /* 4 */
- font-size: $form-legend-font-size;
- line-height: $form-legend-line-height;
- @if(mixin-exists(hook-form-legend)) {@include hook-form-legend();}
-}
-
-
-/* Custom controls
- ========================================================================== */
-
-/*
- * 1. Container fits its content
- * 2. Create position context
- * 3. Prevent content overflow
- * 4. Behave like most inline-block elements
- */
-
-.uk-form-custom {
- /* 1 */
- display: inline-block;
- /* 2 */
- position: relative;
- /* 3 */
- max-width: 100%;
- /* 4 */
- vertical-align: middle;
-}
-
-/*
- * 1. Position and resize the form control to always cover its container
- * 2. Required for Firefox for positioning to the left
- * 3. Required for Webkit to make `height` work
- * 4. Hide controle and show cursor
- * 5. Needed for the cursor
- * 6. Clip height caused by 5. Needed for Webkit only
- */
-
-.uk-form-custom select,
-.uk-form-custom input[type="file"] {
- /* 1 */
- position: absolute;
- top: 0;
- z-index: 1;
- width: 100%;
- height: 100%;
- /* 2 */
- left: 0;
- /* 3 */
- -webkit-appearance: none;
- /* 4 */
- opacity: 0;
- cursor: pointer;
-}
-
-.uk-form-custom input[type="file"] {
- /* 5 */
- font-size: 500px;
- /* 6 */
- overflow: hidden;
-}
-
-
-/* Label
- ========================================================================== */
-
-.uk-form-label {
- @if(mixin-exists(hook-form-label)) {@include hook-form-label();}
-}
-
-
-/* Layout
- ========================================================================== */
-
-/*
- * Stacked
- */
-
-.uk-form-stacked .uk-form-label {
- display: block;
- margin-bottom: $form-stacked-margin-bottom;
- @if(mixin-exists(hook-form-stacked-label)) {@include hook-form-stacked-label();}
-}
-
-/*
- * Horizontal
- */
-
-/* Tablet portrait and smaller */
-@media (max-width: $breakpoint-small-max) {
-
- /* Behave like `uk-form-stacked` */
- .uk-form-horizontal .uk-form-label {
- display: block;
- margin-bottom: $form-stacked-margin-bottom;
- @if(mixin-exists(hook-form-stacked-label)) {@include hook-form-stacked-label();}
- }
-
-}
-
-/* Tablet landscape and bigger */
-@media (min-width: $breakpoint-medium) {
-
- .uk-form-horizontal .uk-form-label {
- width: $form-horizontal-label-width;
- margin-top: $form-horizontal-label-margin-top;
- float: left;
- @if(mixin-exists(hook-form-horizontal-label)) {@include hook-form-horizontal-label();}
- }
-
- .uk-form-horizontal .uk-form-controls { margin-left: $form-horizontal-controls-margin-left; }
-
- /* Better vertical alignment if controls are checkboxes and radio buttons with text */
- .uk-form-horizontal .uk-form-controls-text { padding-top: $form-horizontal-controls-text-padding-top; }
-
-}
-
-
-/* Icons
- ========================================================================== */
-
-/*
- * 1. Set position
- * 2. Set width
- * 3. Center icon vertically and horizontally
- * 4. Style
- */
-
-.uk-form-icon {
- /* 1 */
- position: absolute;
- top: 0;
- bottom: 0;
- left: 0;
- /* 2 */
- width: $form-icon-width;
- /* 3 */
- display: inline-flex;
- justify-content: center;
- align-items: center;
- /* 4 */
- color: $form-icon-color;
-}
-
-/*
- * Required for `a`.
- */
-
-.uk-form-icon:hover { color: $form-icon-hover-color; }
-
-/*
- * Make `input` element clickable through icon, e.g. if it's a `span`
- */
-
-.uk-form-icon:not(a):not(button):not(input) { pointer-events: none; }
-
-/*
- * Input padding
- */
-
-.uk-form-icon:not(.uk-form-icon-flip) + .uk-input { padding-left: $form-icon-width !important; }
-
-/*
- * Position modifier
- */
-
-.uk-form-icon-flip {
- right: 0;
- left: auto;
-}
-
-.uk-form-icon-flip + .uk-input { padding-right: $form-icon-width !important; }
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-form-misc)) {@include hook-form-misc();}
-
-// @mixin hook-form(){}
-// @mixin hook-form-single-line(){}
-// @mixin hook-form-multi-line(){}
-// @mixin hook-form-focus(){}
-// @mixin hook-form-disabled(){}
-// @mixin hook-form-danger(){}
-// @mixin hook-form-success(){}
-// @mixin hook-form-blank(){}
-// @mixin hook-form-blank-focus(){}
-// @mixin hook-form-radio(){}
-// @mixin hook-form-radio-focus(){}
-// @mixin hook-form-radio-checked(){}
-// @mixin hook-form-radio-checked-focus(){}
-// @mixin hook-form-radio-disabled(){}
-// @mixin hook-form-legend(){}
-// @mixin hook-form-label(){}
-// @mixin hook-form-stacked-label(){}
-// @mixin hook-form-horizontal-label(){}
-// @mixin hook-form-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-$inverse-form-background: $inverse-global-muted-background !default;
-$inverse-form-color: $inverse-global-color !default;
-$inverse-form-focus-background: $inverse-global-muted-background !default;
-$inverse-form-focus-color: $inverse-global-color !default;
-$inverse-form-placeholder-color: $inverse-global-muted-color !default;
-
-$inverse-form-select-icon-color: $inverse-global-color !default;
-
-$inverse-form-radio-background: darken($inverse-global-muted-background, 5%) !default;
-
-$inverse-form-radio-checked-background: $inverse-global-primary-background !default;
-$inverse-form-radio-checked-icon-color: $inverse-global-inverse-color !default;
-
-$inverse-form-radio-checked-focus-background: darken($inverse-global-primary-background, 10%) !default;
-
-
-
-// @mixin hook-inverse-form(){}
-// @mixin hook-inverse-form-focus(){}
-// @mixin hook-inverse-form-radio(){}
-// @mixin hook-inverse-form-radio-focus(){}
-// @mixin hook-inverse-form-radio-checked(){}
-// @mixin hook-inverse-form-radio-checked-focus(){}
-// @mixin hook-inverse-form-label(){}
diff --git a/_sass/uikit/components/grid.scss b/_sass/uikit/components/grid.scss
deleted file mode 100644
index 455033c72b..0000000000
--- a/_sass/uikit/components/grid.scss
+++ /dev/null
@@ -1,352 +0,0 @@
-// Name: Grid
-// Description: Component to create responsive, fluid and nestable grids
-//
-// Component: `uk-grid`
-//
-// Modifiers: `uk-grid-small`
-// `uk-grid-medium`
-// `uk-grid-large`
-// `uk-grid-collapse`
-// `uk-grid-divider`
-// `uk-grid-match`
-// `uk-grid-stack`
-// `uk-grid-margin`
-// `uk-grid-margin-small`
-// `uk-grid-margin-medium`
-// `uk-grid-margin-large`
-// `uk-grid-margin-collapse`
-//
-// Sub-modifier: `uk-grid-item-match`
-//
-// States: `uk-first-column`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$grid-gutter-horizontal: $global-gutter !default;
-$grid-gutter-vertical: $grid-gutter-horizontal !default;
-$grid-gutter-horizontal-l: $global-medium-gutter !default;
-$grid-gutter-vertical-l: $grid-gutter-horizontal-l !default;
-
-$grid-small-gutter-horizontal: $global-small-gutter !default;
-$grid-small-gutter-vertical: $grid-small-gutter-horizontal !default;
-
-$grid-medium-gutter-horizontal: $global-gutter !default;
-$grid-medium-gutter-vertical: $grid-medium-gutter-horizontal !default;
-
-$grid-large-gutter-horizontal: $global-medium-gutter !default;
-$grid-large-gutter-vertical: $grid-large-gutter-horizontal !default;
-$grid-large-gutter-horizontal-l: $global-large-gutter !default;
-$grid-large-gutter-vertical-l: $grid-large-gutter-horizontal-l !default;
-
-$grid-divider-border-width: $global-border-width !default;
-$grid-divider-border: $global-border !default;
-
-
-/* ========================================================================
- Component: Grid
- ========================================================================== */
-
-/*
- * 1. Allow cells to wrap into the next line
- * 2. Reset list
- */
-
-.uk-grid {
- display: flex;
- /* 1 */
- flex-wrap: wrap;
- /* 2 */
- margin: 0;
- padding: 0;
- list-style: none;
-}
-
-/*
- * Grid cell
- * Note: Space is allocated solely based on content dimensions, but shrinks: 0 1 auto
- * Reset margin for e.g. paragraphs
- */
-
-.uk-grid > * { margin: 0; }
-
-/*
- * Remove margin from the last-child
- */
-
-.uk-grid > * > :last-child { margin-bottom: 0; }
-
-
-/* Gutter
- ========================================================================== */
-
-/*
- * Default
- */
-
-/* Horizontal */
-.uk-grid { margin-left: (-$grid-gutter-horizontal); }
-.uk-grid > * { padding-left: $grid-gutter-horizontal; }
-
-/* Vertical */
-.uk-grid + .uk-grid,
-.uk-grid > .uk-grid-margin,
-* + .uk-grid-margin { margin-top: $grid-gutter-vertical; }
-
-/* Desktop and bigger */
-@media (min-width: $breakpoint-large) {
-
- /* Horizontal */
- .uk-grid { margin-left: (-$grid-gutter-horizontal-l); }
- .uk-grid > * { padding-left: $grid-gutter-horizontal-l; }
-
- /* Vertical */
- .uk-grid + .uk-grid,
- .uk-grid > .uk-grid-margin,
- * + .uk-grid-margin { margin-top: $grid-gutter-vertical-l; }
-
-}
-
-/*
- * Small
- */
-
-/* Horizontal */
-.uk-grid-small { margin-left: (-$grid-small-gutter-horizontal); }
-.uk-grid-small > * { padding-left: $grid-small-gutter-horizontal; }
-
-/* Vertical */
-.uk-grid + .uk-grid-small,
-.uk-grid-small > .uk-grid-margin,
-* + .uk-grid-margin-small { margin-top: $grid-small-gutter-vertical; }
-
-/*
- * Medium
- */
-
-/* Horizontal */
-.uk-grid-medium { margin-left: (-$grid-medium-gutter-horizontal); }
-.uk-grid-medium > * { padding-left: $grid-medium-gutter-horizontal; }
-
-/* Vertical */
-.uk-grid + .uk-grid-medium,
-.uk-grid-medium > .uk-grid-margin,
-* + .uk-grid-margin-medium { margin-top: $grid-medium-gutter-vertical; }
-
-/*
- * Large
- */
-
-/* Horizontal */
-.uk-grid-large { margin-left: (-$grid-large-gutter-horizontal); }
-.uk-grid-large > * { padding-left: $grid-large-gutter-horizontal; }
-
-/* Vertical */
-.uk-grid + .uk-grid-large,
-.uk-grid-large > .uk-grid-margin,
-* + .uk-grid-margin-large { margin-top: $grid-large-gutter-vertical; }
-
-/* Desktop and bigger */
-@media (min-width: $breakpoint-large) {
-
- /* Horizontal */
- .uk-grid-large { margin-left: (-$grid-large-gutter-horizontal-l); }
- .uk-grid-large > * { padding-left: $grid-large-gutter-horizontal-l; }
-
- /* Vertical */
- .uk-grid + .uk-grid-large,
- .uk-grid-large > .uk-grid-margin,
- * + .uk-grid-margin-large { margin-top: $grid-large-gutter-vertical-l; }
-
-}
-
-/*
- * Collapse
- */
-
-/* Horizontal */
-.uk-grid-collapse { margin-left: 0; }
-.uk-grid-collapse > * { padding-left: 0; }
-
-/* Vertical */
-.uk-grid + .uk-grid-collapse,
-.uk-grid-collapse > .uk-grid-margin { margin-top: 0; }
-
-
-/* Divider
- ========================================================================== */
-
-.uk-grid-divider > * { position: relative; }
-
-.uk-grid-divider > :not(.uk-first-column)::before {
- content: "";
- position: absolute;
- top: 0;
- bottom: 0;
- border-left: $grid-divider-border-width solid $grid-divider-border;
-}
-
-/* Vertical */
-.uk-grid-divider.uk-grid-stack > .uk-grid-margin::before {
- content: "";
- position: absolute;
- left: 0;
- right: 0;
- border-top: $grid-divider-border-width solid $grid-divider-border;
-}
-
-/*
- * Default
- */
-
-/* Horizontal */
-.uk-grid-divider { margin-left: -($grid-gutter-horizontal * 2); }
-.uk-grid-divider > * { padding-left: ($grid-gutter-horizontal * 2); }
-
-.uk-grid-divider > :not(.uk-first-column)::before { left: $grid-gutter-horizontal; }
-
-/* Vertical */
-.uk-grid-divider.uk-grid-stack > .uk-grid-margin { margin-top: ($grid-gutter-vertical * 2); }
-
-.uk-grid-divider.uk-grid-stack > .uk-grid-margin::before {
- top: (-$grid-gutter-vertical);
- left: ($grid-gutter-horizontal * 2);
-}
-
-/* Desktop and bigger */
-@media (min-width: $breakpoint-large) {
-
- /* Horizontal */
- .uk-grid-divider { margin-left: -($grid-gutter-horizontal-l * 2); }
- .uk-grid-divider > * { padding-left: ($grid-gutter-horizontal-l * 2); }
-
- .uk-grid-divider > :not(.uk-first-column)::before { left: $grid-gutter-horizontal-l; }
-
- /* Vertical */
- .uk-grid-divider.uk-grid-stack > .uk-grid-margin { margin-top: ($grid-gutter-vertical-l * 2); }
-
- .uk-grid-divider.uk-grid-stack > .uk-grid-margin::before {
- top: (-$grid-gutter-vertical-l);
- left: ($grid-gutter-horizontal-l * 2);
- }
-
-}
-
-/*
- * Small
- */
-
-/* Horizontal */
-.uk-grid-divider.uk-grid-small { margin-left: -($grid-small-gutter-horizontal * 2); }
-.uk-grid-divider.uk-grid-small > * { padding-left: ($grid-small-gutter-horizontal * 2); }
-
-.uk-grid-divider.uk-grid-small > :not(.uk-first-column)::before { left: $grid-small-gutter-horizontal; }
-
-/* Vertical */
-.uk-grid-divider.uk-grid-small.uk-grid-stack > .uk-grid-margin { margin-top: ($grid-small-gutter-vertical * 2); }
-
-.uk-grid-divider.uk-grid-small.uk-grid-stack > .uk-grid-margin::before {
- top: (-$grid-small-gutter-vertical);
- left: ($grid-small-gutter-horizontal * 2);
-}
-
-/*
- * Medium
- */
-
-/* Horizontal */
-.uk-grid-divider.uk-grid-medium { margin-left: -($grid-medium-gutter-horizontal * 2); }
-.uk-grid-divider.uk-grid-medium > * { padding-left: ($grid-medium-gutter-horizontal * 2); }
-
-.uk-grid-divider.uk-grid-medium > :not(.uk-first-column)::before { left: $grid-medium-gutter-horizontal; }
-
-/* Vertical */
-.uk-grid-divider.uk-grid-medium.uk-grid-stack > .uk-grid-margin { margin-top: ($grid-medium-gutter-vertical * 2); }
-
-.uk-grid-divider.uk-grid-medium.uk-grid-stack > .uk-grid-margin::before {
- top: (-$grid-medium-gutter-vertical);
- left: ($grid-medium-gutter-horizontal * 2);
-}
-
-/*
- * Large
- */
-
-/* Horizontal */
-.uk-grid-divider.uk-grid-large { margin-left: -($grid-large-gutter-horizontal * 2); }
-.uk-grid-divider.uk-grid-large > * { padding-left: ($grid-large-gutter-horizontal * 2); }
-
-.uk-grid-divider.uk-grid-large > :not(.uk-first-column)::before { left: $grid-large-gutter-horizontal; }
-
-/* Vertical */
-.uk-grid-divider.uk-grid-large.uk-grid-stack > .uk-grid-margin { margin-top: ($grid-large-gutter-vertical * 2); }
-
-.uk-grid-divider.uk-grid-large.uk-grid-stack > .uk-grid-margin::before {
- top: (-$grid-large-gutter-vertical);
- left: ($grid-large-gutter-horizontal * 2);
-}
-
-/* Desktop and bigger */
-@media (min-width: $breakpoint-large) {
-
- /* Horizontal */
- .uk-grid-divider.uk-grid-large { margin-left: -($grid-large-gutter-horizontal-l * 2); }
- .uk-grid-divider.uk-grid-large > * { padding-left: ($grid-large-gutter-horizontal-l * 2); }
-
- .uk-grid-divider.uk-grid-large > :not(.uk-first-column)::before { left: $grid-large-gutter-horizontal-l; }
-
- /* Vertical */
- .uk-grid-divider.uk-grid-large.uk-grid-stack > .uk-grid-margin { margin-top: ($grid-large-gutter-vertical-l * 2); }
-
- .uk-grid-divider.uk-grid-large.uk-grid-stack > .uk-grid-margin::before {
- top: (-$grid-large-gutter-vertical-l);
- left: ($grid-large-gutter-horizontal-l * 2);
- }
-
-}
-
-
-/* Match child of a grid cell
- ========================================================================== */
-
-/*
- * Behave like a block element
- * 1. Wrap into the next line
- * 2. Take the full width, at least 100%. Only if no class from the Width component is set.
- * 3. Expand width even if larger than 100%, e.g. because of negative margin (Needed for nested grids)
- */
-
-.uk-grid-match > *,
-.uk-grid-item-match {
- display: flex;
- /* 1 */
- flex-wrap: wrap;
-}
-
-.uk-grid-match > * > :not([class*='uk-width']),
-.uk-grid-item-match > :not([class*='uk-width']) {
- /* 2 */
- box-sizing: border-box;
- width: 100%;
- /* 3 */
- flex: auto;
-}
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-grid-misc)) {@include hook-grid-misc();}
-
-// @mixin hook-grid-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-$inverse-grid-divider-border: $inverse-global-border !default;
-
-
diff --git a/_sass/uikit/components/heading.scss b/_sass/uikit/components/heading.scss
deleted file mode 100644
index 97f1c18517..0000000000
--- a/_sass/uikit/components/heading.scss
+++ /dev/null
@@ -1,214 +0,0 @@
-// Name: Heading
-// Description: Styles for headings
-//
-// Component: `uk-heading-primary`
-// `uk-heading-hero`
-// `uk-heading-divider`
-// `uk-heading-bullet`
-// `uk-heading-line`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$heading-primary-font-size: $global-xxlarge-font-size !default;
-$heading-primary-line-height: 1.2 !default;
-
-$heading-primary-font-size-m: 3.75rem !default; // 54px
-$heading-primary-line-height-m: 1.1 !default;
-
-$heading-hero-font-size: 4rem !default; // 64px
-$heading-hero-line-height: 1.1 !default;
-
-$heading-hero-font-size-s: 6rem !default; // 96px
-$heading-hero-line-height-s: 1 !default;
-
-$heading-hero-font-size-m: 8rem !default; // 128px
-$heading-hero-line-height-m: 1 !default;
-
-$heading-divider-padding-bottom: 10px !default;
-$heading-divider-border-width: $global-border-width !default;
-$heading-divider-border: $global-border !default;
-
-$heading-bullet-top: unquote('calc(-0.1 * 1em)') !default;
-$heading-bullet-height: 0.9em !default;
-$heading-bullet-margin-right: 10px !default;
-$heading-bullet-border-width: 5px !default;
-$heading-bullet-border: $global-border !default;
-
-$heading-line-top: 50% !default;
-$heading-line-height: $heading-line-border-width !default;
-$heading-line-width: 2000px !default;
-$heading-line-border-width: $global-border-width !default;
-$heading-line-border: $global-border !default;
-$heading-line-margin-horizontal: 0.6em !default;
-
-
-/* ========================================================================
- Component: Heading
- ========================================================================== */
-
-
-/* Primary
- ========================================================================== */
-
-.uk-heading-primary {
- font-size: $heading-primary-font-size;
- line-height: $heading-primary-line-height;
- @if(mixin-exists(hook-heading-primary)) {@include hook-heading-primary();}
-}
-
-/* Tablet landscape and bigger */
-@media (min-width: $breakpoint-medium) {
-
- .uk-heading-primary {
- font-size: $heading-primary-font-size-m;
- line-height: $heading-primary-line-height-m;
- }
-
-}
-
-
-/* Hero
- ========================================================================== */
-
-.uk-heading-hero {
- font-size: $heading-hero-font-size;
- line-height: $heading-hero-line-height;
- @if(mixin-exists(hook-heading-hero)) {@include hook-heading-hero();}
-}
-
-/* Phone landscape and bigger */
-@media (min-width: $breakpoint-small) {
-
- .uk-heading-hero {
- font-size: $heading-hero-font-size-s;
- line-height: $heading-hero-line-height-s;
- }
-
-}
-
-/* Tablet landscape and bigger */
-@media (min-width: $breakpoint-medium) {
-
- .uk-heading-hero {
- font-size: $heading-hero-font-size-m;
- line-height: $heading-hero-line-height-m;
- }
-
-}
-
-
-/* Divider
- ========================================================================== */
-
-.uk-heading-divider {
- padding-bottom: $heading-divider-padding-bottom;
- border-bottom: $heading-divider-border-width solid $heading-divider-border;
- @if(mixin-exists(hook-heading-divider)) {@include hook-heading-divider();}
-}
-
-
-/* Bullet
- ========================================================================== */
-
-.uk-heading-bullet { position: relative; }
-
-/*
- * 1. Using `inline-block` to make it work with text alignment
- * 2. Center vertically
- * 3. Style
- */
-
-.uk-heading-bullet::before {
- content: "";
- /* 1 */
- display: inline-block;
- /* 2 */
- position: relative;
- top: $heading-bullet-top;
- vertical-align: middle;
- /* 3 */
- height: $heading-bullet-height;
- margin-right: $heading-bullet-margin-right;
- border-left: $heading-bullet-border-width solid $heading-bullet-border;
- @if(mixin-exists(hook-heading-bullet)) {@include hook-heading-bullet();}
-}
-
-
-/* Line
- ========================================================================== */
-
-/*
- * Clip the child element
- */
-
-.uk-heading-line { overflow: hidden; }
-
-/*
- * Extra markup is needed to make it work with text align
- */
-
-.uk-heading-line > * {
- display: inline-block;
- position: relative;
-}
-
-/*
- * 1. Center vertically
- * 2. Make the element as large as possible. It's clipped by the container.
- * 3. Style
- */
-
-.uk-heading-line > ::before,
-.uk-heading-line > ::after {
- content: "";
- /* 1 */
- position: absolute;
- top: unquote('calc(#{$heading-line-top} - (#{$heading-line-height} / 2))');
- /* 2 */
- width: $heading-line-width;
- /* 3 */
- border-bottom: $heading-line-border-width solid $heading-line-border;
- @if(mixin-exists(hook-heading-line)) {@include hook-heading-line();}
-}
-
-.uk-heading-line > ::before {
- right: 100%;
- margin-right: $heading-line-margin-horizontal;
-}
-.uk-heading-line > ::after {
- left: 100%;
- margin-left: $heading-line-margin-horizontal;
-}
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-heading-misc)) {@include hook-heading-misc();}
-
-// @mixin hook-heading-primary(){}
-// @mixin hook-heading-hero(){}
-// @mixin hook-heading-divider(){}
-// @mixin hook-heading-bullet(){}
-// @mixin hook-heading-line(){}
-// @mixin hook-heading-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-$inverse-heading-divider-border: $inverse-global-border !default;
-$inverse-heading-bullet-border: $inverse-global-border !default;
-$inverse-heading-line-border: $inverse-global-border !default;
-
-
-
-// @mixin hook-inverse-heading-primary(){}
-// @mixin hook-inverse-heading-hero(){}
-// @mixin hook-inverse-heading-divider(){}
-// @mixin hook-inverse-heading-bullet(){}
-// @mixin hook-inverse-heading-line(){}
diff --git a/_sass/uikit/components/icon.scss b/_sass/uikit/components/icon.scss
deleted file mode 100644
index 2ff70ecf4f..0000000000
--- a/_sass/uikit/components/icon.scss
+++ /dev/null
@@ -1,223 +0,0 @@
-// Name: Icon
-// Description: Component to create icons
-//
-// Component: `uk-icon`
-//
-// Modifiers: `uk-icon-image`
-// `uk-icon-link`
-// `uk-icon-button`
-//
-// States: `uk-preserve`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$icon-image-size: 20px !default;
-
-$icon-link-color: $global-muted-color !default;
-$icon-link-hover-color: $global-color !default;
-$icon-link-active-color: darken($global-color, 5%) !default;
-
-$icon-button-size: 36px !default;
-$icon-button-border-radius: 500px !default;
-$icon-button-background: $global-muted-background !default;
-$icon-button-color: $global-muted-color !default;
-
-$icon-button-hover-background: darken($icon-button-background, 5%) !default;
-$icon-button-hover-color: $global-color !default;
-
-$icon-button-active-background: darken($icon-button-background, 10%) !default;
-$icon-button-active-color: $global-color !default;
-
-
-/* ========================================================================
- Component: Icon
- ========================================================================== */
-
-/*
- * Note: 1. - 7. is required for `button` elements. Needed for Close and Form Icon component.
- * 1. Remove margins in Chrome, Safari and Opera.
- * 2. Remove borders for `button`.
- * 3. Remove border-radius in Chrome.
- * 4. Address `overflow` set to `hidden` in IE.
- * 5. Correct `font` properties and `color` not being inherited for `button`.
- * 6. Remove the inheritance of text transform in Edge, Firefox, and IE.
- * 7. Remove default `button` padding and background color
- * 8. Style
- * 9. Fill all SVG elements with the current text color if no `fill` attribute is set
- * 10. Let the container fit the height of the icon
- */
-
-.uk-icon {
- /* 1 */
- margin: 0;
- /* 2 */
- border: none;
- /* 3 */
- border-radius: 0;
- /* 4 */
- overflow: visible;
- /* 5 */
- font: inherit;
- color: inherit;
- /* 6 */
- text-transform: none;
- /* 7. */
- padding: 0;
- background-color: transparent;
- /* 8 */
- display: inline-block;
- /* 9 */
- fill: currentcolor;
- /* 10 */
- line-height: 0;
-}
-
-/* Required for `button`. */
-button.uk-icon:not(:disabled) { cursor: pointer; }
-
-/*
- * Remove the inner border and padding in Firefox.
- */
-
-.uk-icon::-moz-focus-inner {
- border: 0;
- padding: 0;
-}
-
-/*
- * Set the fill and stroke color of all SVG elements to the current text color
- * 1. Fix for uppercase attribute names in Edge. Will be fixed in Windows 10 builds 16251+
- */
-
-.uk-icon [fill*='#']:not(.uk-preserve),
-.uk-icon [FILL*='#']:not(.uk-preserve) { fill: currentcolor; } // 1
-.uk-icon [stroke*='#']:not(.uk-preserve),
-.uk-icon [STROKE*='#']:not(.uk-preserve) { stroke: currentcolor; } // 1
-
-/*
- * Fix Firefox blurry SVG rendering: https://bugzilla.mozilla.org/show_bug.cgi?id=1046835
- */
-
-.uk-icon > * { transform: translate(0,0); }
-
-
-/* Image modifier
- ========================================================================== */
-
-/*
- * Display images in icon dimensions
- */
-
-.uk-icon-image {
- width: $icon-image-size;
- height: $icon-image-size;
- background-position: 50% 50%;
- background-repeat: no-repeat;
- background-size: contain;
- vertical-align: middle;
-}
-
-
-/* Style modifiers
- ========================================================================== */
-
-/*
- * Link
- */
-
-.uk-icon-link {
- color: $icon-link-color;
- @if(mixin-exists(hook-icon-link)) {@include hook-icon-link();}
-}
-
-.uk-icon-link:hover,
-.uk-icon-link:focus {
- color: $icon-link-hover-color;
- outline: none;
- @if(mixin-exists(hook-icon-link-hover)) {@include hook-icon-link-hover();}
-}
-
-/* OnClick + Active */
-.uk-icon-link:active,
-.uk-active > .uk-icon-link {
- color: $icon-link-active-color;
- @if(mixin-exists(hook-icon-link-active)) {@include hook-icon-link-active();}
-}
-
-/*
- * Button
- * 1. Center icon vertically and horizontally
- */
-
-.uk-icon-button {
- box-sizing: border-box;
- width: $icon-button-size;
- height: $icon-button-size;
- border-radius: $icon-button-border-radius;
- background: $icon-button-background;
- color: $icon-button-color;
- vertical-align: middle;
- /* 1 */
- display: inline-flex;
- justify-content: center;
- align-items: center;
- @if(mixin-exists(hook-icon-button)) {@include hook-icon-button();}
-}
-
-/* Hover + Focus */
-.uk-icon-button:hover,
-.uk-icon-button:focus {
- background-color: $icon-button-hover-background;
- color: $icon-button-hover-color;
- outline: none;
- @if(mixin-exists(hook-icon-button-hover)) {@include hook-icon-button-hover();}
-}
-
-/* OnClick + Active */
-.uk-icon-button:active,
-.uk-active > .uk-icon-button {
- background-color: $icon-button-active-background;
- color: $icon-button-active-color;
- @if(mixin-exists(hook-icon-button-active)) {@include hook-icon-button-active();}
-}
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-icon-misc)) {@include hook-icon-misc();}
-
-// @mixin hook-icon-link(){}
-// @mixin hook-icon-link-hover(){}
-// @mixin hook-icon-link-active(){}
-// @mixin hook-icon-button(){}
-// @mixin hook-icon-button-hover(){}
-// @mixin hook-icon-button-active(){}
-// @mixin hook-icon-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-$inverse-icon-link-color: $inverse-global-muted-color !default;
-$inverse-icon-link-hover-color: $inverse-global-color !default;
-$inverse-icon-link-active-color: $inverse-global-color !default;
-$inverse-icon-button-background: $inverse-global-muted-background !default;
-$inverse-icon-button-color: $inverse-global-muted-color !default;
-$inverse-icon-button-hover-background: darken($inverse-icon-button-background, 5%) !default;
-$inverse-icon-button-hover-color: $inverse-global-color !default;
-$inverse-icon-button-active-background: darken($inverse-icon-button-background, 10%) !default;
-$inverse-icon-button-active-color: $inverse-global-color !default;
-
-
-
-// @mixin hook-inverse-icon-link(){}
-// @mixin hook-inverse-icon-link-hover(){}
-// @mixin hook-inverse-icon-link-active(){}
-// @mixin hook-inverse-icon-button(){}
-// @mixin hook-inverse-icon-button-hover(){}
-// @mixin hook-inverse-icon-button-active(){}
diff --git a/_sass/uikit/components/iconnav.scss b/_sass/uikit/components/iconnav.scss
deleted file mode 100644
index ae739c9042..0000000000
--- a/_sass/uikit/components/iconnav.scss
+++ /dev/null
@@ -1,140 +0,0 @@
-// Name: Iconnav
-// Description: Component to create icon navigations
-//
-// Component: `uk-iconnav`
-//
-// Modifier: `uk-iconnav-vertical`
-//
-// States: `uk-active`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$iconnav-margin-horizontal: $global-small-margin !default;
-$iconnav-margin-vertical: $iconnav-margin-horizontal !default;
-
-$iconnav-item-color: $global-muted-color !default;
-
-$iconnav-item-hover-color: $global-color !default;
-
-$iconnav-item-active-color: $global-color !default;
-
-
-/* ========================================================================
- Component: Iconnav
- ========================================================================== */
-
-/*
- * 1. Allow items to wrap into the next line
- * 2. Reset list
- * 3. Gutter
- */
-
-.uk-iconnav {
- display: flex;
- /* 1 */
- flex-wrap: wrap;
- /* 2 */
- margin: 0;
- padding: 0;
- list-style: none;
- /* 3 */
- margin-left: (-$iconnav-margin-horizontal);
- @if(mixin-exists(hook-iconnav)) {@include hook-iconnav();}
-}
-
-/*
- * 1. Space is allocated solely based on content dimensions: 0 0 auto
- * 2. Gutter
- */
-
-.uk-iconnav > * {
- /* 1 */
- flex: none;
- /* 2 */
- padding-left: $iconnav-margin-horizontal;
-}
-
-
-/* Items
- ========================================================================== */
-
-/*
- * Items must target `a` elements to exclude other elements (e.g. dropdowns)
- * 1. Prevent gap if child element is `inline-block`, e.g. an icon
- * 2. Style
- */
-
-.uk-iconnav > * > a {
- /* 1 */
- display: block;
- /* 2 */
- color: $iconnav-item-color;
- @if(mixin-exists(hook-iconnav-item)) {@include hook-iconnav-item();}
-}
-
-/* Hover + Focus */
-.uk-iconnav > * > a:hover,
-.uk-iconnav > * > a:focus {
- color: $iconnav-item-hover-color;
- outline: none;
- @if(mixin-exists(hook-iconnav-item-hover)) {@include hook-iconnav-item-hover();}
-}
-
-/* Active */
-.uk-iconnav > .uk-active > a {
- color: $iconnav-item-active-color;
- @if(mixin-exists(hook-iconnav-item-active)) {@include hook-iconnav-item-active();}
-}
-
-
-/* Modifier: 'uk-iconnav-vertical'
- ========================================================================== */
-
-/*
- * 1. Change direction
- * 2. Gutter
- */
-
-.uk-iconnav-vertical {
- /* 1 */
- flex-direction: column;
- /* 2 */
- margin-left: 0;
- margin-top: (-$iconnav-margin-vertical);
-}
-
-/* 2 */
-.uk-iconnav-vertical > * {
- padding-left: 0;
- padding-top: $iconnav-margin-vertical;
-}
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-iconnav-misc)) {@include hook-iconnav-misc();}
-
-// @mixin hook-iconnav(){}
-// @mixin hook-iconnav-item(){}
-// @mixin hook-iconnav-item-hover(){}
-// @mixin hook-iconnav-item-active(){}
-// @mixin hook-iconnav-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-$inverse-iconnav-item-color: $inverse-global-muted-color !default;
-$inverse-iconnav-item-hover-color: $inverse-global-color !default;
-$inverse-iconnav-item-active-color: $inverse-global-color !default;
-
-
-
-// @mixin hook-inverse-iconnav-item(){}
-// @mixin hook-inverse-iconnav-item-hover(){}
-// @mixin hook-inverse-iconnav-item-active(){}
\ No newline at end of file
diff --git a/_sass/uikit/components/inverse.scss b/_sass/uikit/components/inverse.scss
deleted file mode 100644
index c1b0c07c78..0000000000
--- a/_sass/uikit/components/inverse.scss
+++ /dev/null
@@ -1,46 +0,0 @@
-// Name: Inverse
-// Description: Inverse component style for light or dark backgrounds
-//
-// Component: `uk-light`
-// `uk-dark`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$inverse-global-color-mode: light !default;
-
-$inverse-global-color: rgba($global-inverse-color, 0.7) !default;
-$inverse-global-emphasis-color: $global-inverse-color !default;
-$inverse-global-muted-color: rgba($global-inverse-color, 0.5) !default;
-$inverse-global-inverse-color: $global-color !default;
-
-$inverse-global-primary-background: $global-inverse-color !default;
-$inverse-global-muted-background: rgba($global-inverse-color, 0.1) !default;
-
-$inverse-global-border: rgba($global-inverse-color, 0.2) !default;
-
-
-/* ========================================================================
- Component: Inverse
- ========================================================================== */
-
-
-
-/*
- * Implemented class depends on the general theme color
- * `uk-light` is for light colors on dark backgrounds
- * `uk-dark` is or dark colors on light backgrounds
- */
-
-@if ($inverse-global-color-mode == light) { .uk-light { @if(mixin-exists(hook-inverse)) {@include hook-inverse();}}}
-
-@if ($inverse-global-color-mode == dark) { .uk-dark { @if(mixin-exists(hook-inverse)) {@include hook-inverse();}}}
-
-
-// Hooks
-// ========================================================================
-
-// @mixin hook-inverse(){}
\ No newline at end of file
diff --git a/_sass/uikit/components/label.scss b/_sass/uikit/components/label.scss
deleted file mode 100644
index 6600aedfab..0000000000
--- a/_sass/uikit/components/label.scss
+++ /dev/null
@@ -1,102 +0,0 @@
-// Name: Label
-// Description: Component to indicate important notes
-//
-// Component: `uk-label`
-//
-// Modifiers: `uk-label-success`
-// `uk-label-warning`
-// `uk-label-danger`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$label-padding-vertical: 0 !default;
-$label-padding-horizontal: $global-small-margin !default;
-$label-background: $global-primary-background !default;
-$label-line-height: $global-line-height !default;
-$label-font-size: $global-small-font-size !default;
-$label-color: $global-inverse-color !default;
-
-$label-success-background: $global-success-background !default;
-$label-success-color: $global-inverse-color !default;
-$label-warning-background: $global-warning-background !default;
-$label-warning-color: $global-inverse-color !default;
-$label-danger-background: $global-danger-background !default;
-$label-danger-color: $global-inverse-color !default;
-
-
-/* ========================================================================
- Component: Label
- ========================================================================== */
-
-.uk-label {
- display: inline-block;
- padding: $label-padding-vertical $label-padding-horizontal;
- background: $label-background;
- line-height: $label-line-height;
- font-size: $label-font-size;
- color: $label-color;
- vertical-align: middle;
- white-space: nowrap;
- @if(mixin-exists(hook-label)) {@include hook-label();}
-}
-
-
-/* Color modifiers
- ========================================================================== */
-
-/*
- * Success
- */
-
-.uk-label-success {
- background-color: $label-success-background;
- color: $label-success-color;
- @if(mixin-exists(hook-label-success)) {@include hook-label-success();}
-}
-
-/*
- * Warning
- */
-
-.uk-label-warning {
- background-color: $label-warning-background;
- color: $label-warning-color;
- @if(mixin-exists(hook-label-warning)) {@include hook-label-warning();}
-}
-
-/*
- * Danger
- */
-
-.uk-label-danger {
- background-color: $label-danger-background;
- color: $label-danger-color;
- @if(mixin-exists(hook-label-danger)) {@include hook-label-danger();}
-}
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-label-misc)) {@include hook-label-misc();}
-
-// @mixin hook-label(){}
-// @mixin hook-label-success(){}
-// @mixin hook-label-warning(){}
-// @mixin hook-label-danger(){}
-// @mixin hook-label-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-$inverse-label-background: $inverse-global-primary-background !default;
-$inverse-label-color: $inverse-global-inverse-color !default;
-
-
-
-// @mixin hook-inverse-label(){}
\ No newline at end of file
diff --git a/_sass/uikit/components/lightbox.scss b/_sass/uikit/components/lightbox.scss
deleted file mode 100644
index 4f9c698df8..0000000000
--- a/_sass/uikit/components/lightbox.scss
+++ /dev/null
@@ -1,232 +0,0 @@
-// Name: Lightbox
-// Description: Component to create an lightbox image gallery
-//
-// Component: `uk-lightbox`
-//
-// Sub-objects: `uk-lightbox-page`
-// `uk-lightbox-items`
-// `uk-lightbox-toolbar`
-// `uk-lightbox-toolbar-icon`
-// `uk-lightbox-button`
-// `uk-lightbox-caption`
-// `uk-lightbox-iframe`
-//
-// States: `uk-open`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$lightbox-z-index: $global-z-index + 10 !default;
-$lightbox-background: #000 !default;
-
-$lightbox-item-color: rgba(255,255,255,0.7) !default;
-
-$lightbox-toolbar-padding-vertical: 10px !default;
-$lightbox-toolbar-padding-horizontal: 10px !default;
-$lightbox-toolbar-background: rgba(0,0,0,0.3) !default;
-$lightbox-toolbar-color: rgba(255,255,255,0.7) !default;
-
-$lightbox-toolbar-icon-padding: 5px !default;
-$lightbox-toolbar-icon-color: rgba(255,255,255,0.7) !default;
-
-$lightbox-toolbar-icon-hover-color: #fff !default;
-
-$lightbox-button-size: 50px !default;
-$lightbox-button-background: $lightbox-toolbar-background !default;
-$lightbox-button-color: rgba(255,255,255,0.7) !default;
-
-$lightbox-button-hover-color: #fff !default;
-
-
-/* ========================================================================
- Component: Lightbox
- ========================================================================== */
-
-/*
- * 1. Hide by default
- * 2. Set position
- * 3. Allow scrolling for the modal dialog
- * 4. Horizontal padding
- * 5. Mask the background page
- * 6. Fade-in transition
- */
-
-.uk-lightbox {
- /* 1 */
- display: none;
- /* 2 */
- position: fixed;
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
- z-index: $lightbox-z-index;
- /* 5 */
- background: $lightbox-background;
- /* 6 */
- opacity: 0;
- transition: opacity 0.15s linear;
- @if(mixin-exists(hook-lightbox)) {@include hook-lightbox();}
-}
-
-/*
- * Open
- * 1. Center child
- * 2. Fade-in
- */
-
-.uk-lightbox.uk-open {
- display: block;
- /* 2 */
- opacity: 1;
-}
-
-
-/* Page
- ========================================================================== */
-
-/*
- * Prevent scrollbars
- */
-
-.uk-lightbox-page { overflow: hidden; }
-
-
-/* Item
- ========================================================================== */
-
-/*
- * 1. Center child within the viewport
- * 2. Not visible by default
- * 3. Color needed for spinner icon
- * 4. Optimize animation
- * 5. Responsiveness
- * Using `vh` for `max-height` to fix image proportions after resize in Safari and Opera
- * Using `vh` and `vw` to make responsive image work in IE11
- */
-
-.uk-lightbox-items > * {
- /* 1 */
- position: absolute;
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
- /* 2 */
- display: none;
- justify-content: center;
- align-items: center;
- /* 3 */
- color: $lightbox-item-color;
- /* 4 */
- will-change: transform, opacity;
- @if(mixin-exists(hook-lightbox-item)) {@include hook-lightbox-item();}
-}
-
-/* 5 */
-.uk-lightbox-items > * > * {
- max-width: 100vw;
- max-height: 100vh;
-}
-
-.uk-lightbox-items > * > :not(iframe) {
- width: auto;
- height: auto;
-}
-
-.uk-lightbox-items > .uk-active { display: flex; }
-
-/* Toolbar
- ========================================================================== */
-
-.uk-lightbox-toolbar {
- padding: $lightbox-toolbar-padding-vertical $lightbox-toolbar-padding-horizontal;
- background: $lightbox-toolbar-background;
- color: $lightbox-toolbar-color;
- @if(mixin-exists(hook-lightbox-toolbar)) {@include hook-lightbox-toolbar();}
-}
-
-.uk-lightbox-toolbar * { color: $lightbox-toolbar-color; }
-
-
-/* Toolbar Icon (Close)
- ========================================================================== */
-
-.uk-lightbox-toolbar-icon {
- padding: $lightbox-toolbar-icon-padding;
- color: $lightbox-toolbar-icon-color;
- @if(mixin-exists(hook-lightbox-toolbar-icon)) {@include hook-lightbox-toolbar-icon();}
-}
-
-/*
- * Hover
- */
-
-.uk-lightbox-toolbar-icon:hover {
- color: $lightbox-toolbar-icon-hover-color;
- @if(mixin-exists(hook-lightbox-toolbar-icon-hover)) {@include hook-lightbox-toolbar-icon-hover();}
-}
-
-
-
-/* Button (Slidenav)
- ========================================================================== */
-
-/*
- * 1. Center icon vertically and horizontally
- */
-
-.uk-lightbox-button {
- box-sizing: border-box;
- width: $lightbox-button-size;
- height: $lightbox-button-size;
- background: $lightbox-button-background;
- color: $lightbox-button-color;
- /* 1 */
- display: inline-flex;
- justify-content: center;
- align-items: center;
- @if(mixin-exists(hook-lightbox-button)) {@include hook-lightbox-button();}
-}
-
-/*
- * Hover
- */
-
-.uk-lightbox-button:hover {
- color: $lightbox-button-hover-color;
- @if(mixin-exists(hook-lightbox-button-hover)) {@include hook-lightbox-button-hover();}
-}
-
-
-/* Caption
- ========================================================================== */
-
-.uk-lightbox-caption {}
-
-
-/* Iframe
- ========================================================================== */
-
-.uk-lightbox-iframe {
- width: 80%;
- height: 80%;
-}
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-lightbox-misc)) {@include hook-lightbox-misc();}
-
-// @mixin hook-lightbox(){}
-// @mixin hook-lightbox-item(){}
-// @mixin hook-lightbox-toolbar(){}
-// @mixin hook-lightbox-toolbar-icon(){}
-// @mixin hook-lightbox-toolbar-icon-hover(){}
-// @mixin hook-lightbox-button(){}
-// @mixin hook-lightbox-button-hover(){}
-// @mixin hook-lightbox-misc(){}
diff --git a/_sass/uikit/components/link.scss b/_sass/uikit/components/link.scss
deleted file mode 100644
index 9e0ef0e747..0000000000
--- a/_sass/uikit/components/link.scss
+++ /dev/null
@@ -1,123 +0,0 @@
-// Name: Link
-// Description: Styles for links
-//
-// Component: `uk-link-muted`
-// `uk-link-text`
-// `uk-link-heading`
-// `uk-link-reset`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$link-muted-color: $global-muted-color !default;
-$link-muted-hover-color: $global-color !default;
-
-$link-text-hover-color: $global-muted-color !default;
-
-$link-heading-hover-color: $global-primary-background !default;
-$link-heading-hover-text-decoration: none !default;
-
-
-/* ========================================================================
- Component: Link
- ========================================================================== */
-
-
-/* Muted
- ========================================================================== */
-
-a.uk-link-muted,
-.uk-link-muted a {
- color: $link-muted-color;
- @if(mixin-exists(hook-link-muted)) {@include hook-link-muted();}
-}
-
-a.uk-link-muted:hover,
-.uk-link-muted a:hover {
- color: $link-muted-hover-color;
- @if(mixin-exists(hook-link-muted-hover)) {@include hook-link-muted-hover();}
-}
-
-
-/* Text
- ========================================================================== */
-
-a.uk-link-text:not(:hover),
-.uk-link-text a:not(:hover) {
- color: inherit;
- @if(mixin-exists(hook-link-text)) {@include hook-link-text();}
-}
-
-a.uk-link-text:hover,
-.uk-link-text a:hover {
- color: $link-text-hover-color;
- @if(mixin-exists(hook-link-text-hover)) {@include hook-link-text-hover();}
-}
-
-
-/* Heading
- ========================================================================== */
-
-a.uk-link-heading:not(:hover),
-.uk-link-heading a:not(:hover) {
- color: inherit;
- @if(mixin-exists(hook-link-heading)) {@include hook-link-heading();}
-}
-
-a.uk-link-heading:hover,
-.uk-link-heading a:hover {
- color: $link-heading-hover-color;
- text-decoration: $link-heading-hover-text-decoration;
- @if(mixin-exists(hook-link-heading-hover)) {@include hook-link-heading-hover();}
-}
-
-
-/* Reset
- ========================================================================== */
-
-/*
- * `!important` needed to override inverse component
- */
-
-a.uk-link-reset,
-a.uk-link-reset:hover,
-.uk-link-reset a,
-.uk-link-reset a:hover {
- color: inherit !important;
- text-decoration: none !important;
- @if(mixin-exists(hook-link-reset)) {@include hook-link-reset();}
-}
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-link-misc)) {@include hook-link-misc();}
-
-// @mixin hook-link-muted(){}
-// @mixin hook-link-muted-hover(){}
-// @mixin hook-link-text(){}
-// @mixin hook-link-text-hover(){}
-// @mixin hook-link-heading(){}
-// @mixin hook-link-heading-hover(){}
-// @mixin hook-link-reset(){}
-// @mixin hook-link-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-$inverse-link-muted-color: $inverse-global-muted-color !default;
-$inverse-link-muted-hover-color: $inverse-global-color !default;
-$inverse-link-text-hover-color: $inverse-global-muted-color !default;
-$inverse-link-heading-hover-color: $inverse-global-primary-background !default;
-
-
-
-// @mixin hook-inverse-link-muted(){}
-// @mixin hook-inverse-link-muted-hover(){}
-// @mixin hook-inverse-link-text-hover(){}
-// @mixin hook-inverse-link-heading-hover(){}
diff --git a/_sass/uikit/components/list.scss b/_sass/uikit/components/list.scss
deleted file mode 100644
index ed810bb010..0000000000
--- a/_sass/uikit/components/list.scss
+++ /dev/null
@@ -1,187 +0,0 @@
-// Name: List
-// Description: Styles for lists
-//
-// Component: `uk-list`
-//
-// Modifiers: `uk-list-divider`
-// `uk-list-striped`
-// `uk-list-bullet`
-// `uk-list-large`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$list-margin-top: $global-small-margin !default;
-
-$list-nested-padding-left: $global-gutter !default;
-
-$list-divider-margin-top: $global-small-margin !default;
-$list-divider-border-width: $global-border-width !default;
-$list-divider-border: $global-border !default;
-
-$list-striped-padding-vertical: $global-small-margin !default;
-$list-striped-padding-horizontal: $global-small-margin !default;
-$list-striped-background: $global-muted-background !default;
-
-$list-bullet-width: ($global-line-height * 1em) !default;
-$list-bullet-height: $list-bullet-width !default;
-$list-bullet-margin-right: $global-small-margin !default;
-$list-bullet-icon-color: $global-color !default;
-
-$list-large-margin-top: $global-margin !default;
-$list-large-divider-margin-top: $global-margin !default;
-$list-large-striped-padding-vertical: $global-margin !default;
-$list-large-striped-padding-horizontal: $global-small-margin !default;
-
-$internal-list-bullet-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%226%22%20height%3D%226%22%20viewBox%3D%220%200%206%206%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Ccircle%20fill%3D%22#000%22%20cx%3D%223%22%20cy%3D%223%22%20r%3D%223%22%20%2F%3E%0A%3C%2Fsvg%3E" !default;
-
-
-/* ========================================================================
- Component: List
- ========================================================================== */
-
-.uk-list {
- padding: 0;
- list-style: none;
-}
-
-/*
- * Micro clearfix
- */
-
-.uk-list > li::before,
-.uk-list > li::after {
- content: "";
- display: table;
-}
-
-.uk-list > li::after { clear: both; }
-
-/*
- * Remove margin from the last-child
- */
-
-.uk-list > li > :last-child { margin-bottom: 0; }
-
-/*
- * Nested lists
- */
-
-.uk-list ul {
- margin: 0;
- padding-left: $list-nested-padding-left;
- list-style: none;
-}
-
-/*
- * Style
- */
-
-.uk-list > li:nth-child(n+2),
-.uk-list > li > ul { margin-top: $list-margin-top; }
-
-
-/* Style modifiers
- ========================================================================== */
-
-/*
- * Divider
- */
-
-.uk-list-divider > li:nth-child(n+2) {
- margin-top: $list-divider-margin-top;
- padding-top: $list-divider-margin-top;
- border-top: $list-divider-border-width solid $list-divider-border;
- @if(mixin-exists(hook-list-divider)) {@include hook-list-divider();}
-}
-
-/*
- * Striped
- */
-
-.uk-list-striped > li {
- padding: $list-striped-padding-vertical $list-striped-padding-horizontal;
- @if(mixin-exists(hook-list-striped)) {@include hook-list-striped();}
-}
-
-.uk-list-striped > li:nth-of-type(odd) { background: $list-striped-background; }
-
-.uk-list-striped > li:nth-child(n+2) { margin-top: 0; }
-
-/*
- * Bullet
- */
-
-.uk-list-bullet > li {
- position: relative;
- padding-left: unquote('calc(#{$list-bullet-width} + #{$list-bullet-margin-right})');
-}
-
-.uk-list-bullet > li::before {
- content: "";
- position: absolute;
- top: 0;
- left: 0;
- width: $list-bullet-width;
- height: $list-bullet-height;
- @include svg-fill($internal-list-bullet-image, "#000", $list-bullet-icon-color);
- background-repeat: no-repeat;
- background-position: 50% 50%;
- float: left;
- @if(mixin-exists(hook-list-bullet)) {@include hook-list-bullet();}
-}
-
-
-/* Size modifier
- ========================================================================== */
-
-.uk-list-large > li:nth-child(n+2),
-.uk-list-large > li > ul { margin-top: $list-large-margin-top; }
-
-/*
- * Divider
- */
-
-.uk-list-large.uk-list-divider > li:nth-child(n+2) {
- margin-top: $list-large-divider-margin-top;
- padding-top: $list-large-divider-margin-top;
-}
-
-/*
- * Striped
- */
-
-.uk-list-large.uk-list-striped > li {
- padding: $list-large-striped-padding-vertical $list-large-striped-padding-horizontal;
- @if(mixin-exists(hook-list-striped)) {@include hook-list-striped();}
-}
-
-.uk-list-large.uk-list-striped > li:nth-child(n+2) { margin-top: 0; }
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-list-misc)) {@include hook-list-misc();}
-
-// @mixin hook-list-divider(){}
-// @mixin hook-list-striped(){}
-// @mixin hook-list-bullet(){}
-// @mixin hook-list-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-$inverse-list-divider-border: $inverse-global-border !default;
-$inverse-list-striped-background: $inverse-global-muted-background !default;
-$inverse-list-bullet-icon-color: $inverse-global-color !default;
-
-
-
-// @mixin hook-inverse-list-divider(){}
-// @mixin hook-inverse-list-striped(){}
-// @mixin hook-inverse-list-bullet(){}
diff --git a/_sass/uikit/components/margin.scss b/_sass/uikit/components/margin.scss
deleted file mode 100644
index c3b136911a..0000000000
--- a/_sass/uikit/components/margin.scss
+++ /dev/null
@@ -1,163 +0,0 @@
-// Name: Margin
-// Description: Utilities for margins
-//
-// Component: `uk-margin-*`
-// `uk-margin-small-*`
-// `uk-margin-medium-*`
-// `uk-margin-large-*`
-// `uk-margin-xlarge-*`
-// `uk-margin-remove-*`
-// `uk-margin-auto-*`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$margin-margin: $global-margin !default;
-
-$margin-small-margin: $global-small-margin !default;
-
-$margin-medium-margin: $global-medium-margin !default;
-
-$margin-large-margin: $global-medium-margin !default;
-$margin-large-margin-l: $global-large-margin !default;
-
-$margin-xlarge-margin: $global-large-margin !default;
-$margin-xlarge-margin-l: $global-xlarge-margin !default;
-
-
-/* ========================================================================
- Component: Margin
- ========================================================================== */
-
-/*
- * Default
- */
-
-.uk-margin { margin-bottom: $margin-margin; }
-* + .uk-margin { margin-top: $margin-margin !important; }
-
-.uk-margin-top { margin-top: $margin-margin !important; }
-.uk-margin-bottom { margin-bottom: $margin-margin !important; }
-.uk-margin-left { margin-left: $margin-margin !important; }
-.uk-margin-right { margin-right: $margin-margin !important; }
-
-
-/* Small
- ========================================================================== */
-
-.uk-margin-small { margin-bottom: $margin-small-margin; }
-* + .uk-margin-small { margin-top: $margin-small-margin !important; }
-
-.uk-margin-small-top { margin-top: $margin-small-margin !important; }
-.uk-margin-small-bottom { margin-bottom: $margin-small-margin !important; }
-.uk-margin-small-left { margin-left: $margin-small-margin !important; }
-.uk-margin-small-right { margin-right: $margin-small-margin !important; }
-
-
-/* Medium
- ========================================================================== */
-
-.uk-margin-medium { margin-bottom: $margin-medium-margin; }
-* + .uk-margin-medium { margin-top: $margin-medium-margin !important; }
-
-.uk-margin-medium-top { margin-top: $margin-medium-margin !important; }
-.uk-margin-medium-bottom { margin-bottom: $margin-medium-margin !important; }
-.uk-margin-medium-left { margin-left: $margin-medium-margin !important; }
-.uk-margin-medium-right { margin-right: $margin-medium-margin !important; }
-
-
-/* Large
- ========================================================================== */
-
-.uk-margin-large { margin-bottom: $margin-large-margin; }
-* + .uk-margin-large { margin-top: $margin-large-margin !important; }
-
-.uk-margin-large-top { margin-top: $margin-large-margin !important; }
-.uk-margin-large-bottom { margin-bottom: $margin-large-margin !important; }
-.uk-margin-large-left { margin-left: $margin-large-margin !important; }
-.uk-margin-large-right { margin-right: $margin-large-margin !important; }
-
-/* Desktop and bigger */
-@media (min-width: $breakpoint-large) {
-
- .uk-margin-large { margin-bottom: $margin-large-margin-l; }
- * + .uk-margin-large { margin-top: $margin-large-margin-l !important; }
-
- .uk-margin-large-top { margin-top: $margin-large-margin-l !important; }
- .uk-margin-large-bottom { margin-bottom: $margin-large-margin-l !important; }
- .uk-margin-large-left { margin-left: $margin-large-margin-l !important; }
- .uk-margin-large-right { margin-right: $margin-large-margin-l !important; }
-
-}
-
-
-/* XLarge
- ========================================================================== */
-
-.uk-margin-xlarge { margin-bottom: $margin-xlarge-margin; }
-* + .uk-margin-xlarge { margin-top: $margin-xlarge-margin !important; }
-
-.uk-margin-xlarge-top { margin-top: $margin-xlarge-margin !important; }
-.uk-margin-xlarge-bottom { margin-bottom: $margin-xlarge-margin !important; }
-.uk-margin-xlarge-left { margin-left: $margin-xlarge-margin !important; }
-.uk-margin-xlarge-right { margin-right: $margin-xlarge-margin !important; }
-
-/* Desktop and bigger */
-@media (min-width: $breakpoint-large) {
-
- .uk-margin-xlarge { margin-bottom: $margin-xlarge-margin-l; }
- * + .uk-margin-xlarge { margin-top: $margin-xlarge-margin-l !important; }
-
- .uk-margin-xlarge-top { margin-top: $margin-xlarge-margin-l !important; }
- .uk-margin-xlarge-bottom { margin-bottom: $margin-xlarge-margin-l !important; }
- .uk-margin-xlarge-left { margin-left: $margin-xlarge-margin-l !important; }
- .uk-margin-xlarge-right { margin-right: $margin-xlarge-margin-l !important; }
-
-}
-
-
-/* Remove
- ========================================================================== */
-
-.uk-margin-remove { margin: 0 !important; }
-.uk-margin-remove-top { margin-top: 0 !important; }
-.uk-margin-remove-bottom { margin-bottom: 0 !important; }
-.uk-margin-remove-left { margin-left: 0 !important; }
-.uk-margin-remove-right { margin-right: 0 !important; }
-
-.uk-margin-remove-vertical {
- margin-top: 0 !important;
- margin-bottom: 0 !important;
-}
-
-.uk-margin-remove-adjacent + * { margin-top: 0 !important; }
-
-
-/* Auto
- ========================================================================== */
-
-.uk-margin-auto {
- margin-left: auto !important;
- margin-right: auto !important;
-}
-
-.uk-margin-auto-top { margin-top: auto !important; }
-.uk-margin-auto-bottom { margin-bottom: auto !important; }
-.uk-margin-auto-left { margin-left: auto !important; }
-.uk-margin-auto-right { margin-right: auto !important; }
-
-.uk-margin-auto-vertical {
- margin-top: auto !important;
- margin-bottom: auto !important;
-}
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-margin-misc)) {@include hook-margin-misc();}
-
-// @mixin hook-margin-misc(){}
diff --git a/_sass/uikit/components/marker.scss b/_sass/uikit/components/marker.scss
deleted file mode 100644
index 97e436098c..0000000000
--- a/_sass/uikit/components/marker.scss
+++ /dev/null
@@ -1,63 +0,0 @@
-// Name: Marker
-// Description: Component to create a marker icon
-//
-// Component: `uk-marker`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$marker-padding: 5px !default;
-$marker-background: $global-secondary-background !default;
-$marker-color: $global-inverse-color !default;
-
-$marker-hover-color: $global-inverse-color !default;
-
-
-/* ========================================================================
- Component: Marker
- ========================================================================== */
-
-/*
- * Addopts `uk-icon`
- */
-
-.uk-marker {
- padding: $marker-padding;
- background: $marker-background;
- color: $marker-color;
- @if(mixin-exists(hook-marker)) {@include hook-marker();}
-}
-
-/* Hover + Focus */
-.uk-marker:hover,
-.uk-marker:focus {
- color: $marker-hover-color;
- outline: none;
- @if(mixin-exists(hook-marker-hover)) {@include hook-marker-hover();}
-}
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-marker-misc)) {@include hook-marker-misc();}
-
-// @mixin hook-marker(){}
-// @mixin hook-marker-hover(){}
-// @mixin hook-marker-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-$inverse-marker-background: $global-muted-background !default;
-$inverse-marker-color: $global-color !default;
-$inverse-marker-hover-color: $global-color !default;
-
-
-
-// @mixin hook-inverse-marker(){}
-// @mixin hook-inverse-marker-hover(){}
diff --git a/_sass/uikit/components/mixin.scss b/_sass/uikit/components/mixin.scss
deleted file mode 100644
index 5ed438a569..0000000000
--- a/_sass/uikit/components/mixin.scss
+++ /dev/null
@@ -1,32 +0,0 @@
-//
-// Component: Mixin
-// Description: Defines mixins which are used across all components
-//
-// ========================================================================
-
-
-// SVG
-// ========================================================================
-
-/// Replace `$search` with `$replace` in `$string`
-/// @author Hugo Giraudel
-/// @param {String} $string - Initial string
-/// @param {String} $search - Substring to replace
-/// @param {String} $replace ('') - New value
-/// @return {String} - Updated string
-@function str-replace($string, $search, $replace: '') {
- $index: str-index($string, $search);
-
- @if $index {
- @return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace);
- }
-
- @return $string;
-}
-
-@mixin svg-fill($src, $color-default, $color-new){
-
- $replace-src: str-replace($src, $color-default, $color-new) !default;
- $replace-src: str-replace($replace-src, "#", "%23");
- background-image: url(quote($replace-src));
-}
\ No newline at end of file
diff --git a/_sass/uikit/components/modal.scss b/_sass/uikit/components/modal.scss
deleted file mode 100644
index 863f008a7c..0000000000
--- a/_sass/uikit/components/modal.scss
+++ /dev/null
@@ -1,368 +0,0 @@
-// Name: Modal
-// Description: Component to create modal dialogs
-//
-// Component: `uk-modal`
-//
-// Sub-objects: `uk-modal-page`
-// `uk-modal-dialog`
-// `uk-modal-header`
-// `uk-modal-body`
-// `uk-modal-footer`
-// `uk-modal-title`
-// `uk-modal-close`
-//
-// Adopted: `uk-modal-close-default`
-// `uk-modal-close-outside`
-// `uk-modal-close-full`
-//
-// Modifiers: `uk-modal-container`
-// `uk-modal-full`
-//
-// States: `uk-open`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$modal-z-index: $global-z-index + 10 !default;
-$modal-background: rgba(0,0,0,0.6) !default;
-
-$modal-padding-horizontal: 15px !default;
-$modal-padding-horizontal-s: $global-gutter !default;
-$modal-padding-horizontal-m: $global-medium-gutter !default;
-$modal-padding-vertical: $modal-padding-horizontal !default;
-$modal-padding-vertical-s: 50px !default;
-
-$modal-dialog-width: 600px !default;
-$modal-dialog-background: $global-background !default;
-
-$modal-container-width: 1200px !default;
-
-$modal-body-padding-horizontal: $global-gutter !default;
-$modal-body-padding-vertical: $global-gutter !default;
-
-$modal-header-padding-horizontal: $global-gutter !default;
-$modal-header-padding-vertical: ($modal-header-padding-horizontal / 2) !default;
-$modal-header-background: $global-muted-background !default;
-
-$modal-footer-padding-horizontal: $global-gutter !default;
-$modal-footer-padding-vertical: ($modal-footer-padding-horizontal / 2) !default;
-$modal-footer-background: $global-muted-background !default;
-
-$modal-title-font-size: $global-xlarge-font-size !default;
-$modal-title-line-height: 1.3 !default;
-
-$modal-close-position: $global-small-margin !default;
-$modal-close-padding: 5px !default;
-
-$modal-close-outside-position: 0 !default;
-$modal-close-outside-translate: 100% !default;
-$modal-close-outside-color: lighten($global-inverse-color, 20%) !default;
-$modal-close-outside-hover-color: $global-inverse-color !default;
-
-
-/* ========================================================================
- Component: Modal
- ========================================================================== */
-
-/*
- * 1. Hide by default
- * 2. Set position
- * 3. Allow scrolling for the modal dialog
- * 4. Horizontal padding
- * 5. Mask the background page
- * 6. Fade-in transition
- */
-
-.uk-modal {
- /* 1 */
- display: none;
- /* 2 */
- position: fixed;
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
- z-index: $modal-z-index;
- /* 3 */
- overflow-y: auto;
- -webkit-overflow-scrolling: touch;
- /* 4 */
- padding: $modal-padding-vertical $modal-padding-horizontal;
- /* 5 */
- background: $modal-background;
- /* 6 */
- opacity: 0;
- transition: opacity 0.15s linear;
- @if(mixin-exists(hook-modal)) {@include hook-modal();}
-}
-
-/* Phone landscape and bigger */
-@media (min-width: $breakpoint-small) {
-
- .uk-modal { padding: $modal-padding-vertical-s $modal-padding-horizontal-s; }
-
-}
-
-/* Tablet landscape and bigger */
-@media (min-width: $breakpoint-medium) {
-
- .uk-modal {
- padding-left: $modal-padding-horizontal-m;
- padding-right: $modal-padding-horizontal-m;
- }
-
-}
-
-/*
- * Open
- */
-
-.uk-modal.uk-open { opacity: 1; }
-
-
-/* Page
- ========================================================================== */
-
-/*
- * Prevent scrollbars
- */
-
-.uk-modal-page { overflow: hidden; }
-
-
-/* Dialog
- ========================================================================== */
-
-/*
- * 1. Create position context for spinner and close button
- * 2. Dimensions
- * 3. Fix `max-width: 100%` not working in combination with flex and responsive images in IE11
- * `!important` needed to overwrite `uk-width-auto`. See `#modal-media-image` in tests
- * 4. Style
- * 5. Slide-in transition
- */
-
-.uk-modal-dialog {
- /* 1 */
- position: relative;
- /* 2 */
- box-sizing: border-box;
- margin: 0 auto;
- width: $modal-dialog-width;
- /* 3 */
- max-width: unquote('calc(100% - 0.01px)') !important;
- /* 4 */
- background: $modal-dialog-background;
- /* 5 */
- opacity: 0;
- transform: translateY(-100px);
- transition: 0.3s linear;
- transition-property: opacity, transform;
- @if(mixin-exists(hook-modal-dialog)) {@include hook-modal-dialog();}
-}
-
-/*
- * Open
- */
-
-.uk-open > .uk-modal-dialog {
- opacity: 1;
- transform: translateY(0);
-}
-
-
-/* Size modifier
- ========================================================================== */
-
-/*
- * Container size
- * Take the same size as the Container component
- */
-
-.uk-modal-container .uk-modal-dialog { width: $modal-container-width; }
-
-/*
- * Full size
- * 1. Remove padding and background from modal
- * 2. Reset all default declarations from modal dialog
- */
-
-/* 1 */
-.uk-modal-full {
- padding: 0;
- background: none;
-}
-
-/* 2 */
-.uk-modal-full .uk-modal-dialog {
- margin: 0;
- width: 100%;
- max-width: 100%;
- transform: translateY(0);
- @if(mixin-exists(hook-modal-full)) {@include hook-modal-full();}
-}
-
-
-/* Sections
- ========================================================================== */
-
-.uk-modal-body {
- padding: $modal-body-padding-vertical $modal-body-padding-horizontal;
- @if(mixin-exists(hook-modal-body)) {@include hook-modal-body();}
-}
-
-.uk-modal-header {
- padding: $modal-header-padding-vertical $modal-header-padding-horizontal;
- background: $modal-header-background;
- @if(mixin-exists(hook-modal-header)) {@include hook-modal-header();}
-}
-
-.uk-modal-footer {
- padding: $modal-footer-padding-vertical $modal-footer-padding-horizontal;
- background: $modal-footer-background;
- @if(mixin-exists(hook-modal-footer)) {@include hook-modal-footer();}
-}
-
-/*
- * Micro clearfix
- */
-
-.uk-modal-body::before,
-.uk-modal-body::after,
-.uk-modal-header::before,
-.uk-modal-header::after,
-.uk-modal-footer::before,
-.uk-modal-footer::after {
- content: "";
- display: table;
-}
-
-.uk-modal-body::after,
-.uk-modal-header::after,
-.uk-modal-footer::after { clear: both; }
-
-/*
- * Remove margin from the last-child
- */
-
-.uk-modal-body > :last-child,
-.uk-modal-header > :last-child,
-.uk-modal-footer > :last-child { margin-bottom: 0; }
-
-
-/* Title
- ========================================================================== */
-
-.uk-modal-title {
- font-size: $modal-title-font-size;
- line-height: $modal-title-line-height;
- @if(mixin-exists(hook-modal-title)) {@include hook-modal-title();}
-}
-
-
-/* Close
- * Adopts `uk-close`
- ========================================================================== */
-
-[class*='uk-modal-close-'] {
- position: absolute;
- z-index: $modal-z-index;
- top: $modal-close-position;
- right: $modal-close-position;
- padding: $modal-close-padding;
- @if(mixin-exists(hook-modal-close)) {@include hook-modal-close();}
-}
-
-/*
- * Remove margin from adjacent element
- */
-
-[class*='uk-modal-close-']:first-child + * { margin-top: 0; }
-
-/*
- * Hover
- */
-
-[class*='uk-modal-close-']:hover {
- @if(mixin-exists(hook-modal-close-hover)) {@include hook-modal-close-hover();}
-}
-
-/*
- * Default
- */
-
-.uk-modal-close-default {
- @if(mixin-exists(hook-modal-close-default)) {@include hook-modal-close-default();}
-}
-
-.uk-modal-close-default:hover {
- @if(mixin-exists(hook-modal-close-default-hover)) {@include hook-modal-close-default-hover();}
-}
-
-/*
- * Outside
- * 1. Prevent scrollbar on small devices
- */
-
-.uk-modal-close-outside {
- top: $modal-close-outside-position;
- /* 1 */
- right: (-$modal-close-padding);
- transform: translate(0, -($modal-close-outside-translate));
- color: $modal-close-outside-color;
- @if(mixin-exists(hook-modal-close-outside)) {@include hook-modal-close-outside();}
-}
-
-.uk-modal-close-outside:hover {
- color: $modal-close-outside-hover-color;
- @if(mixin-exists(hook-modal-close-outside-hover)) {@include hook-modal-close-outside-hover();}
-}
-
-/* Tablet landscape and bigger */
-@media (min-width: $breakpoint-medium) {
-
- /* 1 */
- .uk-modal-close-outside {
- right: $modal-close-outside-position;
- transform: translate($modal-close-outside-translate, -($modal-close-outside-translate));
- }
-
-}
-
-/*
- * Full
- */
-
-.uk-modal-close-full {
- @if(mixin-exists(hook-modal-close-full)) {@include hook-modal-close-full();}
-}
-
-.uk-modal-close-full:hover {
- @if(mixin-exists(hook-modal-close-full-hover)) {@include hook-modal-close-full-hover();}
-}
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-modal-misc)) {@include hook-modal-misc();}
-
-// @mixin hook-modal(){}
-// @mixin hook-modal-dialog(){}
-// @mixin hook-modal-full(){}
-// @mixin hook-modal-header(){}
-// @mixin hook-modal-body(){}
-// @mixin hook-modal-footer(){}
-// @mixin hook-modal-title(){}
-// @mixin hook-modal-close(){}
-// @mixin hook-modal-close-hover(){}
-// @mixin hook-modal-close-default(){}
-// @mixin hook-modal-close-default-hover(){}
-// @mixin hook-modal-close-outside(){}
-// @mixin hook-modal-close-outside-hover(){}
-// @mixin hook-modal-close-full(){}
-// @mixin hook-modal-close-full-hover(){}
-// @mixin hook-modal-misc(){}
diff --git a/_sass/uikit/components/nav.scss b/_sass/uikit/components/nav.scss
deleted file mode 100644
index 9d990ca248..0000000000
--- a/_sass/uikit/components/nav.scss
+++ /dev/null
@@ -1,357 +0,0 @@
-// Name: Nav
-// Description: Defines styles for list navigations
-//
-// Component: `uk-nav`
-//
-// Sub-objects: `uk-nav-header`
-// `uk-nav-divider`
-// `uk-nav-sub`
-//
-// Modifiers: `uk-nav-parent-icon`
-// `uk-nav-default`
-// `uk-nav-primary`
-// `uk-nav-center`
-//
-// States: `uk-active`
-// `uk-parent`
-// `uk-open`
-// `uk-touch`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$nav-item-padding-vertical: 5px !default;
-$nav-item-padding-horizontal: 0 !default;
-
-$nav-sublist-padding-vertical: 5px !default;
-$nav-sublist-padding-left: 15px !default;
-$nav-sublist-deeper-padding-left: 15px !default;
-$nav-sublist-item-padding-vertical: 2px !default;
-
-$nav-parent-icon-width: ($global-line-height * 1em) !default;
-$nav-parent-icon-height: $nav-parent-icon-width !default;
-$nav-parent-icon-color: $global-color !default;
-
-$nav-header-padding-vertical: $nav-item-padding-vertical !default;
-$nav-header-padding-horizontal: $nav-item-padding-horizontal !default;
-$nav-header-font-size: $global-small-font-size !default;
-$nav-header-text-transform: uppercase !default;
-$nav-header-margin-top: $global-margin !default;
-
-$nav-divider-margin-vertical: 5px !default;
-$nav-divider-margin-horizontal: 0 !default;
-
-$nav-default-item-color: $global-muted-color !default;
-$nav-default-item-hover-color: $global-color !default;
-$nav-default-item-active-color: $global-emphasis-color !default;
-$nav-default-header-color: $global-emphasis-color !default;
-$nav-default-divider-border-width: $global-border-width !default;
-$nav-default-divider-border: $global-border !default;
-$nav-default-sublist-item-color: $global-muted-color !default;
-$nav-default-sublist-item-hover-color: $global-color !default;
-
-$nav-primary-item-font-size: $global-large-font-size !default;
-$nav-primary-item-line-height: $global-line-height !default;
-$nav-primary-item-color: $global-muted-color !default;
-$nav-primary-item-hover-color: $global-color !default;
-$nav-primary-item-active-color: $global-emphasis-color !default;
-$nav-primary-header-color: $global-emphasis-color !default;
-$nav-primary-divider-border-width: $global-border-width !default;
-$nav-primary-divider-border: $global-border !default;
-$nav-primary-sublist-item-color: $global-muted-color !default;
-$nav-primary-sublist-item-hover-color: $global-color !default;
-
-$internal-nav-parent-close-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2214%22%20height%3D%2214%22%20viewBox%3D%220%200%2014%2014%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolyline%20fill%3D%22none%22%20stroke%3D%22#000%22%20stroke-width%3D%221.1%22%20points%3D%2210%201%204%207%2010%2013%22%20%2F%3E%0A%3C%2Fsvg%3E" !default;
-$internal-nav-parent-open-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2214%22%20height%3D%2214%22%20viewBox%3D%220%200%2014%2014%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolyline%20fill%3D%22none%22%20stroke%3D%22#000%22%20stroke-width%3D%221.1%22%20points%3D%221%204%207%2010%2013%204%22%20%2F%3E%0A%3C%2Fsvg%3E" !default;
-
-
-/* ========================================================================
- Component: Nav
- ========================================================================== */
-
-/*
- * Reset
- * 1. Prepare lists
- * 2. Prepare links
- * 3. Remove default focus style
- */
-
-/* 1 */
-.uk-nav,
-.uk-nav ul {
- margin: 0;
- padding: 0;
- list-style: none;
-}
-
-/* 2 */
-.uk-nav li > a {
- display: block;
- text-decoration: none;
-}
-
-/* 3 */
-.uk-nav li > a:focus { outline: none; }
-
-/*
- * Items
- * Must target `a` elements to exclude other elements (e.g. lists)
- */
-
-.uk-nav > li > a { padding: $nav-item-padding-vertical $nav-item-padding-horizontal; }
-
-
-/* Sublists
- ========================================================================== */
-
-/*
- * Level 2
- * `ul` needed for higher specificity to override padding
- */
-
-ul.uk-nav-sub {
- padding: $nav-sublist-padding-vertical 0 $nav-sublist-padding-vertical $nav-sublist-padding-left;
- @if(mixin-exists(hook-nav-sub)) {@include hook-nav-sub();}
-}
-
-/*
- * Level 3 and deeper
- */
-
-.uk-nav-sub ul { padding-left: $nav-sublist-deeper-padding-left; }
-
-/*
- * Items
- */
-
-.uk-nav-sub a { padding: $nav-sublist-item-padding-vertical 0; }
-
-
-/* Parent icon modifier
- ========================================================================== */
-
-.uk-nav-parent-icon > .uk-parent > a::after {
- content: "";
- width: $nav-parent-icon-width;
- height: $nav-parent-icon-height;
- float: right;
- @include svg-fill($internal-nav-parent-close-image, "#000", $nav-parent-icon-color);
- background-repeat: no-repeat;
- background-position: 50% 50%;
- @if(mixin-exists(hook-nav-parent-icon)) {@include hook-nav-parent-icon();}
-}
-
-.uk-nav-parent-icon > .uk-parent.uk-open > a::after { @include svg-fill($internal-nav-parent-open-image, "#000", $nav-parent-icon-color); }
-
-
-/* Header
- ========================================================================== */
-
-.uk-nav-header {
- padding: $nav-header-padding-vertical $nav-header-padding-horizontal;
- text-transform: $nav-header-text-transform;
- font-size: $nav-header-font-size;
- @if(mixin-exists(hook-nav-header)) {@include hook-nav-header();}
-}
-
-.uk-nav-header:not(:first-child) { margin-top: $nav-header-margin-top; }
-
-
-/* Divider
- ========================================================================== */
-
-.uk-nav-divider {
- margin: $nav-divider-margin-vertical $nav-divider-margin-horizontal;
- @if(mixin-exists(hook-nav-divider)) {@include hook-nav-divider();}
-}
-
-
-/* Default modifier
- ========================================================================== */
-
-.uk-nav-default {
- @if(mixin-exists(hook-nav-default)) {@include hook-nav-default();}
-}
-
-/*
- * Items
- */
-
-.uk-nav-default > li > a {
- color: $nav-default-item-color;
- @if(mixin-exists(hook-nav-default-item)) {@include hook-nav-default-item();}
-}
-
-/* Hover + Focus */
-.uk-nav-default > li > a:hover,
-.uk-nav-default > li > a:focus {
- color: $nav-default-item-hover-color;
- @if(mixin-exists(hook-nav-default-item-hover)) {@include hook-nav-default-item-hover();}
-}
-
-/* Active */
-.uk-nav-default > li.uk-active > a {
- color: $nav-default-item-active-color;
- @if(mixin-exists(hook-nav-default-item-active)) {@include hook-nav-default-item-active();}
-}
-
-/*
- * Header
- */
-
-.uk-nav-default .uk-nav-header {
- color: $nav-default-header-color;
- @if(mixin-exists(hook-nav-default-header)) {@include hook-nav-default-header();}
-}
-
-/*
- * Divider
- */
-
-.uk-nav-default .uk-nav-divider {
- border-top: $nav-default-divider-border-width solid $nav-default-divider-border;
- @if(mixin-exists(hook-nav-default-divider)) {@include hook-nav-default-divider();}
-}
-
-/*
- * Sublists
- */
-
-.uk-nav-default .uk-nav-sub a { color: $nav-default-sublist-item-color; }
-
-.uk-nav-default .uk-nav-sub a:hover,
-.uk-nav-default .uk-nav-sub a:focus { color: $nav-default-sublist-item-hover-color; }
-
-
-/* Primary modifier
- ========================================================================== */
-
-.uk-nav-primary {
- @if(mixin-exists(hook-nav-primary)) {@include hook-nav-primary();}
-}
-
-/*
- * Items
- */
-
-.uk-nav-primary > li > a {
- font-size: $nav-primary-item-font-size;
- line-height: $nav-primary-item-line-height;
- color: $nav-primary-item-color;
- @if(mixin-exists(hook-nav-primary-item)) {@include hook-nav-primary-item();}
-}
-
-/* Hover + Focus */
-.uk-nav-primary > li > a:hover,
-.uk-nav-primary > li > a:focus {
- color: $nav-primary-item-hover-color;
- @if(mixin-exists(hook-nav-primary-item-hover)) {@include hook-nav-primary-item-hover();}
-}
-
-/* Active */
-.uk-nav-primary > li.uk-active > a {
- color: $nav-primary-item-active-color;
- @if(mixin-exists(hook-nav-primary-item-active)) {@include hook-nav-primary-item-active();}
-}
-
-/*
- * Header
- */
-
-.uk-nav-primary .uk-nav-header {
- color: $nav-primary-header-color;
- @if(mixin-exists(hook-nav-primary-header)) {@include hook-nav-primary-header();}
-}
-
-/*
- * Divider
- */
-
-.uk-nav-primary .uk-nav-divider {
- border-top: $nav-primary-divider-border-width solid $nav-primary-divider-border;
- @if(mixin-exists(hook-nav-primary-divider)) {@include hook-nav-primary-divider();}
-}
-
-/*
- * Sublists
- */
-
-.uk-nav-primary .uk-nav-sub a { color: $nav-primary-sublist-item-color; }
-
-.uk-nav-primary .uk-nav-sub a:hover,
-.uk-nav-primary .uk-nav-sub a:focus { color: $nav-primary-sublist-item-hover-color; }
-
-
-/* Alignment modifier
- ========================================================================== */
-
-.uk-nav-center { text-align: center; }
-
-/* Sublists */
-.uk-nav-center .uk-nav-sub,
-.uk-nav-center .uk-nav-sub ul { padding-left: 0; }
-
-/* Parent icon modifier */
-.uk-nav-center.uk-nav-parent-icon > .uk-parent > a::after { position: absolute; }
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-nav-misc)) {@include hook-nav-misc();}
-
-// @mixin hook-nav-sub(){}
-// @mixin hook-nav-parent-icon(){}
-// @mixin hook-nav-header(){}
-// @mixin hook-nav-divider(){}
-// @mixin hook-nav-default(){}
-// @mixin hook-nav-default-item(){}
-// @mixin hook-nav-default-item-hover(){}
-// @mixin hook-nav-default-item-active(){}
-// @mixin hook-nav-default-header(){}
-// @mixin hook-nav-default-divider(){}
-// @mixin hook-nav-primary(){}
-// @mixin hook-nav-primary-item(){}
-// @mixin hook-nav-primary-item-hover(){}
-// @mixin hook-nav-primary-item-active(){}
-// @mixin hook-nav-primary-header(){}
-// @mixin hook-nav-primary-divider(){}
-// @mixin hook-nav-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-$inverse-nav-parent-icon-color: $inverse-global-color !default;
-$inverse-nav-default-item-color: $inverse-global-muted-color !default;
-$inverse-nav-default-item-hover-color: $inverse-global-color !default;
-$inverse-nav-default-item-active-color: $inverse-global-emphasis-color !default;
-$inverse-nav-default-header-color: $inverse-global-emphasis-color !default;
-$inverse-nav-default-divider-border: $inverse-global-border !default;
-$inverse-nav-default-sublist-item-color: $inverse-global-muted-color !default;
-$inverse-nav-default-sublist-item-hover-color: $inverse-global-color !default;
-
-$inverse-nav-primary-item-color: $inverse-global-muted-color !default;
-$inverse-nav-primary-item-hover-color: $inverse-global-color !default;
-$inverse-nav-primary-item-active-color: $inverse-global-emphasis-color !default;
-$inverse-nav-primary-header-color: $inverse-global-emphasis-color !default;
-$inverse-nav-primary-divider-border: $inverse-global-border !default;
-$inverse-nav-primary-sublist-item-color: $inverse-global-muted-color !default;
-$inverse-nav-primary-sublist-item-hover-color: $inverse-global-color !default;
-
-
-
-// @mixin hook-inverse-nav-parent-icon(){}
-// @mixin hook-inverse-nav-default-item(){}
-// @mixin hook-inverse-nav-default-item-hover(){}
-// @mixin hook-inverse-nav-default-item-active(){}
-// @mixin hook-inverse-nav-default-header(){}
-// @mixin hook-inverse-nav-default-divider(){}
-// @mixin hook-inverse-nav-primary-item(){}
-// @mixin hook-inverse-nav-primary-item-hover(){}
-// @mixin hook-inverse-nav-primary-item-active(){}
-// @mixin hook-inverse-nav-primary-header(){}
-// @mixin hook-inverse-nav-primary-divider(){}
diff --git a/_sass/uikit/components/navbar.scss b/_sass/uikit/components/navbar.scss
deleted file mode 100644
index a1f633a3de..0000000000
--- a/_sass/uikit/components/navbar.scss
+++ /dev/null
@@ -1,537 +0,0 @@
-// Name: Navbar
-// Description: Component to create horizontal navigation bars
-//
-// Component: `uk-navbar`
-//
-// Sub-objects: `uk-navbar-container`
-// `uk-navbar-left`
-// `uk-navbar-right`
-// `uk-navbar-center`
-// `uk-navbar-center-left`
-// `uk-navbar-center-right`
-// `uk-navbar-nav`
-// `uk-navbar-item`
-// `uk-navbar-toggle`
-// `uk-navbar-subtitle`
-// `uk-navbar-dropbar`
-//
-// Adopted: `uk-navbar-dropdown` + Modifiers
-// `uk-navbar-dropdown-nav`
-// `uk-navbar-dropdown-grid`
-// `uk-navbar-toggle-icon`
-//
-// Modifiers: `uk-navbar-transparent`
-// `uk-navbar-sticky`
-// `uk-navbar-dropdown-stack`
-//
-// States: `uk-active`
-// `uk-parent`
-// `uk-open`
-//
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$navbar-background: $global-muted-background !default;
-$navbar-color-mode: none !default;
-
-$navbar-nav-item-height: 80px !default;
-$navbar-nav-item-padding-horizontal: 15px !default;
-$navbar-nav-item-color: $global-muted-color !default;
-$navbar-nav-item-font-size: $global-font-size !default;
-$navbar-nav-item-font-family: $global-font-family !default;
-$navbar-nav-item-hover-color: $global-color !default;
-$navbar-nav-item-onclick-color: $global-emphasis-color !default;
-$navbar-nav-item-active-color: $global-emphasis-color !default;
-
-$navbar-item-color: $global-color !default;
-
-$navbar-toggle-color: $global-muted-color !default;
-$navbar-toggle-hover-color: $global-color !default;
-
-$navbar-subtitle-font-size: $global-small-font-size !default;
-
-$navbar-dropdown-z-index: $global-z-index + 20 !default;
-$navbar-dropdown-width: 200px !default;
-$navbar-dropdown-margin: 0 !default;
-$navbar-dropdown-padding: 15px !default;
-$navbar-dropdown-background: $global-muted-background !default;
-$navbar-dropdown-color: $global-color !default;
-$navbar-dropdown-grid-gutter-horizontal: $global-gutter !default;
-$navbar-dropdown-grid-gutter-vertical: $navbar-dropdown-grid-gutter-horizontal !default;
-
-$navbar-dropdown-dropbar-margin-top: 0 !default;
-$navbar-dropdown-dropbar-margin-bottom: $navbar-dropdown-dropbar-margin-top !default;
-
-$navbar-dropdown-nav-item-color: $global-muted-color !default;
-$navbar-dropdown-nav-item-hover-color: $global-color !default;
-$navbar-dropdown-nav-item-active-color: $global-emphasis-color !default;
-$navbar-dropdown-nav-header-color: $global-emphasis-color !default;
-$navbar-dropdown-nav-divider-border-width: $global-border-width !default;
-$navbar-dropdown-nav-divider-border: $global-border !default;
-$navbar-dropdown-nav-sublist-item-color: $global-muted-color !default;
-$navbar-dropdown-nav-sublist-item-hover-color: $global-color !default;
-
-$navbar-dropbar-background: $navbar-dropdown-background !default;
-$navbar-dropbar-z-index: $global-z-index - 20 !default;
-
-
-/* ========================================================================
- Component: Navbar
- ========================================================================== */
-
-/*
- * 1. Create position context to center navbar group
- */
-
-.uk-navbar {
- display: flex;
- /* 1 */
- position: relative;
- @if(mixin-exists(hook-navbar)) {@include hook-navbar();}
-}
-
-
-/* Container
- ========================================================================== */
-
-.uk-navbar-container:not(.uk-navbar-transparent) {
- background: $navbar-background;
- @if(mixin-exists(hook-navbar-container)) {@include hook-navbar-container();}
-}
-
-// Color Mode
-@if ( $navbar-color-mode == light ) { .uk-navbar-container:not(.uk-navbar-transparent) { @extend .uk-light !optional;} }
-@if ( $navbar-color-mode == dark ) { .uk-navbar-container:not(.uk-navbar-transparent) { @extend .uk-dark !optional;} }
-
-/*
- * Remove pseudo elements created by micro clearfix as precaution (if Container component is used)
- */
-
-.uk-navbar-container > ::before,
-.uk-navbar-container > ::after { display: none !important; }
-
-
-/* Groups
- ========================================================================== */
-
-/*
- * 1. Align navs and items vertically if they have a different height
- * 2. Note: IE 11 requires an extra `div` which affects the center selector
- */
-
-.uk-navbar-left,
-.uk-navbar-right,
-// 2. [class*='uk-navbar-center'],
-.uk-navbar-center,
-.uk-navbar-center-left > *,
-.uk-navbar-center-right > * {
- display: flex;
- /* 1 */
- align-items: center;
-}
-
-/*
- * Horizontal alignment
- * 1. Create position context for centered navbar with sub groups (left/right)
- * 2. Needed for dropdowns because a new position context is created
- * `z-index` must be smaller than off-canvas
- * 3. Fix text wrapping if the centered section is larger than 50% of the navbar
- * 4. Align sub groups for centered navbar
- */
-
-.uk-navbar-right { margin-left: auto; }
-
-.uk-navbar-center:only-child {
- margin-left: auto;
- margin-right: auto;
- /* 1 */
- position: relative;
-}
-
-.uk-navbar-center:not(:only-child) {
- position: absolute;
- top: 50%;
- left: 50%;
- transform: translate(-50%,-50%);
- /* 2 */
- z-index: $global-z-index - 10;
-}
-
-/* 3 */
-.uk-navbar-center:not(:only-child) .uk-navbar-nav > li > a,
-.uk-navbar-center:not(:only-child) .uk-navbar-item,
-.uk-navbar-center:not(:only-child) .uk-navbar-toggle { white-space: nowrap; }
-
-/* 4 */
-.uk-navbar-center-left,
-.uk-navbar-center-right {
- position: absolute;
- top: 0;
-}
-
-.uk-navbar-center-left { right: 100%; }
-.uk-navbar-center-right { left: 100%; }
-
-[class*='uk-navbar-center-'] .uk-navbar-nav > li > a,
-[class*='uk-navbar-center-'] .uk-navbar-item,
-[class*='uk-navbar-center-'] .uk-navbar-toggle { white-space: nowrap; }
-
-
-/* Nav
- ========================================================================== */
-
-/*
- * 1. Reset list
- */
-
-.uk-navbar-nav {
- display: flex;
- /* 1 */
- margin: 0;
- padding: 0;
- list-style: none;
-}
-
-/*
- * Allow items to wrap into the next line
- * Only not `absolute` positioned groups
- */
-
-.uk-navbar-left,
-.uk-navbar-right,
-.uk-navbar-center:only-child { flex-wrap: wrap; }
-
-/*
- * Items
- * 1. Center content vertically and horizontally
- * 2. Dimensions
- * 3. Style
- * 4. Required for `a`
- */
-
-.uk-navbar-nav > li > a, // Nav item
-.uk-navbar-item, // Content item
-.uk-navbar-toggle { // Clickable item
- /* 1 */
- display: flex;
- justify-content: center;
- align-items: center;
- /* 2 */
- box-sizing: border-box;
- height: $navbar-nav-item-height;
- padding: 0 $navbar-nav-item-padding-horizontal;
- /* 3 */
- font-size: $navbar-nav-item-font-size;
- font-family: $navbar-nav-item-font-family;
- /* 4 */
- text-decoration: none;
-}
-
-/*
- * Nav items
- */
-
-.uk-navbar-nav > li > a {
- color: $navbar-nav-item-color;
- @if(mixin-exists(hook-navbar-nav-item)) {@include hook-navbar-nav-item();}
-}
-
-/*
- * Hover
- * Apply hover style also to focus state and if dropdown is opened
- */
-
-.uk-navbar-nav > li:hover > a,
-.uk-navbar-nav > li > a:focus,
-.uk-navbar-nav > li > a.uk-open {
- color: $navbar-nav-item-hover-color;
- outline: none;
- @if(mixin-exists(hook-navbar-nav-item-hover)) {@include hook-navbar-nav-item-hover();}
-}
-
-/* OnClick */
-.uk-navbar-nav > li > a:active {
- color: $navbar-nav-item-onclick-color;
- @if(mixin-exists(hook-navbar-nav-item-onclick)) {@include hook-navbar-nav-item-onclick();}
-}
-
-/* Active */
-.uk-navbar-nav > li.uk-active > a {
- color: $navbar-nav-item-active-color;
- @if(mixin-exists(hook-navbar-nav-item-active)) {@include hook-navbar-nav-item-active();}
-}
-
-
-/* Item
- ========================================================================== */
-
-.uk-navbar-item {
- color: $navbar-item-color;
- @if(mixin-exists(hook-navbar-item)) {@include hook-navbar-item();}
-}
-
-
-/* Toggle
- ========================================================================== */
-
-.uk-navbar-toggle {
- color: $navbar-toggle-color;
- @if(mixin-exists(hook-navbar-toggle)) {@include hook-navbar-toggle();}
-}
-
-.uk-navbar-toggle:hover,
-.uk-navbar-toggle:focus,
-.uk-navbar-toggle.uk-open {
- color: $navbar-toggle-hover-color;
- outline: none;
- text-decoration: none;
- @if(mixin-exists(hook-navbar-toggle-hover)) {@include hook-navbar-toggle-hover();}
-}
-
-/*
- * Icon
- * Adopts `uk-icon`
- */
-
-.uk-navbar-toggle-icon {
- @if(mixin-exists(hook-navbar-toggle-icon)) {@include hook-navbar-toggle-icon();}
-}
-
-/* Hover + Focus */
-:hover > .uk-navbar-toggle-icon,
-:focus > .uk-navbar-toggle-icon {
- @if(mixin-exists(hook-navbar-toggle-icon-hover)) {@include hook-navbar-toggle-icon-hover();}
-}
-
-
-/* Subtitle
- ========================================================================== */
-
-.uk-navbar-subtitle {
- font-size: $navbar-subtitle-font-size;
- @if(mixin-exists(hook-navbar-subtitle)) {@include hook-navbar-subtitle();}
-}
-
-
-/* Style modifiers
- ========================================================================== */
-
-.uk-navbar-transparent {
- @if(mixin-exists(hook-navbar-transparent)) {@include hook-navbar-transparent();}
-}
-
-.uk-navbar-sticky {
- @if(mixin-exists(hook-navbar-sticky)) {@include hook-navbar-sticky();}
-}
-
-
-/* Dropdown
- ========================================================================== */
-
-/*
- * Adopts `uk-dropdown`
- * 1. Hide by default
- * 2. Set position
- * 3. Set a default width
- * 4. Style
- */
-
-.uk-navbar-dropdown {
- /* 1 */
- display: none;
- /* 2 */
- position: absolute;
- z-index: $navbar-dropdown-z-index;
- /* 3 */
- box-sizing: border-box;
- width: $navbar-dropdown-width;
- /* 4 */
- padding: $navbar-dropdown-padding;
- background: $navbar-dropdown-background;
- color: $navbar-dropdown-color;
- @if(mixin-exists(hook-navbar-dropdown)) {@include hook-navbar-dropdown();}
-}
-
-/* Show */
-.uk-navbar-dropdown.uk-open { display: block; }
-
-/*
- * Direction / Alignment modifiers
- */
-
-/* Direction */
-[class*='uk-navbar-dropdown-top'] { margin-top: (-$navbar-dropdown-margin); }
-[class*='uk-navbar-dropdown-bottom'] { margin-top: $navbar-dropdown-margin; }
-[class*='uk-navbar-dropdown-left'] { margin-left: (-$navbar-dropdown-margin); }
-[class*='uk-navbar-dropdown-right'] { margin-left: $navbar-dropdown-margin; }
-
-/*
- * Grid
- * Adopts `uk-grid`
- */
-
-/* Gutter Horizontal */
-.uk-navbar-dropdown-grid { margin-left: (-$navbar-dropdown-grid-gutter-horizontal); }
-.uk-navbar-dropdown-grid > * { padding-left: $navbar-dropdown-grid-gutter-horizontal; }
-
-/* Gutter Vertical */
-.uk-navbar-dropdown-grid > .uk-grid-margin { margin-top: $navbar-dropdown-grid-gutter-vertical; }
-
-/* Stack */
-.uk-navbar-dropdown-stack .uk-navbar-dropdown-grid > * { width: 100% !important; }
-
-/*
- * Width modifier
- */
-
-.uk-navbar-dropdown-width-2:not(.uk-navbar-dropdown-stack) { width: ($navbar-dropdown-width * 2); }
-.uk-navbar-dropdown-width-3:not(.uk-navbar-dropdown-stack) { width: ($navbar-dropdown-width * 3); }
-.uk-navbar-dropdown-width-4:not(.uk-navbar-dropdown-stack) { width: ($navbar-dropdown-width * 4); }
-.uk-navbar-dropdown-width-5:not(.uk-navbar-dropdown-stack) { width: ($navbar-dropdown-width * 5); }
-
-/*
- * Dropbar modifier
- */
-
-.uk-navbar-dropdown-dropbar {
- margin-top: $navbar-dropdown-dropbar-margin-top;
- margin-bottom: $navbar-dropdown-dropbar-margin-bottom;
- @if(mixin-exists(hook-navbar-dropdown-dropbar)) {@include hook-navbar-dropdown-dropbar();}
-}
-
-
-/* Dropdown Nav
- * Adopts `uk-nav`
- ========================================================================== */
-
-.uk-navbar-dropdown-nav {
- @if(mixin-exists(hook-navbar-dropdown-nav)) {@include hook-navbar-dropdown-nav();}
-}
-
-/*
- * Items
- */
-
-.uk-navbar-dropdown-nav > li > a {
- color: $navbar-dropdown-nav-item-color;
- @if(mixin-exists(hook-navbar-dropdown-nav-item)) {@include hook-navbar-dropdown-nav-item();}
-}
-
-/* Hover + Focus */
-.uk-navbar-dropdown-nav > li > a:hover,
-.uk-navbar-dropdown-nav > li > a:focus {
- color: $navbar-dropdown-nav-item-hover-color;
- @if(mixin-exists(hook-navbar-dropdown-nav-item-hover)) {@include hook-navbar-dropdown-nav-item-hover();}
-}
-
-/* Active */
-.uk-navbar-dropdown-nav > li.uk-active > a {
- color: $navbar-dropdown-nav-item-active-color;
- @if(mixin-exists(hook-navbar-dropdown-nav-item-active)) {@include hook-navbar-dropdown-nav-item-active();}
-}
-
-/*
- * Header
- */
-
-.uk-navbar-dropdown-nav .uk-nav-header {
- color: $navbar-dropdown-nav-header-color;
- @if(mixin-exists(hook-navbar-dropdown-nav-header)) {@include hook-navbar-dropdown-nav-header();}
-}
-
-/*
- * Divider
- */
-
-.uk-navbar-dropdown-nav .uk-nav-divider {
- border-top: $navbar-dropdown-nav-divider-border-width solid $navbar-dropdown-nav-divider-border;
- @if(mixin-exists(hook-navbar-dropdown-nav-divider)) {@include hook-navbar-dropdown-nav-divider();}
-}
-
-/*
- * Sublists
- */
-
-.uk-navbar-dropdown-nav .uk-nav-sub a { color: $navbar-dropdown-nav-sublist-item-color; }
-
-.uk-navbar-dropdown-nav .uk-nav-sub a:hover,
-.uk-navbar-dropdown-nav .uk-nav-sub a:focus { color: $navbar-dropdown-nav-sublist-item-hover-color; }
-
-
-/* Dropbar
- ========================================================================== */
-
-.uk-navbar-dropbar {
- background: $navbar-dropbar-background;
- @if(mixin-exists(hook-navbar-dropbar)) {@include hook-navbar-dropbar();}
-}
-
-/*
- * Slide modifier
- */
-
-.uk-navbar-dropbar-slide {
- position: absolute;
- z-index: $navbar-dropbar-z-index;
- left: 0;
- right: 0;
- @if(mixin-exists(hook-navbar-dropbar-slide)) {@include hook-navbar-dropbar-slide();}
-}
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-navbar-misc)) {@include hook-navbar-misc();}
-
-// @mixin hook-navbar(){}
-// @mixin hook-navbar-container(){}
-// @mixin hook-navbar-nav-item(){}
-// @mixin hook-navbar-nav-item-hover(){}
-// @mixin hook-navbar-nav-item-onclick(){}
-// @mixin hook-navbar-nav-item-active(){}
-// @mixin hook-navbar-item(){}
-// @mixin hook-navbar-toggle(){}
-// @mixin hook-navbar-toggle-hover(){}
-// @mixin hook-navbar-toggle-icon(){}
-// @mixin hook-navbar-toggle-icon-hover(){}
-// @mixin hook-navbar-subtitle(){}
-// @mixin hook-navbar-transparent(){}
-// @mixin hook-navbar-sticky(){}
-// @mixin hook-navbar-dropdown(){}
-// @mixin hook-navbar-dropdown-dropbar(){}
-// @mixin hook-navbar-dropdown-nav(){}
-// @mixin hook-navbar-dropdown-nav-item(){}
-// @mixin hook-navbar-dropdown-nav-item-hover(){}
-// @mixin hook-navbar-dropdown-nav-item-active(){}
-// @mixin hook-navbar-dropdown-nav-header(){}
-// @mixin hook-navbar-dropdown-nav-divider(){}
-// @mixin hook-navbar-dropbar(){}
-// @mixin hook-navbar-dropbar-slide(){}
-// @mixin hook-navbar-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-$inverse-navbar-nav-item-color: $inverse-global-muted-color !default;
-$inverse-navbar-nav-item-hover-color: $inverse-global-color !default;
-$inverse-navbar-nav-item-onclick-color: $inverse-global-emphasis-color !default;
-$inverse-navbar-nav-item-active-color: $inverse-global-emphasis-color !default;
-$inverse-navbar-item-color: $inverse-global-color !default;
-$inverse-navbar-toggle-color: $inverse-global-muted-color !default;
-$inverse-navbar-toggle-hover-color: $inverse-global-color !default;
-
-
-
-// @mixin hook-inverse-navbar-nav-item(){}
-// @mixin hook-inverse-navbar-nav-item-hover(){}
-// @mixin hook-inverse-navbar-nav-item-onclick(){}
-// @mixin hook-inverse-navbar-nav-item-active(){}
-// @mixin hook-inverse-navbar-item(){}
-// @mixin hook-inverse-navbar-toggle(){}
-// @mixin hook-inverse-navbar-toggle-hover(){}
diff --git a/_sass/uikit/components/notification.scss b/_sass/uikit/components/notification.scss
deleted file mode 100644
index cc1ba55214..0000000000
--- a/_sass/uikit/components/notification.scss
+++ /dev/null
@@ -1,190 +0,0 @@
-// Name: Notification
-// Description: Component to create notification messages
-//
-// Component: `uk-notification`
-//
-// Sub-objects: `uk-notification-message`
-//
-// Adopted: `uk-notification-close`
-//
-// Modifiers: `uk-notification-top-center`
-// `uk-notification-top-right`
-// `uk-notification-bottom-left`
-// `uk-notification-bottom-center`
-// `uk-notification-bottom-right`
-// `uk-notification-message-primary`
-// `uk-notification-message-success`
-// `uk-notification-message-warning`
-// `uk-notification-message-danger`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$notification-position: 10px !default;
-$notification-z-index: $global-z-index + 40 !default;
-$notification-width: 350px !default;
-
-$notification-message-margin-bottom: 10px !default;
-$notification-message-padding: $global-small-gutter !default;
-$notification-message-background: $global-muted-background !default;
-$notification-message-color: $global-color !default;
-$notification-message-font-size: $global-medium-font-size !default;
-$notification-message-line-height: 1.4 !default;
-
-$notification-close-top: $notification-message-padding + 5px !default;
-$notification-close-right: $notification-message-padding !default;
-
-$notification-message-primary-color: $global-primary-background !default;
-$notification-message-success-color: $global-success-background !default;
-$notification-message-warning-color: $global-warning-background !default;
-$notification-message-danger-color: $global-danger-background !default;
-
-
-/* ========================================================================
- Component: Notification
- ========================================================================== */
-
-/*
- * 1. Set position
- * 2. Dimensions
- */
-
-.uk-notification {
- /* 1 */
- position: fixed;
- top: $notification-position;
- left: $notification-position;
- z-index: $notification-z-index;
- /* 2 */
- box-sizing: border-box;
- width: $notification-width;
- @if(mixin-exists(hook-notification)) {@include hook-notification();}
-}
-
-
-/* Position modifiers
-========================================================================== */
-
-.uk-notification-top-right,
-.uk-notification-bottom-right {
- left: auto;
- right: $notification-position;
-}
-
-.uk-notification-top-center,
-.uk-notification-bottom-center {
- left: 50%;
- margin-left: ($notification-width / -2);
-}
-
-.uk-notification-bottom-left,
-.uk-notification-bottom-right,
-.uk-notification-bottom-center {
- top: auto;
- bottom: $notification-position;
-}
-
-
-/* Responsiveness
-========================================================================== */
-
-/* Phones portrait and smaller */
-@media (max-width: $breakpoint-xsmall-max) {
-
- .uk-notification {
- left: $notification-position;
- right: $notification-position;
- width: auto;
- margin: 0;
- }
-
-}
-
-
-/* Message
-========================================================================== */
-
-.uk-notification-message {
- position: relative;
- margin-bottom: $notification-message-margin-bottom;
- padding: $notification-message-padding;
- background: $notification-message-background;
- color: $notification-message-color;
- font-size: $notification-message-font-size;
- line-height: $notification-message-line-height;
- cursor: pointer;
- @if(mixin-exists(hook-notification-message)) {@include hook-notification-message();}
-}
-
-
-/* Close
- * Adopts `uk-close`
- ========================================================================== */
-
-.uk-notification-close {
- display: none;
- position: absolute;
- top: $notification-close-top;
- right: $notification-close-right;
- @if(mixin-exists(hook-notification-close)) {@include hook-notification-close();}
-}
-
-.uk-notification-message:hover .uk-notification-close { display: block; }
-
-
-/* Style modifiers
- ========================================================================== */
-
-/*
- * Primary
- */
-
-.uk-notification-message-primary {
- color: $notification-message-primary-color;
- @if(mixin-exists(hook-notification-message-primary)) {@include hook-notification-message-primary();}
-}
-
-/*
- * Success
- */
-
-.uk-notification-message-success {
- color: $notification-message-success-color;
- @if(mixin-exists(hook-notification-message-success)) {@include hook-notification-message-success();}
-}
-
-/*
- * Warning
- */
-
-.uk-notification-message-warning {
- color: $notification-message-warning-color;
- @if(mixin-exists(hook-notification-message-warning)) {@include hook-notification-message-warning();}
-}
-
-/*
- * Danger
- */
-
-.uk-notification-message-danger {
- color: $notification-message-danger-color;
- @if(mixin-exists(hook-notification-message-danger)) {@include hook-notification-message-danger();}
-}
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-notification-misc)) {@include hook-notification-misc();}
-
-// @mixin hook-notification(){}
-// @mixin hook-notification-message(){}
-// @mixin hook-notification-close(){}
-// @mixin hook-notification-message-primary(){}
-// @mixin hook-notification-message-success(){}
-// @mixin hook-notification-message-warning(){}
-// @mixin hook-notification-message-danger(){}
-// @mixin hook-notification-misc(){}
diff --git a/_sass/uikit/components/offcanvas.scss b/_sass/uikit/components/offcanvas.scss
deleted file mode 100644
index 5fc055873a..0000000000
--- a/_sass/uikit/components/offcanvas.scss
+++ /dev/null
@@ -1,301 +0,0 @@
-// Name: Off-canvas
-// Description: Component to create an off-canvas sidebar
-//
-// Component: `uk-offcanvas`
-//
-// Sub-objects: `uk-offcanvas-bar`
-// `uk-offcanvas-container`
-// `uk-offcanvas-content`
-// `uk-offcanvas-page`
-//
-// Adopted: `uk-offcanvas-close`
-//
-// Modifiers: `uk-offcanvas-flip`
-// `uk-offcanvas-bar-animation`
-// `uk-offcanvas-reveal`
-// `uk-offcanvas-overlay`
-// `uk-offcanvas-content-animation`
-//
-// States: `uk-open`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$offcanvas-z-index: $global-z-index !default;
-
-$offcanvas-bar-width: 270px !default;
-$offcanvas-bar-padding-vertical: $global-margin !default;
-$offcanvas-bar-padding-horizontal: $global-margin !default;
-$offcanvas-bar-background: $global-secondary-background !default;
-$offcanvas-bar-color-mode: light !default;
-
-$offcanvas-bar-width-m: 350px !default;
-$offcanvas-bar-padding-vertical-m: $global-medium-gutter !default;
-$offcanvas-bar-padding-horizontal-m: $global-medium-gutter !default;
-
-$offcanvas-close-position: 20px !default;
-$offcanvas-close-padding: 5px !default;
-
-$offcanvas-overlay-background: rgba(0,0,0,0.1) !default;
-
-
-/* ========================================================================
- Component: Off-canvas
- ========================================================================== */
-
-/*
- * 1. Hide by default
- * 2. Set position
- */
-
-.uk-offcanvas {
- /* 1 */
- display: none;
- /* 2 */
- position: fixed;
- top: 0;
- bottom: 0;
- left: 0;
- z-index: $offcanvas-z-index;
-}
-
-/*
- * Flip modifier
- */
-
-.uk-offcanvas-flip .uk-offcanvas {
- right: 0;
- left: auto;
-}
-
-
-/* Bar
- ========================================================================== */
-
-/*
- * 1. Set position
- * 2. Size and style
- * 3. Allow scrolling
- * 4. Transform
- */
-
-.uk-offcanvas-bar {
- /* 1 */
- position: absolute;
- top: 0;
- bottom: 0;
- left: 0;
- /* 2 */
- box-sizing: border-box;
- width: $offcanvas-bar-width;
- padding: $offcanvas-bar-padding-vertical $offcanvas-bar-padding-horizontal;
- background: $offcanvas-bar-background;
- /* 3 */
- overflow-y: auto;
- -webkit-overflow-scrolling: touch;
- /* 4 */
- transform: translateX(-100%);
- @if(mixin-exists(hook-offcanvas-bar)) {@include hook-offcanvas-bar();}
-}
-
-/* Tablet landscape and bigger */
-@media (min-width: $breakpoint-medium) {
-
- .uk-offcanvas-bar {
- width: $offcanvas-bar-width-m;
- padding: $offcanvas-bar-padding-vertical-m $offcanvas-bar-padding-horizontal-m;
- }
-
-}
-
-// Color Mode
-@if ( $offcanvas-bar-color-mode == light ) { .uk-offcanvas-bar { @extend .uk-light !optional;} }
-@if ( $offcanvas-bar-color-mode == dark ) { .uk-offcanvas-bar { @extend .uk-dark !optional;} }
-
-/* Flip modifier */
-.uk-offcanvas-flip .uk-offcanvas-bar {
- left: auto;
- right: 0;
- transform: translateX(100%);
-}
-
-/*
- * Open
- */
-
-.uk-open > .uk-offcanvas-bar { transform: translateX(0); }
-
-/*
- * Slide Animation (Used in slide and push mode)
- */
-
-.uk-offcanvas-bar-animation { transition: transform 0.3s ease-out; }
-
-/*
- * Reveal Animation
- * 1. Set position
- * 2. Clip the bar
- * 3. Animation
- * 4. Reset transform
- */
-
-.uk-offcanvas-reveal {
- /* 1 */
- position: absolute;
- top: 0;
- bottom: 0;
- left: 0;
- /* 2 */
- width: 0;
- overflow: hidden;
- /* 3 */
- transition: width 0.3s ease-out;
-}
-
-.uk-offcanvas-reveal .uk-offcanvas-bar {
- /* 4 */
- transform: translateX(0);
-}
-
-.uk-open > .uk-offcanvas-reveal { width: $offcanvas-bar-width; }
-
-/* Tablet landscape and bigger */
-@media (min-width: $breakpoint-medium) {
-
- .uk-open > .uk-offcanvas-reveal { width: $offcanvas-bar-width-m; }
-
-}
-
-/*
- * Flip modifier
- */
-
-.uk-offcanvas-flip .uk-offcanvas-reveal {
- right: 0;
- left: auto;
-}
-
-
-/* Close
- * Adopts `uk-close`
- ========================================================================== */
-
-.uk-offcanvas-close {
- position: absolute;
- z-index: $offcanvas-z-index;
- top: $offcanvas-close-position;
- right: $offcanvas-close-position;
- padding: $offcanvas-close-padding;
- @if(mixin-exists(hook-offcanvas-close)) {@include hook-offcanvas-close();}
-}
-
-
-/* Overlay
- ========================================================================== */
-
-/*
- * Overlay the whole page. Needed for the `::before`
- * 1. Using `100vw` so no modification is needed when off-canvas is flipped
- * 2. Allow for closing with swipe gesture on devices with pointer events.
- */
-
-.uk-offcanvas-overlay {
- /* 1 */
- width: 100vw;
- /* 2 */
- touch-action: none;
-}
-
-/*
- * 1. Mask the whole page
- * 2. Fade-in transition
- */
-
-.uk-offcanvas-overlay::before {
- /* 1 */
- content: "";
- position: absolute;
- top: 0;
- bottom: 0;
- left: 0;
- right: 0;
- background: $offcanvas-overlay-background;
- /* 2 */
- opacity: 0;
- transition: opacity 0.15s linear;
- @if(mixin-exists(hook-offcanvas-overlay)) {@include hook-offcanvas-overlay();}
-}
-
-.uk-offcanvas-overlay.uk-open::before { opacity: 1; }
-
-
-/* Container
- ========================================================================== */
-
-/*
- * Prevent horizontal scrollbar when the content is slide-out
- * Has to be on the `html` element too to make it work on the `body`
- */
-
-.uk-offcanvas-page,
-.uk-offcanvas-container { overflow-x: hidden; }
-
-/*
- * Prevent all scrollbars if overlay is used
- */
-
-.uk-offcanvas-container-overlay { overflow: hidden; }
-
-
-/* Content
- ========================================================================== */
-
-/*
- * Prepare slide-out animation (Used in reveal and push mode)
- * Using `position: left` instead of `transform` because position `fixed` elements like sticky navbars
- * lose their fixed state and behaves like `absolute` within a transformed container
- * Note: JS sets a fixed width and height so the page can slide-out without shrinking
- * 1. Smooth scrolling
- */
-
-.uk-offcanvas-container .uk-offcanvas-content {
- position: relative;
- left: 0;
- transition: left 0.3s ease-out;
- /* 1 */
- -webkit-overflow-scrolling: touch;
-}
-
-/* Disable scrolling if overlay mode */
-.uk-offcanvas-overlay .uk-offcanvas-content { overflow-y: hidden; }
-
-/*
- * Activate slide-out animation
- */
-
-:not(.uk-offcanvas-flip) > .uk-offcanvas-content-animation { left: $offcanvas-bar-width; }
-
-.uk-offcanvas-flip > .uk-offcanvas-content-animation { left: (-$offcanvas-bar-width); }
-
-/* Tablet landscape and bigger */
-@media (min-width: $breakpoint-medium) {
-
- :not(.uk-offcanvas-flip) > .uk-offcanvas-content-animation { left: $offcanvas-bar-width-m; }
-
- .uk-offcanvas-flip > .uk-offcanvas-content-animation { left: (-$offcanvas-bar-width-m); }
-
-}
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-offcanvas-misc)) {@include hook-offcanvas-misc();}
-
-// @mixin hook-offcanvas-bar(){}
-// @mixin hook-offcanvas-close(){}
-// @mixin hook-offcanvas-overlay(){}
-// @mixin hook-offcanvas-misc(){}
diff --git a/_sass/uikit/components/overlay.scss b/_sass/uikit/components/overlay.scss
deleted file mode 100644
index c3eb0a5711..0000000000
--- a/_sass/uikit/components/overlay.scss
+++ /dev/null
@@ -1,85 +0,0 @@
-// Name: Overlay
-// Description: Component to create content areas overlaying an image
-//
-// Component: `uk-overlay`
-//
-// Adopted: `uk-overlay-icon`
-//
-// Modifier: `uk-overlay-default`
-// `uk-overlay-primary`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$overlay-padding-horizontal: $global-gutter !default;
-$overlay-padding-vertical: $global-gutter !default;
-
-$overlay-default-background: rgba($global-background, 0.8) !default;
-
-$overlay-primary-background: rgba($global-secondary-background, 0.8) !default;
-$overlay-primary-color-mode: light !default;
-
-
-/* ========================================================================
- Component: Overlay
- ========================================================================== */
-
-.uk-overlay {
- padding: $overlay-padding-vertical $overlay-padding-horizontal;
- @if(mixin-exists(hook-overlay)) {@include hook-overlay();}
-}
-
-/*
- * Remove margin from the last-child
- */
-
-.uk-overlay > :last-child { margin-bottom: 0; }
-
-
-/* Icon
- ========================================================================== */
-
-.uk-overlay-icon {
- @if(mixin-exists(hook-overlay-icon)) {@include hook-overlay-icon();}
-}
-
-
-/* Style modifiers
- ========================================================================== */
-
-/*
- * Default
- */
-
-.uk-overlay-default {
- background: $overlay-default-background;
- @if(mixin-exists(hook-overlay-default)) {@include hook-overlay-default();}
-}
-
-/*
- * Primary
- */
-
-.uk-overlay-primary {
- background: $overlay-primary-background;
- @if(mixin-exists(hook-overlay-primary)) {@include hook-overlay-primary();}
-}
-
-// Color Mode
-@if ( $overlay-primary-color-mode == light ) { .uk-overlay-primary { @extend .uk-light !optional;} }
-@if ( $overlay-primary-color-mode == dark ) { .uk-overlay-primary { @extend .uk-dark !optional;} }
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-overlay-misc)) {@include hook-overlay-misc();}
-
-// @mixin hook-overlay(){}
-// @mixin hook-overlay-icon(){}
-// @mixin hook-overlay-default(){}
-// @mixin hook-overlay-primary(){}
-// @mixin hook-overlay-misc(){}
diff --git a/_sass/uikit/components/padding.scss b/_sass/uikit/components/padding.scss
deleted file mode 100644
index 0c0f1ed10b..0000000000
--- a/_sass/uikit/components/padding.scss
+++ /dev/null
@@ -1,81 +0,0 @@
-// Name: Padding
-// Description: Utilities for padding
-//
-// Component: `uk-padding`
-// `uk-padding-large`
-// `uk-padding-remove-*`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$padding-padding: $global-gutter !default;
-$padding-padding-l: $global-medium-gutter !default;
-
-$padding-small-padding: $global-small-gutter !default;
-
-$padding-large-padding: $global-gutter !default;
-$padding-large-padding-l: $global-large-gutter !default;
-
-
-/* ========================================================================
- Component: Padding
- ========================================================================== */
-
-.uk-padding { padding: $padding-padding; }
-
-/* Desktop and bigger */
-@media (min-width: $breakpoint-large) {
-
- .uk-padding { padding: $padding-padding-l; }
-
-}
-
-
-/* Small
- ========================================================================== */
-
-.uk-padding-small { padding: $padding-small-padding; }
-
-
-/* Large
- ========================================================================== */
-
-.uk-padding-large { padding: $padding-large-padding; }
-
-/* Desktop and bigger */
-@media (min-width: $breakpoint-large) {
-
- .uk-padding-large { padding: $padding-large-padding-l; }
-
-}
-
-
-/* Remove
- ========================================================================== */
-
-.uk-padding-remove { padding: 0 !important; }
-.uk-padding-remove-top { padding-top: 0 !important; }
-.uk-padding-remove-bottom { padding-bottom: 0 !important; }
-.uk-padding-remove-left { padding-left: 0 !important; }
-.uk-padding-remove-right { padding-right: 0 !important; }
-
-.uk-padding-remove-vertical {
- padding-top: 0 !important;
- padding-bottom: 0 !important;
-}
-
-.uk-padding-remove-horizontal {
- padding-left: 0 !important;
- padding-right: 0 !important;
-}
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-padding-misc)) {@include hook-padding-misc();}
-
-// @mixin hook-padding-misc(){}
diff --git a/_sass/uikit/components/pagination.scss b/_sass/uikit/components/pagination.scss
deleted file mode 100644
index 5dce23ad12..0000000000
--- a/_sass/uikit/components/pagination.scss
+++ /dev/null
@@ -1,128 +0,0 @@
-// Name: Pagination
-// Description: Component to create a page navigation
-//
-// Component: `uk-pagination`
-//
-// Adopted: `uk-pagination-next`
-// `uk-pagination-previous`
-//
-// States: `uk-active`
-// `uk-disabled`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$pagination-margin-horizontal: 20px !default;
-
-$pagination-item-color: $global-muted-color !default;
-$pagination-item-hover-color: $global-color !default;
-$pagination-item-hover-text-decoration: none !default;
-$pagination-item-active-color: $global-color !default;
-$pagination-item-disabled-color: $global-muted-color !default;
-
-
-/* ========================================================================
- Component: Pagination
- ========================================================================== */
-
-/*
- * 1. Allow items to wrap into the next line
- * 2. Gutter
- * 3. Reset list
- */
-
-.uk-pagination {
- display: flex;
- /* 1 */
- flex-wrap: wrap;
- /* 2 */
- margin-left: (-$pagination-margin-horizontal);
- /* 3 */
- padding: 0;
- list-style: none;
- @if(mixin-exists(hook-pagination)) {@include hook-pagination();}
-}
-
-/*
- * 1. Space is allocated solely based on content dimensions: 0 0 auto
- * 2. Gutter
- * 3. Create position context for dropdowns
- */
-
-.uk-pagination > * {
- /* 1 */
- flex: none;
- /* 2 */
- padding-left: $pagination-margin-horizontal;
- /* 3 */
- position: relative;
-}
-
-
-/* Items
- ========================================================================== */
-
-/*
- * 1. Prevent gap if child element is `inline-block`, e.g. an icon
- * 2. Style
- */
-
-.uk-pagination > * > * {
- /* 1 */
- display: block;
- /* 2 */
- color: $pagination-item-color;
- @if(mixin-exists(hook-pagination-item)) {@include hook-pagination-item();}
-}
-
-/* Hover + Focus */
-.uk-pagination > * > :hover,
-.uk-pagination > * > :focus {
- color: $pagination-item-hover-color;
- text-decoration: $pagination-item-hover-text-decoration;
- @if(mixin-exists(hook-pagination-item-hover)) {@include hook-pagination-item-hover();}
-}
-
-/* Active */
-.uk-pagination > .uk-active > * {
- color: $pagination-item-active-color;
- @if(mixin-exists(hook-pagination-item-active)) {@include hook-pagination-item-active();}
-}
-
-/* Disabled */
-.uk-pagination > .uk-disabled > * {
- color: $pagination-item-disabled-color;
- @if(mixin-exists(hook-pagination-item-disabled)) {@include hook-pagination-item-disabled();}
-}
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-pagination-misc)) {@include hook-pagination-misc();}
-
-// @mixin hook-pagination(){}
-// @mixin hook-pagination-item(){}
-// @mixin hook-pagination-item-hover(){}
-// @mixin hook-pagination-item-active(){}
-// @mixin hook-pagination-item-disabled(){}
-// @mixin hook-pagination-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-$inverse-pagination-item-color: $inverse-global-muted-color !default;
-$inverse-pagination-item-hover-color: $inverse-global-color !default;
-$inverse-pagination-item-active-color: $inverse-global-color !default;
-$inverse-pagination-item-disabled-color: $inverse-global-muted-color !default;
-
-
-
-// @mixin hook-inverse-pagination-item(){}
-// @mixin hook-inverse-pagination-item-hover(){}
-// @mixin hook-inverse-pagination-item-active(){}
-// @mixin hook-inverse-pagination-item-disabled(){}
diff --git a/_sass/uikit/components/placeholder.scss b/_sass/uikit/components/placeholder.scss
deleted file mode 100644
index 05c06f7d92..0000000000
--- a/_sass/uikit/components/placeholder.scss
+++ /dev/null
@@ -1,45 +0,0 @@
-// Name: Placeholder
-// Description: Component to create placeholder boxes
-//
-// Component: `uk-placeholder`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$placeholder-margin-vertical: $global-margin !default;
-$placeholder-padding-vertical: $global-gutter !default;
-$placeholder-padding-horizontal: $global-gutter !default;
-$placeholder-background: $global-muted-background !default;
-
-
-/* ========================================================================
- Component: Placeholder
- ========================================================================== */
-
-.uk-placeholder {
- margin-bottom: $placeholder-margin-vertical;
- padding: $placeholder-padding-vertical $placeholder-padding-horizontal;
- background: $placeholder-background;
- @if(mixin-exists(hook-placeholder)) {@include hook-placeholder();}
-}
-
-/* Add margin if adjacent element */
-* + .uk-placeholder { margin-top: $placeholder-margin-vertical; }
-
-/*
- * Remove margin from the last-child
- */
-
-.uk-placeholder > :last-child { margin-bottom: 0; }
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-placeholder-misc)) {@include hook-placeholder-misc();}
-
-// @mixin hook-placeholder(){}
-// @mixin hook-placeholder-misc(){}
\ No newline at end of file
diff --git a/_sass/uikit/components/position.scss b/_sass/uikit/components/position.scss
deleted file mode 100644
index 799b3587a0..0000000000
--- a/_sass/uikit/components/position.scss
+++ /dev/null
@@ -1,250 +0,0 @@
-// Name: Position
-// Description: Utilities to position content
-//
-// Component: `uk-position-absolute`
-// `uk-position-relative`
-// `uk-position-z-index`
-// `uk-position-top`
-// `uk-position-bottom`
-// `uk-position-left`
-// `uk-position-right`
-// `uk-position-top-left`
-// `uk-position-top-center`
-// `uk-position-top-right`
-// `uk-position-bottom-left`
-// `uk-position-bottom-center`
-// `uk-position-bottom-right`
-// `uk-position-center`
-// `uk-position-center-left`
-// `uk-position-center-right`
-// `uk-position-cover`
-//
-// Modifiers: `uk-position-small`
-// `uk-position-medium`
-// `uk-position-large`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$position-small-margin: $global-small-gutter !default;
-$position-medium-margin: $global-gutter !default;
-$position-large-margin: $global-gutter !default;
-$position-large-margin-l: 50px !default;
-
-
-/* ========================================================================
- Component: Position
- ========================================================================== */
-
-
-/* Directions
- ========================================================================== */
-
-[class*='uk-position-top'],
-[class*='uk-position-bottom'],
-[class*='uk-position-left'],
-[class*='uk-position-right'],
-[class*='uk-position-center'] { position: absolute !important; }
-
-
-/* Edges
- ========================================================================== */
-
-/* Don't use `width: 100%` because it is wrong if the parent has padding. */
-.uk-position-top {
- top: 0;
- left: 0;
- right: 0;
-}
-
-.uk-position-bottom {
- bottom: 0;
- left: 0;
- right: 0;
-}
-
-.uk-position-left {
- top: 0;
- bottom: 0;
- left: 0;
-}
-
-.uk-position-right {
- top: 0;
- bottom: 0;
- right: 0;
-}
-
-
-/* Corners
- ========================================================================== */
-
-.uk-position-top-left {
- top: 0;
- left: 0;
-}
-
-.uk-position-top-right {
- top: 0;
- right: 0;
-}
-
-.uk-position-bottom-left {
- bottom: 0;
- left: 0;
-}
-
-.uk-position-bottom-right {
- bottom: 0;
- right: 0;
-}
-
-/*
- * Center
- * 1. Fix text wrapping if content is larger than 50% of the container (Not working in Firefox)
- * 2. Fix text wrapping for Firefox
- */
-
-.uk-position-center {
- top: 50%;
- left: 50%;
- transform: translate(-50%,-50%);
- /* 1 */
- display: table;
- /* 2 */
- width: -moz-max-content;
- max-width: 100%;
- box-sizing: border-box;
-}
-
-/* Vertical */
-[class*='uk-position-center-left'],
-[class*='uk-position-center-right'] {
- top: 50%;
- transform: translateY(-50%);
-}
-
-.uk-position-center-left { left: 0; }
-.uk-position-center-right { right: 0; }
-
-.uk-position-center-left-out {
- right: 100%;
- width: max-content;
-}
-
-.uk-position-center-right-out {
- left: 100%;
- width: max-content;
-}
-
-/* Horizontal */
-.uk-position-top-center,
-.uk-position-bottom-center {
- left: 50%;
- transform: translateX(-50%);
- /* 1 */
- display: table;
- /* 2 */
- width: -moz-max-content;
- max-width: 100%;
- box-sizing: border-box;
-}
-
-.uk-position-top-center { top: 0; }
-.uk-position-bottom-center { bottom: 0; }
-
-
-/* Cover
- ========================================================================== */
-
-.uk-position-cover {
- position: absolute;
- top: 0;
- bottom: 0;
- left: 0;
- right: 0;
-}
-
-
-/* Utility
- ========================================================================== */
-
-.uk-position-relative { position: relative !important; }
-
-.uk-position-absolute { position: absolute !important; }
-
-.uk-position-fixed { position: fixed !important; }
-
-.uk-position-z-index { z-index: 1; }
-
-
-/* Margin modifier
- ========================================================================== */
-
-/*
- * Small
- */
-
-.uk-position-small { margin: $position-small-margin; }
-
-.uk-position-small.uk-position-center { transform: translate(-50%, -50%) translate(-$position-small-margin, (-$position-small-margin)); }
-
-.uk-position-small[class*='uk-position-center-left'],
-.uk-position-small[class*='uk-position-center-right'] { transform: translateY(-50%) translateY(-$position-small-margin); }
-
-.uk-position-small.uk-position-top-center,
-.uk-position-small.uk-position-bottom-center { transform: translateX(-50%) translateX(-$position-small-margin); }
-
-/*
- * Medium
- */
-
-.uk-position-medium { margin: $position-medium-margin; }
-
-.uk-position-medium.uk-position-center { transform: translate(-50%, -50%) translate(-$position-medium-margin, (-$position-medium-margin)); }
-
-.uk-position-medium[class*='uk-position-center-left'],
-.uk-position-medium[class*='uk-position-center-right'] { transform: translateY(-50%) translateY(-$position-medium-margin); }
-
-.uk-position-medium.uk-position-top-center,
-.uk-position-medium.uk-position-bottom-center { transform: translateX(-50%) translateX(-$position-medium-margin); }
-
-/*
- * Large
- */
-
-.uk-position-large { margin: $position-large-margin; }
-
-.uk-position-large.uk-position-center { transform: translate(-50%, -50%) translate(-$position-large-margin, (-$position-large-margin)); }
-
-.uk-position-large[class*='uk-position-center-left'],
-.uk-position-large[class*='uk-position-center-right'] { transform: translateY(-50%) translateY(-$position-large-margin); }
-
-.uk-position-large.uk-position-top-center,
-.uk-position-large.uk-position-bottom-center { transform: translateX(-50%) translateX(-$position-large-margin); }
-
-/* Desktop and bigger */
-@media (min-width: $breakpoint-large) {
-
- .uk-position-large { margin: $position-large-margin-l; }
-
- .uk-position-large.uk-position-center { transform: translate(-50%, -50%) translate(-$position-large-margin-l, (-$position-large-margin-l)); }
-
- .uk-position-large[class*='uk-position-center-left'],
- .uk-position-large[class*='uk-position-center-right'] { transform: translateY(-50%) translateY(-$position-large-margin-l); }
-
- .uk-position-large.uk-position-top-center,
- .uk-position-large.uk-position-bottom-center { transform: translateX(-50%) translateX(-$position-large-margin-l); }
-
-}
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-position-misc)) {@include hook-position-misc();}
-
-// @mixin hook-position-misc(){}
diff --git a/_sass/uikit/components/print.scss b/_sass/uikit/components/print.scss
deleted file mode 100644
index 6162df525f..0000000000
--- a/_sass/uikit/components/print.scss
+++ /dev/null
@@ -1,61 +0,0 @@
-// Name: Print
-// Description: Optimize page for printing
-//
-// Adapted from http://github.com/h5bp/html5-boilerplate
-//
-// Modifications: Removed link `href` and `title` related rules
-//
-// ========================================================================
-
-
-/* ========================================================================
- Component: Print
- ========================================================================== */
-
-@media print {
-
- *,
- *::before,
- *::after {
- background: transparent !important;
- color: black !important;
- box-shadow: none !important;
- text-shadow: none !important;
- }
-
- a,
- a:visited { text-decoration: underline; }
-
- pre,
- blockquote {
- border: 1px solid #999;
- page-break-inside: avoid;
- }
-
- thead { display: table-header-group; }
-
- tr,
- img { page-break-inside: avoid; }
-
- img { max-width: 100% !important; }
-
- @page { margin: 0.5cm; }
-
- p,
- h2,
- h3 {
- orphans: 3;
- widows: 3;
- }
-
- h2,
- h3 { page-break-after: avoid; }
-
- @if(mixin-exists(hook-print)) {@include hook-print();}
-
-}
-
-// Hooks
-// ========================================================================
-
-// @mixin hook-print(){}
diff --git a/_sass/uikit/components/progress.scss b/_sass/uikit/components/progress.scss
deleted file mode 100644
index 4575513ed6..0000000000
--- a/_sass/uikit/components/progress.scss
+++ /dev/null
@@ -1,105 +0,0 @@
-// Name: Progress
-// Description: Component to create progress bars
-//
-// Component: `uk-progress`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$progress-height: 15px !default;
-$progress-margin-vertical: $global-margin !default;
-$progress-background: $global-muted-background !default;
-
-$progress-bar-background: $global-primary-background !default;
-
-
-/* ========================================================================
- Component: Progress
- ========================================================================== */
-
-/*
- * 1. Add the correct vertical alignment in Chrome, Firefox, and Opera.
- * 2. Remove default style
- * 3. Behave like a block element
- * 4. Remove borders in Firefox and Edge
- * 5. Set background color for progress container in Firefox, IE11 and Edge
- * 6. Style
- */
-
-.uk-progress {
- /* 1 */
- vertical-align: baseline;
- /* 2 */
- -webkit-appearance: none;
- -moz-appearance: none;
- /* 3 */
- display: block;
- width: 100%;
- /* 4 */
- border: 0;
- /* 5 */
- background-color: $progress-background;
- /* 6 */
- margin-bottom: $progress-margin-vertical;
- height: $progress-height;
- @if(mixin-exists(hook-progress)) {@include hook-progress();}
-}
-
-/* Add margin if adjacent element */
-* + .uk-progress { margin-top: $progress-margin-vertical; }
-
-/*
- * Remove animated circles for indeterminate state in IE11 and Edge
- */
-
-.uk-progress:indeterminate { color: transparent; }
-
-/*
- * Progress container
- * 2. Remove progress bar for indeterminate state in Firefox
- */
-
-.uk-progress::-webkit-progress-bar {
- background-color: $progress-background;
- @if(mixin-exists(hook-progress)) {@include hook-progress();}
-}
-
-/* 2 */
-.uk-progress:indeterminate::-moz-progress-bar { width: 0; }
-
-/*
- * Progress bar
- * 1. Remove right border in IE11 and Edge
- */
-
-.uk-progress::-webkit-progress-value {
- background-color: $progress-bar-background;
- transition: width 0.6s ease;
- @if(mixin-exists(hook-progress-bar)) {@include hook-progress-bar();}
-}
-
-.uk-progress::-moz-progress-bar {
- background-color: $progress-bar-background;
- @if(mixin-exists(hook-progress-bar)) {@include hook-progress-bar();}
-}
-
-.uk-progress::-ms-fill {
- background-color: $progress-bar-background;
- transition: width 0.6s ease;
- /* 1 */
- border: 0;
- @if(mixin-exists(hook-progress-bar)) {@include hook-progress-bar();}
-}
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-progress-misc)) {@include hook-progress-misc();}
-
-// @mixin hook-progress(){}
-// @mixin hook-progress-bar(){}
-// @mixin hook-progress-misc(){}
diff --git a/_sass/uikit/components/search.scss b/_sass/uikit/components/search.scss
deleted file mode 100644
index 78a1bf5098..0000000000
--- a/_sass/uikit/components/search.scss
+++ /dev/null
@@ -1,328 +0,0 @@
-// Name: Search
-// Description: Component to create the search
-//
-// Component: `uk-search`
-//
-// Sub-objects: `uk-search-input`
-// `uk-search-toggle`
-//
-// Adopted: `uk-search-icon`
-//
-// Modifier: `uk-search-default`
-// `uk-search-navbar`
-// `uk-search-large`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$search-color: $global-color !default;
-$search-placeholder-color: $global-muted-color !default;
-
-$search-icon-color: $global-muted-color !default;
-
-$search-default-width: 180px !default;
-$search-default-height: $global-control-height !default;
-$search-default-padding-horizontal: 6px !default;
-$search-default-background: $global-muted-background !default;
-$search-default-focus-background: $search-default-background !default;
-
-$search-default-icon-width: $global-control-height !default;
-
-$search-navbar-width: 400px !default;
-$search-navbar-height: 40px !default;
-$search-navbar-background: transparent !default;
-$search-navbar-font-size: $global-large-font-size !default;
-
-$search-navbar-icon-width: 40px !default;
-
-$search-large-width: 500px !default;
-$search-large-height: 80px !default;
-$search-large-background: transparent !default;
-$search-large-font-size: $global-xxlarge-font-size !default;
-
-$search-large-icon-width: 80px !default;
-
-$search-toggle-color: $global-muted-color !default;
-$search-toggle-hover-color: $global-color !default;
-
-
-/* ========================================================================
- Component: Search
- ========================================================================== */
-
-/*
- * 1. Container fits its content
- * 2. Create position context
- * 3. Prevent content overflow
- * 4. Reset `form`
- */
-
-.uk-search {
- /* 1 */
- display: inline-block;
- /* 2 */
- position: relative;
- /* 3 */
- max-width: 100%;
- /* 4 */
- margin: 0;
-}
-
-
-/* Input
- ========================================================================== */
-
-/*
- * Remove the inner padding and cancel buttons in Chrome on OS X and Safari on OS X.
- */
-
-.uk-search-input::-webkit-search-cancel-button,
-.uk-search-input::-webkit-search-decoration { -webkit-appearance: none; }
-
-/*
- * Removes placeholder transparency in Firefox.
- */
-
-.uk-search-input::-moz-placeholder { opacity: 1; }
-
-/*
- * 1. Define consistent box sizing.
- * 2. Address margins set differently in Firefox/IE and Chrome/Safari/Opera.
- * 3. Remove `border-radius` in iOS.
- * 4. Change font properties to `inherit` in all browsers
- * 5. Show the overflow in Edge.
- * 6. Remove default style in iOS.
- * 7. Vertical alignment
- * 8. Take the full container width
- * 9. Style
- */
-
-.uk-search-input {
- /* 1 */
- box-sizing: border-box;
- /* 2 */
- margin: 0;
- /* 3 */
- border-radius: 0;
- /* 4 */
- font: inherit;
- /* 5 */
- overflow: visible;
- /* 6 */
- -webkit-appearance: none;
- /* 7 */
- vertical-align: middle;
- /* 8 */
- width: 100%;
- /* 9 */
- border: none;
- color: $search-color;
- @if(mixin-exists(hook-search-input)) {@include hook-search-input();}
-}
-
-.uk-search-input:focus { outline: none; }
-
-/* Placeholder */
-.uk-search-input:-ms-input-placeholder { color: $search-placeholder-color !important; }
-.uk-search-input::placeholder { color: $search-placeholder-color; }
-
-
-/* Icon (Adopts `uk-icon`)
- ========================================================================== */
-
-/*
- * Remove default focus style
- */
-
-.uk-search-icon:focus { outline: none; }
-
-/*
- * Position above input
- * 1. Set position
- * 2. Center icon vertically and horizontally
- * 3. Style
- */
-
-.uk-search .uk-search-icon {
- /* 1 */
- position: absolute;
- top: 0;
- bottom: 0;
- left: 0;
- /* 2 */
- display: inline-flex;
- justify-content: center;
- align-items: center;
- /* 3 */
- color: $search-icon-color;
-}
-
-/*
- * Required for `a`.
- */
-
-.uk-search .uk-search-icon:hover { color: $search-icon-color; }
-
-/*
- * Make `input` element clickable through icon, e.g. if it's a `span`
- */
-
-.uk-search .uk-search-icon:not(a):not(button):not(input) { pointer-events: none; }
-
-/*
- * Position modifier
- */
-
-.uk-search .uk-search-icon-flip {
- right: 0;
- left: auto;
-}
-
-
-/* Default modifier
- ========================================================================== */
-
-.uk-search-default { width: $search-default-width; }
-
-/*
- * Input
- */
-
-.uk-search-default .uk-search-input {
- height: $search-default-height;
- padding-left: $search-default-padding-horizontal;
- padding-right: $search-default-padding-horizontal;
- background: $search-default-background;
- @if(mixin-exists(hook-search-default-input)) {@include hook-search-default-input();}
-}
-
-/* Focus */
-.uk-search-default .uk-search-input:focus {
- background-color: $search-default-focus-background;
- @if(mixin-exists(hook-search-default-input-focus)) {@include hook-search-default-input-focus();}
-}
-
-/*
- * Icon
- */
-
-.uk-search-default .uk-search-icon { width: $search-default-icon-width; }
-
-.uk-search-default .uk-search-icon:not(.uk-search-icon-flip) + .uk-search-input { padding-left: ($search-default-icon-width); }
-.uk-search-default .uk-search-icon-flip + .uk-search-input { padding-right: ($search-default-icon-width); }
-
-
-/* Navbar modifier
- ========================================================================== */
-
-.uk-search-navbar { width: $search-navbar-width; }
-
-/*
- * Input
- */
-
-.uk-search-navbar .uk-search-input {
- height: $search-navbar-height;
- background: $search-navbar-background;
- font-size: $search-navbar-font-size;
- @if(mixin-exists(hook-search-navbar-input)) {@include hook-search-navbar-input();}
-}
-
-/*
- * Icon
- */
-
-.uk-search-navbar .uk-search-icon { width: $search-navbar-icon-width; }
-
-.uk-search-navbar .uk-search-icon:not(.uk-search-icon-flip) + .uk-search-input { padding-left: ($search-navbar-icon-width); }
-.uk-search-navbar .uk-search-icon-flip + .uk-search-input { padding-right: ($search-navbar-icon-width); }
-
-
-/* Large modifier
- ========================================================================== */
-
-.uk-search-large { width: $search-large-width; }
-
-/*
- * Input
- */
-
-.uk-search-large .uk-search-input {
- height: $search-large-height;
- background: $search-large-background;
- font-size: $search-large-font-size;
- @if(mixin-exists(hook-search-large-input)) {@include hook-search-large-input();}
-}
-
-/*
- * Icon
- */
-
-.uk-search-large .uk-search-icon { width: $search-large-icon-width; }
-
-.uk-search-large .uk-search-icon:not(.uk-search-icon-flip) + .uk-search-input { padding-left: ($search-large-icon-width); }
-.uk-search-large .uk-search-icon-flip + .uk-search-input { padding-right: ($search-large-icon-width); }
-
-
-/* Toggle
- ========================================================================== */
-
-.uk-search-toggle {
- color: $search-toggle-color;
- @if(mixin-exists(hook-search-toggle)) {@include hook-search-toggle();}
-}
-
-/* Hover + Focus */
-.uk-search-toggle:hover,
-.uk-search-toggle:focus {
- color: $search-toggle-hover-color;
- @if(mixin-exists(hook-search-toggle-hover)) {@include hook-search-toggle-hover();}
-}
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-search-misc)) {@include hook-search-misc();}
-
-// @mixin hook-search-input(){}
-// @mixin hook-search-default-input(){}
-// @mixin hook-search-default-input-focus(){}
-// @mixin hook-search-navbar-input(){}
-// @mixin hook-search-large-input(){}
-
-// @mixin hook-search-toggle(){}
-// @mixin hook-search-toggle-hover(){}
-
-// @mixin hook-search-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-$inverse-search-color: $inverse-global-color !default;
-$inverse-search-placeholder-color: $inverse-global-muted-color !default;
-
-$inverse-search-icon-color: $inverse-global-muted-color !default;
-
-$inverse-search-default-background: $inverse-global-muted-background !default;
-$inverse-search-default-focus-background: $inverse-search-default-background !default;
-
-$inverse-search-navbar-background: transparent !default;
-
-$inverse-search-large-background: transparent !default;
-
-$inverse-search-toggle-color: $inverse-global-muted-color !default;
-$inverse-search-toggle-hover-color: $inverse-global-color !default;
-
-
-
-// @mixin hook-inverse-search-default-input(){}
-// @mixin hook-inverse-search-default-input-focus(){}
-// @mixin hook-inverse-search-navbar-input(){}
-// @mixin hook-inverse-search-large-input(){}
-// @mixin hook-inverse-search-toggle(){}
-// @mixin hook-inverse-search-toggle-hover(){}
diff --git a/_sass/uikit/components/section.scss b/_sass/uikit/components/section.scss
deleted file mode 100644
index 3c0707a156..0000000000
--- a/_sass/uikit/components/section.scss
+++ /dev/null
@@ -1,226 +0,0 @@
-// Name: Section
-// Description: Component to create horizontal layout section
-//
-// Component: `uk-section`
-//
-// Modifiers: `uk-section-xsmall`
-// `uk-section-small`
-// `uk-section-large`
-// `uk-section-xlarge`
-// `uk-section-default`
-// `uk-section-muted`
-// `uk-section-primary`
-// `uk-section-secondary`
-// `uk-section-overlap`
-//
-// States: `uk-preserve-color`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$section-padding-vertical: $global-medium-margin !default;
-$section-padding-vertical-m: $global-large-margin !default;
-
-$section-xsmall-padding-vertical: $global-margin !default;
-
-$section-small-padding-vertical: $global-medium-margin !default;
-
-$section-large-padding-vertical: $global-large-margin !default;
-$section-large-padding-vertical-m: $global-xlarge-margin !default;
-
-$section-xlarge-padding-vertical: $global-xlarge-margin !default;
-$section-xlarge-padding-vertical-m: ($global-large-margin + $global-xlarge-margin) !default;
-
-$section-default-background: $global-background !default;
-
-$section-muted-background: $global-muted-background !default;
-
-$section-primary-background: $global-primary-background !default;
-$section-primary-color-mode: light !default;
-
-$section-secondary-background: $global-secondary-background !default;
-$section-secondary-color-mode: light !default;
-
-
-/* ========================================================================
- Component: Section
- ========================================================================== */
-
-/*
- * 1. Make it work with `100vh` and height in general
- */
-
-.uk-section {
- box-sizing: border-box; /* 1 */
- padding-top: $section-padding-vertical;
- padding-bottom: $section-padding-vertical;
- @if(mixin-exists(hook-section)) {@include hook-section();}
-}
-
-/* Desktop and bigger */
-@media (min-width: $breakpoint-medium) {
-
- .uk-section {
- // padding-top: $section-padding-vertical-m;
- // padding-bottom: $section-padding-vertical-m;
- padding-top: 15px;
- padding-bottom: 15px;
- }
-
-}
-
-/*
- * Micro clearfix
- */
-
-.uk-section::before,
-.uk-section::after {
- content: "";
- display: table;
-}
-
-.uk-section::after { clear: both; }
-
-/*
- * Remove margin from the last-child
- */
-
-.uk-section > :last-child { margin-bottom: 0; }
-
-
-/* Size modifiers
- ========================================================================== */
-
-/*
- * XSmall
- */
-
-.uk-section-xsmall {
- padding-top: $section-xsmall-padding-vertical;
- padding-bottom: $section-xsmall-padding-vertical;
-}
-
-/*
- * Small
- */
-
-.uk-section-small {
- padding-top: $section-small-padding-vertical;
- padding-bottom: $section-small-padding-vertical;
-}
-
-/*
- * Large
- */
-
-.uk-section-large {
- padding-top: $section-large-padding-vertical;
- padding-bottom: $section-large-padding-vertical;
-}
-
-/* Tablet landscape and bigger */
-@media (min-width: $breakpoint-medium) {
-
- .uk-section-large {
- padding-top: $section-large-padding-vertical-m;
- padding-bottom: $section-large-padding-vertical-m;
- }
-
-}
-
-
-/*
- * XLarge
- */
-
-.uk-section-xlarge {
- padding-top: $section-xlarge-padding-vertical;
- padding-bottom: $section-xlarge-padding-vertical;
-}
-
-/* Tablet landscape and bigger */
-@media (min-width: $breakpoint-medium) {
-
- .uk-section-xlarge {
- padding-top: $section-xlarge-padding-vertical-m;
- padding-bottom: $section-xlarge-padding-vertical-m;
- }
-
-}
-
-
-/* Style modifiers
- ========================================================================== */
-
-/*
- * Default
- */
-
-.uk-section-default {
- background: $section-default-background;
- @if(mixin-exists(hook-section-default)) {@include hook-section-default();}
-}
-
-/*
- * Muted
- */
-
-.uk-section-muted {
- background: $section-muted-background;
- @if(mixin-exists(hook-section-muted)) {@include hook-section-muted();}
-}
-
-/*
- * Primary
- */
-
-.uk-section-primary {
- background: $section-primary-background;
- @if(mixin-exists(hook-section-primary)) {@include hook-section-primary();}
-}
-
-@if ( $section-primary-color-mode == light ) { .uk-section-primary:not(.uk-preserve-color) { @extend .uk-light !optional;} }
-@if ( $section-primary-color-mode == dark ) { .uk-section-primary:not(.uk-preserve-color) { @extend .uk-dark !optional;} }
-
-
-/*
- * Secondary
- */
-
-.uk-section-secondary {
- background: $section-secondary-background;
- @if(mixin-exists(hook-section-secondary)) {@include hook-section-secondary();}
-}
-
-@if ( $section-secondary-color-mode == light ) { .uk-section-secondary:not(.uk-preserve-color) { @extend .uk-light !optional;} }
-@if ( $section-secondary-color-mode == dark ) { .uk-section-secondary:not(.uk-preserve-color) { @extend .uk-dark !optional;} }
-
-
-/* Overlap modifier
- ========================================================================== */
-
-/*
- * Reserved modifier to make a section overlap another section with an border image
- * Implemented by the theme
- */
-
-.uk-section-overlap {
- @if(mixin-exists(hook-section-overlap)) {@include hook-section-overlap();}
-}
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-section-misc)) {@include hook-section-misc();}
-
-// @mixin hook-section(){}
-// @mixin hook-section-default(){}
-// @mixin hook-section-muted(){}
-// @mixin hook-section-secondary(){}
-// @mixin hook-section-primary(){}
-// @mixin hook-section-overlap(){}
-// @mixin hook-section-misc(){}
diff --git a/_sass/uikit/components/slidenav.scss b/_sass/uikit/components/slidenav.scss
deleted file mode 100644
index 0b9af8f256..0000000000
--- a/_sass/uikit/components/slidenav.scss
+++ /dev/null
@@ -1,122 +0,0 @@
-// Name: Slidenav
-// Description: Component to create previous/next icon navigations
-//
-// Component: `uk-slidenav`
-//
-// Sub-objects: `uk-slidenav-container`
-//
-// Modifiers: `uk-slidenav-previous`
-// `uk-slidenav-next`
-// `uk-slidenav-large`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$slidenav-padding-vertical: 5px !default;
-$slidenav-padding-horizontal: 10px !default;
-
-$slidenav-color: rgba($global-color, 0.5) !default;
-$slidenav-hover-color: rgba($global-color, 0.9) !default;
-$slidenav-active-color: rgba($global-color, 0.5) !default;
-
-$slidenav-large-padding-vertical: 10px !default;
-$slidenav-large-padding-horizontal: $slidenav-large-padding-vertical !default;
-
-
-/* ========================================================================
- Component: Slidenav
- ========================================================================== */
-
-/*
- * Adopts `uk-icon`
- */
-
-.uk-slidenav {
- padding: $slidenav-padding-vertical $slidenav-padding-horizontal;
- color: $slidenav-color;
- @if(mixin-exists(hook-slidenav)) {@include hook-slidenav();}
-}
-
-/* Hover + Focus */
-.uk-slidenav:hover,
-.uk-slidenav:focus {
- color: $slidenav-hover-color;
- outline: none;
- @if(mixin-exists(hook-slidenav-hover)) {@include hook-slidenav-hover();}
-}
-
-/* OnClick */
-.uk-slidenav:active {
- color: $slidenav-active-color;
- @if(mixin-exists(hook-slidenav-active)) {@include hook-slidenav-active();}
-}
-
-
-/* Icon modifier
- ========================================================================== */
-
-/*
- * Previous
- */
-
-.uk-slidenav-previous {
- @if(mixin-exists(hook-slidenav-previous)) {@include hook-slidenav-previous();}
-}
-
-/*
- * Next
- */
-
-.uk-slidenav-next {
- @if(mixin-exists(hook-slidenav-next)) {@include hook-slidenav-next();}
-}
-
-
-/* Size modifier
- ========================================================================== */
-
-.uk-slidenav-large {
- padding: $slidenav-large-padding-vertical $slidenav-large-padding-horizontal;
- @if(mixin-exists(hook-slidenav-large)) {@include hook-slidenav-large();}
-}
-
-
-/* Container
- ========================================================================== */
-
-.uk-slidenav-container {
- display: flex;
- @if(mixin-exists(hook-slidenav-container)) {@include hook-slidenav-container();}
-}
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-slidenav-misc)) {@include hook-slidenav-misc();}
-
-// @mixin hook-slidenav(){}
-// @mixin hook-slidenav-hover(){}
-// @mixin hook-slidenav-active(){}
-// @mixin hook-slidenav-previous(){}
-// @mixin hook-slidenav-next(){}
-// @mixin hook-slidenav-large(){}
-// @mixin hook-slidenav-container(){}
-// @mixin hook-slidenav-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-$inverse-slidenav-color: rgba($inverse-global-color, 0.7) !default;
-$inverse-slidenav-hover-color: rgba($inverse-global-color, 0.95) !default;
-$inverse-slidenav-active-color: rgba($inverse-global-color, 0.7) !default;
-
-
-
-// @mixin hook-inverse-slidenav(){}
-// @mixin hook-inverse-slidenav-hover(){}
-// @mixin hook-inverse-slidenav-active(){}
diff --git a/_sass/uikit/components/slider.scss b/_sass/uikit/components/slider.scss
deleted file mode 100644
index 2799868e28..0000000000
--- a/_sass/uikit/components/slider.scss
+++ /dev/null
@@ -1,99 +0,0 @@
-// Name: Slider
-// Description: Component to create horizontal sliders
-//
-// Component: `uk-slider`
-//
-// Sub-objects: `uk-slider-container`
-// `uk-slider-items`
-//
-// States: `uk-active`
-//
-// ========================================================================
-
-
-/* ========================================================================
- Component: Slider
- ========================================================================== */
-
-/*
- * 1. Prevent tab highlighting on iOS.
- */
-
-.uk-slider {
- /* 1 */
- -webkit-tap-highlight-color: transparent;
- @if(mixin-exists(hook-slider)) {@include hook-slider();}
-}
-
-
-/* Container
- ========================================================================== */
-
-/*
- * 1. Clip child elements
- */
-
-.uk-slider-container {
- /* 1 */
- overflow: hidden;
-}
-
-/* Items
- ========================================================================== */
-
-/*
- * 1. Optimize animation
- * 2. Create a containing block. In Safari it's neither created by `transform` nor `will-change`.
- */
-
-.uk-slider-items {
- /* 1 */
- will-change: transform;
- /* 2 */
- position: relative;
-}
-
-/*
- * 1. Reset list style without interfering with grid
- * 2. Prevent displaying the callout information on iOS.
- */
-
-.uk-slider-items:not(.uk-grid) {
- display: flex;
- /* 1 */
- margin: 0;
- padding: 0;
- list-style: none;
- /* 2 */
- -webkit-touch-callout: none;
-}
-
-.uk-slider-items.uk-grid { flex-wrap: nowrap; }
-
-
-/* Item
- ========================================================================== */
-
-/*
- * 1. Let items take content dimensions (0 0 auto)
- * 2. Create position context
- * 3. Disable horizontal panning gestures in IE11 and Edge
- */
-
-.uk-slider-items > * {
- /* 1 */
- flex: none;
- /* 2 */
- position: relative;
- /* 3 */
- touch-action: pan-y;
-}
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-slider-misc)) {@include hook-slider-misc();}
-
-// @mixin hook-slider(){}
-// @mixin hook-slider-misc(){}
diff --git a/_sass/uikit/components/slideshow.scss b/_sass/uikit/components/slideshow.scss
deleted file mode 100644
index fc355d419d..0000000000
--- a/_sass/uikit/components/slideshow.scss
+++ /dev/null
@@ -1,93 +0,0 @@
-// Name: Slideshow
-// Description: Component to create slideshows
-//
-// Component: `uk-slideshow`
-//
-// Sub-objects: `uk-slideshow-items`
-//
-// States: `uk-active`
-//
-// ========================================================================
-
-
-/* ========================================================================
- Component: Slideshow
- ========================================================================== */
-
-/*
- * 1. Prevent tab highlighting on iOS.
- */
-
-.uk-slideshow {
- /* 1 */
- -webkit-tap-highlight-color: transparent;
- @if(mixin-exists(hook-slideshow)) {@include hook-slideshow();}
-}
-
-
-/* Items
- ========================================================================== */
-
-/*
- * 1. Create position and stacking context
- * 2. Reset list
- * 3. Clip child elements
- * 4. Prevent displaying the callout information on iOS.
- */
-
-.uk-slideshow-items {
- /* 1 */
- position: relative;
- z-index: 0;
- /* 2 */
- margin: 0;
- padding: 0;
- list-style: none;
- /* 3 */
- overflow: hidden;
- /* 4 */
- -webkit-touch-callout: none;
-}
-
-
-/* Item
- ========================================================================== */
-
-/*
- * 1. Position items above each other
- * 2. Take the full width
- * 3. Clip child elements, e.g. for `uk-cover`
- * 4. Optimize animation
- * 5. Disable horizontal panning gestures in IE11 and Edge
- */
-
-.uk-slideshow-items > * {
- /* 1 */
- position: absolute;
- top: 0;
- left: 0;
- /* 2 */
- right: 0;
- bottom: 0;
- /* 3 */
- overflow: hidden;
- /* 4 */
- will-change: transform, opacity;
- /* 5 */
- touch-action: pan-y;
-}
-
-/*
- * Hide not active items
- */
-
-.uk-slideshow-items > :not(.uk-active) { display: none; }
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-slideshow-misc)) {@include hook-slideshow-misc();}
-
-// @mixin hook-slideshow(){}
-// @mixin hook-slideshow-misc(){}
diff --git a/_sass/uikit/components/sortable.scss b/_sass/uikit/components/sortable.scss
deleted file mode 100644
index 8895f11c1f..0000000000
--- a/_sass/uikit/components/sortable.scss
+++ /dev/null
@@ -1,101 +0,0 @@
-// Name: Sortable
-// Description: Component to create sortable grids and lists
-//
-// Component: `uk-sortable`
-//
-// Sub-objects: `uk-sortable-drag`
-// `uk-sortable-placeholder`
-// `uk-sortable-handle`
-//
-// Modifiers: `uk-sortable-empty`
-//
-// States: `uk-drag`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$sortable-dragged-z-index: $global-z-index + 50 !default;
-
-$sortable-placeholder-opacity: 0 !default;
-
-$sortable-empty-height: 50px !default;
-
-
-/* ========================================================================
- Component: Sortable
- ========================================================================== */
-
-.uk-sortable {
- position: relative;
- @if(mixin-exists(hook-sortable)) {@include hook-sortable();}
-}
-
-/*
- * Deactivate browser touch actions in IE11 and Edge
- */
-
-.uk-sortable > * { touch-action: none; }
-
-/*
- * Deactivate pointer-events on SVGs in Safari
- */
-
-.uk-sortable svg { pointer-events: none; }
-
-/*
- * Remove margin from the last-child
- */
-
-.uk-sortable > :last-child { margin-bottom: 0; }
-
-
-/* Drag
- ========================================================================== */
-
-.uk-sortable-drag {
- position: absolute !important;
- z-index: $sortable-dragged-z-index !important;
- pointer-events: none;
- @if(mixin-exists(hook-sortable-drag)) {@include hook-sortable-drag();}
-}
-
-
-/* Placeholder
- ========================================================================== */
-
-.uk-sortable-placeholder {
- opacity: $sortable-placeholder-opacity;
- @if(mixin-exists(hook-sortable-placeholder)) {@include hook-sortable-placeholder();}
-}
-
-
-/* Empty modifier
- ========================================================================== */
-
-.uk-sortable-empty {
- min-height: $sortable-empty-height;
- @if(mixin-exists(hook-sortable-empty)) {@include hook-sortable-empty();}
-}
-
-
-/* Handle
- ========================================================================== */
-
-/* Hover */
-.uk-sortable-handle:hover { cursor: move; }
-
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-sortable-misc)) {@include hook-sortable-misc();}
-
-// @mixin hook-sortable(){}
-// @mixin hook-sortable-drag(){}
-// @mixin hook-sortable-placeholder(){}
-// @mixin hook-sortable-empty(){}
-// @mixin hook-sortable-misc(){}
diff --git a/_sass/uikit/components/spinner.scss b/_sass/uikit/components/spinner.scss
deleted file mode 100644
index a02f41d17b..0000000000
--- a/_sass/uikit/components/spinner.scss
+++ /dev/null
@@ -1,74 +0,0 @@
-// Name: Spinner
-// Description: Component to create a loading spinner
-//
-// Component: `uk-spinner`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$spinner-size: 30px !default;
-$spinner-stroke-width: 1 !default;
-$spinner-radius: floor(($spinner-size - $spinner-stroke-width) / 2) !default; // Minus stroke width to prevent overflow clipping
-$spinner-circumference: round(2 * 3.141 * $spinner-radius) !default;
-$spinner-duration: 1.4s !default;
-
-
-/* ========================================================================
- Component: Spinner
- ========================================================================== */
-
-/*
- * Adopts `uk-icon`
- */
-
-.uk-spinner {
- @if(mixin-exists(hook-spinner)) {@include hook-spinner();}
-}
-
-
-/* SVG
- ========================================================================== */
-
-.uk-spinner > * { animation: uk-spinner-rotate $spinner-duration linear infinite; }
-
-@keyframes uk-spinner-rotate {
- 0% { transform: rotate(0deg); }
- 100% { transform: rotate(270deg); }
-}
-
-/*
- * Circle
- */
-
-.uk-spinner > * > * {
- stroke-dasharray: $spinner-circumference;
- stroke-dashoffset: 0;
- transform-origin: center;
- animation: uk-spinner-dash $spinner-duration ease-in-out infinite;
- stroke-width: $spinner-stroke-width;
- stroke-linecap: round;
-}
-
-@keyframes uk-spinner-dash {
- 0% { stroke-dashoffset: $spinner-circumference; }
- 50% {
- stroke-dashoffset: $spinner-circumference/4;
- transform:rotate(135deg);
- }
- 100% {
- stroke-dashoffset: $spinner-circumference;
- transform:rotate(450deg);
- }
-}
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-spinner-misc)) {@include hook-spinner-misc();}
-
-// @mixin hook-spinner(){}
-// @mixin hook-spinner-misc(){}
diff --git a/_sass/uikit/components/sticky.scss b/_sass/uikit/components/sticky.scss
deleted file mode 100644
index e8e54f9201..0000000000
--- a/_sass/uikit/components/sticky.scss
+++ /dev/null
@@ -1,53 +0,0 @@
-// Name: Sticky
-// Description: Component to make elements sticky in the viewport
-//
-// Component: `uk-sticky`
-//
-// Modifier: `uk-sticky-fixed`
-//
-// States: `uk-active`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$sticky-z-index: $global-z-index - 20 !default;
-
-$sticky-animation-duration: 0.2s !default;
-$sticky-reverse-animation-duration: 0.2s !default;
-
-
-/* ========================================================================
- Component: Sticky
- ========================================================================== */
-
-/*
- * 1. Resolve frame rate issues on devices with lower frame rates by forcing hardware acceleration
- */
-
-.uk-sticky-fixed {
- z-index: $sticky-z-index;
- box-sizing: border-box;
- margin: 0 !important;
- /* 1 */
- -webkit-backface-visibility: hidden;
- backface-visibility: hidden;
-}
-
-/*
- * Faster animations
- */
-
-.uk-sticky[class*='uk-animation-'] { animation-duration: $sticky-animation-duration; }
-
-.uk-sticky.uk-animation-reverse { animation-duration: $sticky-reverse-animation-duration; }
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-sticky-misc)) {@include hook-sticky-misc();}
-
-// @mixin hook-sticky-misc(){}
diff --git a/_sass/uikit/components/subnav.scss b/_sass/uikit/components/subnav.scss
deleted file mode 100644
index 5397501669..0000000000
--- a/_sass/uikit/components/subnav.scss
+++ /dev/null
@@ -1,232 +0,0 @@
-// Name: Subnav
-// Description: Component to create a sub navigation
-//
-// Component: `uk-subnav`
-//
-// Modifiers: `uk-subnav-divider`
-// `uk-subnav-pill`
-//
-// States: `uk-active`
-// `uk-first-column`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$subnav-margin-horizontal: 20px !default;
-
-$subnav-item-color: $global-muted-color !default;
-$subnav-item-hover-color: $global-color !default;
-$subnav-item-hover-text-decoration: none !default;
-$subnav-item-active-color: $global-emphasis-color !default;
-
-$subnav-divider-margin-horizontal: $subnav-margin-horizontal !default;
-$subnav-divider-border-height: 1.5em !default;
-$subnav-divider-border-width: $global-border-width !default;
-$subnav-divider-border: $global-border !default;
-
-$subnav-pill-item-padding-vertical: 5px !default;
-$subnav-pill-item-padding-horizontal: 10px !default;
-$subnav-pill-item-background: transparent !default;
-$subnav-pill-item-color: $subnav-item-color !default;
-$subnav-pill-item-hover-background: $global-muted-background !default;
-$subnav-pill-item-hover-color: $global-color !default;
-$subnav-pill-item-onclick-background: $subnav-pill-item-hover-background !default;
-$subnav-pill-item-onclick-color: $subnav-pill-item-hover-color !default;
-$subnav-pill-item-active-background: $global-primary-background !default;
-$subnav-pill-item-active-color: $global-inverse-color !default;
-
-$subnav-item-disabled-color: $global-muted-color !default;
-
-
-/* ========================================================================
- Component: Subnav
- ========================================================================== */
-
-/*
- * 1. Allow items to wrap into the next line
- * 2. Gutter
- * 3. Reset list
- */
-
-.uk-subnav {
- display: flex;
- /* 1 */
- flex-wrap: wrap;
- /* 2 */
- margin-left: (-$subnav-margin-horizontal);
- /* 3 */
- padding: 0;
- list-style: none;
- @if(mixin-exists(hook-subnav)) {@include hook-subnav();}
-}
-
-/*
- * 1. Space is allocated solely based on content dimensions: 0 0 auto
- * 2. Gutter
- * 3. Create position context for dropdowns
- */
-
-.uk-subnav > * {
- /* 1 */
- flex: none;
- /* 2 */
- padding-left: $subnav-margin-horizontal;
- /* 3 */
- position: relative;
-}
-
-
-/* Items
- ========================================================================== */
-
-/*
- * Items must target `a` elements to exclude other elements (e.g. dropdowns)
- * Using `:first-child` instead of `a` to support `span` elements for text
- * 1. Prevent gap if child element is `inline-block`, e.g. an icon
- * 2. Style
- */
-
-.uk-subnav > * > :first-child {
- /* 1 */
- display: block;
- /* 2 */
- color: $subnav-item-color;
- @if(mixin-exists(hook-subnav-item)) {@include hook-subnav-item();}
-}
-
-/* Hover + Focus */
-.uk-subnav > * > a:hover,
-.uk-subnav > * > a:focus {
- color: $subnav-item-hover-color;
- text-decoration: $subnav-item-hover-text-decoration;
- outline: none;
- @if(mixin-exists(hook-subnav-item-hover)) {@include hook-subnav-item-hover();}
-}
-
-/* Active */
-.uk-subnav > .uk-active > a {
- color: $subnav-item-active-color;
- @if(mixin-exists(hook-subnav-item-active)) {@include hook-subnav-item-active();}
-}
-
-
-/* Divider modifier
- ========================================================================== */
-
-/*
- * 1. Align items and divider vertically
- */
-
-.uk-subnav-divider > * {
- /* 1 */
- display: flex;
- align-items: center;
-}
-
-/*
- * Divider
- * `nth-child` makes it also work without JS if it's only one row
- */
-
-.uk-subnav-divider > :nth-child(n+2):not(.uk-first-column)::before {
- content: "";
- height: $subnav-divider-border-height;
- margin-left: ($subnav-divider-margin-horizontal - $subnav-margin-horizontal);
- margin-right: $subnav-divider-margin-horizontal;
- border-left: $subnav-divider-border-width solid $subnav-divider-border;
- @if(mixin-exists(hook-subnav-divider)) {@include hook-subnav-divider();}
-}
-
-
-/* Pill modifier
- ========================================================================== */
-
-.uk-subnav-pill > * > :first-child {
- padding: $subnav-pill-item-padding-vertical $subnav-pill-item-padding-horizontal;
- background: $subnav-pill-item-background;
- color: $subnav-pill-item-color;
- @if(mixin-exists(hook-subnav-pill-item)) {@include hook-subnav-pill-item();}
-}
-
-/* Hover + Focus */
-.uk-subnav-pill > * > a:hover,
-.uk-subnav-pill > * > a:focus {
- background-color: $subnav-pill-item-hover-background;
- color: $subnav-pill-item-hover-color;
- @if(mixin-exists(hook-subnav-pill-item-hover)) {@include hook-subnav-pill-item-hover();}
-}
-
-/* OnClick */
-.uk-subnav-pill > * > a:active {
- background-color: $subnav-pill-item-onclick-background;
- color: $subnav-pill-item-onclick-color;
- @if(mixin-exists(hook-subnav-pill-item-onclick)) {@include hook-subnav-pill-item-onclick();}
-}
-
-/* Active */
-.uk-subnav-pill > .uk-active > a {
- background-color: $subnav-pill-item-active-background;
- color: $subnav-pill-item-active-color;
- @if(mixin-exists(hook-subnav-pill-item-active)) {@include hook-subnav-pill-item-active();}
-}
-
-
-/* Disabled
- * The same for all style modifiers
- ========================================================================== */
-
-.uk-subnav > .uk-disabled > a {
- color: $subnav-item-disabled-color;
- @if(mixin-exists(hook-subnav-item-disabled)) {@include hook-subnav-item-disabled();}
-}
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-subnav-misc)) {@include hook-subnav-misc();}
-
-// @mixin hook-subnav(){}
-// @mixin hook-subnav-item(){}
-// @mixin hook-subnav-item-hover(){}
-// @mixin hook-subnav-item-active(){}
-// @mixin hook-subnav-divider(){}
-// @mixin hook-subnav-pill-item(){}
-// @mixin hook-subnav-pill-item-hover(){}
-// @mixin hook-subnav-pill-item-onclick(){}
-// @mixin hook-subnav-pill-item-active(){}
-// @mixin hook-subnav-item-disabled(){}
-// @mixin hook-subnav-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-$inverse-subnav-item-color: $inverse-global-muted-color !default;
-$inverse-subnav-item-hover-color: $inverse-global-color !default;
-$inverse-subnav-item-active-color: $inverse-global-emphasis-color !default;
-$inverse-subnav-divider-border: $inverse-global-border !default;
-$inverse-subnav-pill-item-background: transparent !default;
-$inverse-subnav-pill-item-color: $inverse-global-muted-color !default;
-$inverse-subnav-pill-item-hover-background: $inverse-global-muted-background !default;
-$inverse-subnav-pill-item-hover-color: $inverse-global-color !default;
-$inverse-subnav-pill-item-onclick-background: $inverse-subnav-pill-item-hover-background !default;
-$inverse-subnav-pill-item-onclick-color: $inverse-subnav-pill-item-hover-color !default;
-$inverse-subnav-pill-item-active-background: $inverse-global-primary-background !default;
-$inverse-subnav-pill-item-active-color: $inverse-global-inverse-color !default;
-$inverse-subnav-item-disabled-color: $inverse-global-muted-color !default;
-
-
-
-// @mixin hook-inverse-subnav-item(){}
-// @mixin hook-inverse-subnav-item-hover(){}
-// @mixin hook-inverse-subnav-item-active(){}
-// @mixin hook-inverse-subnav-divider(){}
-// @mixin hook-inverse-subnav-pill-item(){}
-// @mixin hook-inverse-subnav-pill-item-hover(){}
-// @mixin hook-inverse-subnav-pill-item-onclick(){}
-// @mixin hook-inverse-subnav-pill-item-active(){}
-// @mixin hook-inverse-subnav-item-disabled(){}
diff --git a/_sass/uikit/components/switcher.scss b/_sass/uikit/components/switcher.scss
deleted file mode 100644
index 0d99cdf7b9..0000000000
--- a/_sass/uikit/components/switcher.scss
+++ /dev/null
@@ -1,47 +0,0 @@
-// Name: Switcher
-// Description: Component to navigate through different content panes
-//
-// Component: `uk-switcher`
-//
-// States: `uk-active`
-//
-// ========================================================================
-
-
-/* ========================================================================
- Component: Switcher
- ========================================================================== */
-
-/*
- * Reset list
- */
-
-.uk-switcher {
- margin: 0;
- padding: 0;
- list-style: none;
-}
-
-
-/* Items
- ========================================================================== */
-
-/*
- * Hide not active items
- */
-
-.uk-switcher > :not(.uk-active) { display: none; }
-
-/*
- * Remove margin from the last-child
- */
-
-.uk-switcher > * > :last-child { margin-bottom: 0; }
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-switcher-misc)) {@include hook-switcher-misc();}
-
-// @mixin hook-switcher-misc(){}
\ No newline at end of file
diff --git a/_sass/uikit/components/tab.scss b/_sass/uikit/components/tab.scss
deleted file mode 100644
index 87e0a678d8..0000000000
--- a/_sass/uikit/components/tab.scss
+++ /dev/null
@@ -1,191 +0,0 @@
-// Name: Tab
-// Description: Component to create a tabbed navigation
-//
-// Component: `uk-tab`
-//
-// Modifiers: `uk-tab-bottom`
-// `uk-tab-left`
-// `uk-tab-right`
-//
-// States: `uk-active`
-// `uk-disabled`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$tab-margin-horizontal: 20px !default;
-
-$tab-item-padding-horizontal: 10px !default;
-$tab-item-padding-vertical: 5px !default;
-$tab-item-color: $global-muted-color !default;
-$tab-item-hover-color: $global-color !default;
-$tab-item-hover-text-decoration: none !default;
-$tab-item-active-color: $global-emphasis-color !default;
-$tab-item-disabled-color: $global-muted-color !default;
-
-
-/* ========================================================================
- Component: Tab
- ========================================================================== */
-
-/*
- * 1. Allow items to wrap into the next line
- * 2. Gutter
- * 3. Reset list
- */
-
-.uk-tab {
- display: flex;
- /* 1 */
- flex-wrap: wrap;
- /* 2 */
- margin-left: (-$tab-margin-horizontal);
- /* 3 */
- padding: 0;
- list-style: none;
- @if(mixin-exists(hook-tab)) {@include hook-tab();}
-}
-
-/*
- * 1. Space is allocated solely based on content dimensions: 0 0 auto
- * 2. Gutter
- * 3. Create position context for dropdowns
- */
-
-.uk-tab > * {
- /* 1 */
- flex: none;
- /* 2 */
- padding-left: $tab-margin-horizontal;
- /* 3 */
- position: relative;
-}
-
-
-/* Items
- ========================================================================== */
-
-/*
- * Items must target `a` elements to exclude other elements (e.g. dropdowns)
- * 1. Center text if a width is set
- * 2. Style
- */
-
-.uk-tab > * > a {
- /* 1 */
- display: block;
- text-align: center;
- /* 2 */
- padding: $tab-item-padding-vertical $tab-item-padding-horizontal;
- color: $tab-item-color;
- @if(mixin-exists(hook-tab-item)) {@include hook-tab-item();}
-}
-
-/* Hover + Focus */
-.uk-tab > * > a:hover,
-.uk-tab > * > a:focus {
- color: $tab-item-hover-color;
- text-decoration: $tab-item-hover-text-decoration;
- @if(mixin-exists(hook-tab-item-hover)) {@include hook-tab-item-hover();}
-}
-
-/* Active */
-.uk-tab > .uk-active > a {
- color: $tab-item-active-color;
- @if(mixin-exists(hook-tab-item-active)) {@include hook-tab-item-active();}
-}
-
-/* Disabled */
-.uk-tab > .uk-disabled > a {
- color: $tab-item-disabled-color;
- @if(mixin-exists(hook-tab-item-disabled)) {@include hook-tab-item-disabled();}
-}
-
-
-/* Position modifier
- ========================================================================== */
-
-/*
- * Bottom
- */
-
-.uk-tab-bottom {
- @if(mixin-exists(hook-tab-bottom)) {@include hook-tab-bottom();}
-}
-
-.uk-tab-bottom > * > a {
- @if(mixin-exists(hook-tab-bottom-item)) {@include hook-tab-bottom-item();}
-}
-
-/*
- * Left + Right
- * 1. Reset Gutter
- */
-
-.uk-tab-left,
-.uk-tab-right {
- flex-direction: column;
- /* 1 */
- margin-left: 0;
-}
-
-/* 1 */
-.uk-tab-left > *,
-.uk-tab-right > * { padding-left: 0; }
-
-.uk-tab-left {
- @if(mixin-exists(hook-tab-left)) {@include hook-tab-left();}
-}
-
-.uk-tab-right {
- @if(mixin-exists(hook-tab-right)) {@include hook-tab-right();}
-}
-
-.uk-tab-left > * > a {
- text-align: left;
- @if(mixin-exists(hook-tab-left-item)) {@include hook-tab-left-item();}
-}
-
-.uk-tab-right > * > a {
- text-align: left;
- @if(mixin-exists(hook-tab-right-item)) {@include hook-tab-right-item();}
-}
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-tab-misc)) {@include hook-tab-misc();}
-
-// @mixin hook-tab(){}
-// @mixin hook-tab-item(){}
-// @mixin hook-tab-item-hover(){}
-// @mixin hook-tab-item-active(){}
-// @mixin hook-tab-item-disabled(){}
-// @mixin hook-tab-bottom(){}
-// @mixin hook-tab-bottom-item(){}
-// @mixin hook-tab-left(){}
-// @mixin hook-tab-left-item(){}
-// @mixin hook-tab-right(){}
-// @mixin hook-tab-right-item(){}
-// @mixin hook-tab-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-$inverse-tab-item-color: $inverse-global-muted-color !default;
-$inverse-tab-item-hover-color: $inverse-global-color !default;
-$inverse-tab-item-active-color: $inverse-global-emphasis-color !default;
-$inverse-tab-item-disabled-color: $inverse-global-muted-color !default;
-
-
-
-// @mixin hook-inverse-tab(){}
-// @mixin hook-inverse-tab-item(){}
-// @mixin hook-inverse-tab-item-hover(){}
-// @mixin hook-inverse-tab-item-active(){}
-// @mixin hook-inverse-tab-item-disabled(){}
\ No newline at end of file
diff --git a/_sass/uikit/components/table.scss b/_sass/uikit/components/table.scss
deleted file mode 100644
index 313d218b23..0000000000
--- a/_sass/uikit/components/table.scss
+++ /dev/null
@@ -1,316 +0,0 @@
-// Name: Table
-// Description: Styles for tables
-//
-// Component: `uk-table`
-//
-// Modifiers: `uk-table-middle`
-// `uk-table-divider`
-// `uk-table-striped`
-// `uk-table-hover`
-// `uk-table-small`
-// `uk-table-justify`
-// `uk-table-shrink`
-// `uk-table-expand`
-// `uk-table-link`
-// `uk-table-responsive`
-//
-// States: `uk-active`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$table-margin-vertical: $global-margin !default;
-
-$table-cell-padding-vertical: 16px !default;
-$table-cell-padding-horizontal: 12px !default;
-
-$table-header-cell-font-size: $global-font-size !default;
-$table-header-cell-font-weight: bold !default;
-$table-header-cell-color: $global-color !default;
-
-$table-footer-font-size: $global-small-font-size !default;
-
-$table-caption-font-size: $global-small-font-size !default;
-$table-caption-color: $global-muted-color !default;
-
-$table-row-active-background: #ffd !default;
-
-$table-divider-border-width: $global-border-width !default;
-$table-divider-border: $global-border !default;
-
-$table-striped-row-background: $global-muted-background !default;
-
-$table-hover-row-background: $table-row-active-background !default;
-
-$table-small-cell-padding-vertical: 10px !default;
-$table-small-cell-padding-horizontal: 12px !default;
-
-$table-large-cell-padding-vertical: 22px !default;
-$table-large-cell-padding-horizontal: 12px !default;
-
-$table-expand-min-width: 150px !default;
-
-
-/* ========================================================================
- Component: Table
- ========================================================================== */
-
-/*
- * 1. Remove most spacing between table cells.
- * 2. Behave like a block element
- * 3. Style
- */
-
-.uk-table {
- /* 1 */
- border-collapse: collapse;
- border-spacing: 0;
- /* 2 */
- width: 100%;
- /* 3 */
- margin-bottom: $table-margin-vertical;
- @if(mixin-exists(hook-table)) {@include hook-table();}
-}
-
-/* Add margin if adjacent element */
-* + .uk-table { margin-top: $table-margin-vertical; }
-
-
-/* Header cell
- ========================================================================== */
-
-/*
- * 1. Style
- */
-
-.uk-table th {
- padding: $table-cell-padding-vertical $table-cell-padding-horizontal;
- text-align: left;
- vertical-align: bottom;
- /* 1 */
- font-size: $table-header-cell-font-size;
- font-weight: $table-header-cell-font-weight;
- color: $table-header-cell-color;
- @if(mixin-exists(hook-table-header-cell)) {@include hook-table-header-cell();}
-}
-
-
-/* Cell
- ========================================================================== */
-
-.uk-table td {
- padding: $table-cell-padding-vertical $table-cell-padding-horizontal;
- vertical-align: top;
- @if(mixin-exists(hook-table-cell)) {@include hook-table-cell();}
-}
-
-/*
- * Remove margin from the last-child
- */
-
-.uk-table td > :last-child { margin-bottom: 0; }
-
-
-/* Footer
- ========================================================================== */
-
-.uk-table tfoot {
- font-size: $table-footer-font-size;
- @if(mixin-exists(hook-table-footer)) {@include hook-table-footer();}
-}
-
-
-/* Caption
- ========================================================================== */
-
-.uk-table caption {
- font-size: $table-caption-font-size;
- text-align: left;
- color: $table-caption-color;
- @if(mixin-exists(hook-table-caption)) {@include hook-table-caption();}
-}
-
-
-/* Row
- ========================================================================== */
-
-.uk-table > tr.uk-active,
-.uk-table tbody tr.uk-active {
- background: $table-row-active-background;
- @if(mixin-exists(hook-table-row-active)) {@include hook-table-row-active();}
-}
-
-
-/* Alignment modifier
- ========================================================================== */
-
-.uk-table-middle,
-.uk-table-middle td { vertical-align: middle !important; }
-
-
-/* Style modifiers
- ========================================================================== */
-
-/*
- * Divider
- */
-
-.uk-table-divider > tr:not(:first-child),
-.uk-table-divider > :not(:first-child) > tr,
-.uk-table-divider > :first-child > tr:not(:first-child) {
- border-top: $table-divider-border-width solid $table-divider-border;
- @if(mixin-exists(hook-table-divider)) {@include hook-table-divider();}
-}
-
-/*
- * Striped
- */
-
-.uk-table-striped > tr:nth-of-type(odd),
-.uk-table-striped tbody tr:nth-of-type(odd) {
- background: $table-striped-row-background;
- @if(mixin-exists(hook-table-striped)) {@include hook-table-striped();}
-}
-
-/*
- * Hover
- */
-
-.uk-table-hover > tr:hover,
-.uk-table-hover tbody tr:hover {
- background: $table-hover-row-background;
- @if(mixin-exists(hook-table-hover)) {@include hook-table-hover();}
-}
-
-
-/* Size modifier
- ========================================================================== */
-
-.uk-table-small th,
-.uk-table-small td {
- padding: $table-small-cell-padding-vertical $table-small-cell-padding-horizontal;
- @if(mixin-exists(hook-table-small)) {@include hook-table-small();}
-}
-
-.uk-table-large th,
-.uk-table-large td {
- padding: $table-large-cell-padding-vertical $table-large-cell-padding-horizontal;
- @if(mixin-exists(hook-table-large)) {@include hook-table-large();}
-}
-
-
-/* Justify modifier
- ========================================================================== */
-
-.uk-table-justify th:first-child,
-.uk-table-justify td:first-child { padding-left: 0; }
-
-.uk-table-justify th:last-child,
-.uk-table-justify td:last-child { padding-right: 0; }
-
-
-/* Cell size modifier
- ========================================================================== */
-
-.uk-table-shrink { width: 1px; }
-.uk-table-expand { min-width: $table-expand-min-width; }
-
-
-/* Cell link modifier
- ========================================================================== */
-
-/*
- * Does not work with `uk-table-justify` at the moment
- */
-
-.uk-table-link { padding: 0 !important; }
-
-.uk-table-link > a {
- display: block;
- padding: $table-cell-padding-vertical $table-cell-padding-horizontal;
-}
-
-.uk-table-small .uk-table-link > a { padding: $table-small-cell-padding-vertical $table-small-cell-padding-horizontal; }
-
-
-/* Responsive table
- ========================================================================== */
-
-
-/* Phone landscape and smaller */
-@media (max-width: $breakpoint-small-max) {
-
- .uk-table-responsive,
- .uk-table-responsive tbody,
- .uk-table-responsive th,
- .uk-table-responsive td,
- .uk-table-responsive tr { display: block; }
-
- .uk-table-responsive thead { display: none; }
-
- .uk-table-responsive th,
- .uk-table-responsive td {
- width: auto !important;
- max-width: none !important;
- min-width: 0 !important;
- overflow: visible !important;
- white-space: normal !important;
- }
-
- .uk-table-responsive th:not(:first-child):not(.uk-table-link),
- .uk-table-responsive td:not(:first-child):not(.uk-table-link),
- .uk-table-responsive .uk-table-link:not(:first-child) > a { padding-top: round($table-cell-padding-vertical / 3) !important; }
-
- .uk-table-responsive th:not(:last-child):not(.uk-table-link),
- .uk-table-responsive td:not(:last-child):not(.uk-table-link),
- .uk-table-responsive .uk-table-link:not(:last-child) > a { padding-bottom: round($table-cell-padding-vertical / 3) !important; }
-
- .uk-table-justify.uk-table-responsive th,
- .uk-table-justify.uk-table-responsive td {
- padding-left: 0;
- padding-right: 0;
- }
-
-}
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-table-misc)) {@include hook-table-misc();}
-
-// @mixin hook-table(){}
-// @mixin hook-table-header-cell(){}
-// @mixin hook-table-cell(){}
-// @mixin hook-table-footer(){}
-// @mixin hook-table-caption(){}
-// @mixin hook-table-row-active(){}
-// @mixin hook-table-divider(){}
-// @mixin hook-table-striped(){}
-// @mixin hook-table-hover(){}
-// @mixin hook-table-small(){}
-// @mixin hook-table-large(){}
-// @mixin hook-table-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-$inverse-table-header-cell-color: $inverse-global-color !default;
-$inverse-table-caption-color: $inverse-global-muted-color !default;
-$inverse-table-row-active-background: fade-out($inverse-global-muted-background, 0.02) !default;
-$inverse-table-divider-border: $inverse-global-border !default;
-$inverse-table-striped-row-background: $inverse-global-muted-background !default;
-$inverse-table-hover-row-background: $inverse-table-row-active-background !default;
-
-
-
-// @mixin hook-inverse-table-header-cell(){}
-// @mixin hook-inverse-table-caption(){}
-// @mixin hook-inverse-table-row-active(){}
-// @mixin hook-inverse-table-divider(){}
-// @mixin hook-inverse-table-striped(){}
-// @mixin hook-inverse-table-hover(){}
\ No newline at end of file
diff --git a/_sass/uikit/components/text.scss b/_sass/uikit/components/text.scss
deleted file mode 100644
index c60915b84b..0000000000
--- a/_sass/uikit/components/text.scss
+++ /dev/null
@@ -1,262 +0,0 @@
-// Name: Text
-// Description: Utilities for text
-//
-// Component: `uk-text-*`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$text-lead-font-size: $global-large-font-size !default;
-$text-lead-line-height: 1.5 !default;
-$text-lead-color: $global-emphasis-color !default;
-
-$text-meta-font-size: $global-small-font-size !default;
-$text-meta-line-height: 1.4 !default;
-$text-meta-color: $global-muted-color !default;
-
-$text-small-font-size: $global-small-font-size !default;
-$text-small-line-height: 1.5 !default;
-
-$text-large-font-size: $global-large-font-size !default;
-$text-large-line-height: 1.5 !default;
-
-$text-bold-font-weight: bolder !default;
-
-$text-muted-color: $global-muted-color !default;
-$text-primary-color: $global-primary-background !default;
-$text-success-color: $global-success-background !default;
-$text-warning-color: $global-warning-background !default;
-$text-danger-color: $global-danger-background !default;
-
-$text-background-color: $global-primary-background !default;
-
-
-/* ========================================================================
- Component: Text
- ========================================================================== */
-
-
-/* Style modifiers
- ========================================================================== */
-
-.uk-text-lead {
- font-size: $text-lead-font-size;
- line-height: $text-lead-line-height;
- color: $text-lead-color;
- @if(mixin-exists(hook-text-lead)) {@include hook-text-lead();}
-}
-
-.uk-text-meta {
- font-size: $text-meta-font-size;
- line-height: $text-meta-line-height;
- color: $text-meta-color;
- @if(mixin-exists(hook-text-meta)) {@include hook-text-meta();}
-}
-
-
-/* Size modifiers
- ========================================================================== */
-
-.uk-text-small {
- font-size: $text-small-font-size;
- line-height: $text-small-line-height;
- @if(mixin-exists(hook-text-small)) {@include hook-text-small();}
-}
-
-.uk-text-large {
- font-size: $text-large-font-size;
- line-height: $text-large-line-height;
- @if(mixin-exists(hook-text-large)) {@include hook-text-large();}
-}
-
-
-/* Weight modifier
- ========================================================================== */
-
-.uk-text-bold { font-weight: $text-bold-font-weight; }
-
-
-/* Transform modifier
- ========================================================================== */
-
-.uk-text-uppercase { text-transform: uppercase !important; }
-.uk-text-capitalize { text-transform: capitalize !important; }
-.uk-text-lowercase { text-transform: lowercase !important; }
-
-
-/* Color modifiers
- ========================================================================== */
-
-.uk-text-muted { color: $text-muted-color !important; }
-.uk-text-primary { color: $text-primary-color !important; }
-.uk-text-success { color: $text-success-color !important; }
-.uk-text-warning { color: $text-warning-color !important; }
-.uk-text-danger { color: $text-danger-color !important; }
-
-
-/* Background modifier
- ========================================================================== */
-
-/*
- * 1. The background clips to the foreground text. Works in Chrome, Firefox, Safari, Edge and Opera
- * Default color is set to transparent
- * 2. Container fits the text
- * 3. Fallback color for IE11
- */
-
-.uk-text-background {
- /* 1 */
- -webkit-background-clip: text;
- -webkit-text-fill-color: transparent;
- /* 2 */
- display: inline-block;
- /* 3 */
- color: $text-background-color !important;
-}
-
-@supports (-webkit-background-clip: text) {
-
- .uk-text-background {
- background-color: $text-background-color;
- @if(mixin-exists(hook-text-background)) {@include hook-text-background();}
- }
-
-}
-
-
-/* Alignment modifiers
- ========================================================================== */
-
-.uk-text-left { text-align: left !important; }
-.uk-text-right { text-align: right !important; }
-.uk-text-center { text-align: center !important; }
-.uk-text-justify { text-align: justify !important; }
-
-/* Phone landscape and bigger */
-@media (min-width: $breakpoint-small) {
-
- .uk-text-left\@s { text-align: left !important; }
- .uk-text-right\@s { text-align: right !important; }
- .uk-text-center\@s { text-align: center !important; }
-
-}
-
-/* Tablet landscape and bigger */
-@media (min-width: $breakpoint-medium) {
-
- .uk-text-left\@m { text-align: left !important; }
- .uk-text-right\@m { text-align: right !important; }
- .uk-text-center\@m { text-align: center !important; }
-
-}
-
-/* Desktop and bigger */
-@media (min-width: $breakpoint-large) {
-
- .uk-text-left\@l { text-align: left !important; }
- .uk-text-right\@l { text-align: right !important; }
- .uk-text-center\@l { text-align: center !important; }
-
-}
-
-/* Large screen and bigger */
-@media (min-width: $breakpoint-xlarge) {
-
- .uk-text-left\@xl { text-align: left !important; }
- .uk-text-right\@xl { text-align: right !important; }
- .uk-text-center\@xl { text-align: center !important; }
-
-}
-
-/*
- * Vertical
- */
-
-.uk-text-top { vertical-align: top !important; }
-.uk-text-middle { vertical-align: middle !important; }
-.uk-text-bottom { vertical-align: bottom !important; }
-.uk-text-baseline { vertical-align: baseline !important; }
-
-
-/* Wrap modifiers
- ========================================================================== */
-
-/*
- * Prevent text from wrapping onto multiple lines
- */
-
-.uk-text-nowrap { white-space: nowrap; }
-
-/*
- * 1. Make sure a max-width is set after which truncation can occur
- * 2. Prevent text from wrapping onto multiple lines, and truncate with an ellipsis
- * 3. Fix for table cells
- */
-
-.uk-text-truncate {
- /* 1 */
- max-width: 100%;
- /* 2 */
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-/* 2 */
-th.uk-text-truncate,
-td.uk-text-truncate { max-width: 0; }
-
-
-/*
- * 1. Wrap long words onto the next line and break them if they are too long to fit
- * 2. Legacy `word-wrap` as fallback for `overflow-wrap`
- * 3. Add a hyphen where the word breaks
- * 4. Fix `overflow-wrap` which doesn't work with table cells in Chrome, Opera, IE11 and Edge
- * Must use `break-all` to support IE11 and Edge
- */
-
-.uk-text-break {
- /* 1 */
- overflow-wrap: break-word;
- /* 2 */
- word-wrap: break-word;
- /* 3 */
- -ms-hyphens: auto;
- -webkit-hyphens: auto;
- hyphens: auto;
-}
-
-/* 4 */
-th.uk-text-break,
-td.uk-text-break { word-break: break-all; }
-
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-text-misc)) {@include hook-text-misc();}
-
-// @mixin hook-text-lead(){}
-// @mixin hook-text-meta(){}
-// @mixin hook-text-small(){}
-// @mixin hook-text-large(){}
-// @mixin hook-text-background(){}
-// @mixin hook-text-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-$inverse-text-lead-color: $inverse-global-color !default;
-$inverse-text-meta-color: $inverse-global-muted-color !default;
-$inverse-text-muted-color: $inverse-global-muted-color !default;
-$inverse-text-primary-color: $inverse-global-color !default;
-
-
-
-// @mixin hook-inverse-text-lead(){}
-// @mixin hook-inverse-text-meta(){}
diff --git a/_sass/uikit/components/thumbnav.scss b/_sass/uikit/components/thumbnav.scss
deleted file mode 100644
index ee551f99b6..0000000000
--- a/_sass/uikit/components/thumbnav.scss
+++ /dev/null
@@ -1,123 +0,0 @@
-// Name: Thumbnav
-// Description: Component to create thumbnail navigations
-//
-// Component: `uk-thumbnav`
-//
-// Modifier: `uk-thumbnav-vertical`
-//
-// States: `uk-active`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$thumbnav-margin-horizontal: 15px !default;
-$thumbnav-margin-vertical: $thumbnav-margin-horizontal !default;
-
-
-/* ========================================================================
- Component: Thumbnav
- ========================================================================== */
-
-/*
- * 1. Allow items to wrap into the next line
- * 2. Reset list
- * 3. Gutter
- */
-
-.uk-thumbnav {
- display: flex;
- /* 1 */
- flex-wrap: wrap;
- /* 2 */
- margin: 0;
- padding: 0;
- list-style: none;
- /* 3 */
- margin-left: (-$thumbnav-margin-horizontal);
- @if(mixin-exists(hook-thumbnav)) {@include hook-thumbnav();}
-}
-
-/*
- * 1. Space is allocated solely based on content dimensions: 0 0 auto
- * 2. Gutter
- */
-
-.uk-thumbnav > * {
- /* 1 */
- flex: none;
- /* 2 */
- padding-left: $thumbnav-margin-horizontal;
-}
-
-
-/* Items
- ========================================================================== */
-
-/*
- * Items
- */
-
-.uk-thumbnav > * > * {
- display: inline-block;
- @if(mixin-exists(hook-thumbnav-item)) {@include hook-thumbnav-item();}
-}
-
-/* Hover + Focus */
-.uk-thumbnav > * > :hover,
-.uk-thumbnav > * > :focus {
- outline: none;
- @if(mixin-exists(hook-thumbnav-item-hover)) {@include hook-thumbnav-item-hover();}
-}
-
-/* Active */
-.uk-thumbnav > .uk-active > * {
- @if(mixin-exists(hook-thumbnav-item-active)) {@include hook-thumbnav-item-active();}
-}
-
-
-/* Modifier: 'uk-thumbnav-vertical'
- ========================================================================== */
-
-/*
- * 1. Change direction
- * 2. Gutter
- */
-
-.uk-thumbnav-vertical {
- /* 1 */
- flex-direction: column;
- /* 2 */
- margin-left: 0;
- margin-top: (-$thumbnav-margin-vertical);
-}
-
-/* 2 */
-.uk-thumbnav-vertical > * {
- padding-left: 0;
- padding-top: $thumbnav-margin-vertical;
-}
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-thumbnav-misc)) {@include hook-thumbnav-misc();}
-
-// @mixin hook-thumbnav(){}
-// @mixin hook-thumbnav-item(){}
-// @mixin hook-thumbnav-item-hover(){}
-// @mixin hook-thumbnav-item-active(){}
-// @mixin hook-thumbnav-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-
-
-// @mixin hook-inverse-thumbnav-item(){}
-// @mixin hook-inverse-thumbnav-item-hover(){}
-// @mixin hook-inverse-thumbnav-item-active(){}
\ No newline at end of file
diff --git a/_sass/uikit/components/tile.scss b/_sass/uikit/components/tile.scss
deleted file mode 100644
index 3a364bfb2a..0000000000
--- a/_sass/uikit/components/tile.scss
+++ /dev/null
@@ -1,224 +0,0 @@
-// Name: Tile
-// Description: Component to create tiled boxes
-//
-// Component: `uk-tile`
-//
-// Modifiers: `uk-tile-xsmall`
-// `uk-tile-small`
-// `uk-tile-large`
-// `uk-tile-xlarge`
-// `uk-tile-default`
-// `uk-tile-muted`
-// `uk-tile-primary`
-// `uk-tile-secondary`
-//
-// States: `uk-preserve-color`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$tile-padding-horizontal: 15px !default;
-$tile-padding-horizontal-s: $global-gutter !default;
-$tile-padding-horizontal-m: $global-medium-gutter !default;
-$tile-padding-vertical: $global-medium-margin !default;
-$tile-padding-vertical-m: $global-large-margin !default;
-
-$tile-xsmall-padding-vertical: $global-margin !default;
-
-$tile-small-padding-vertical: $global-medium-margin !default;
-
-$tile-large-padding-vertical: $global-large-margin !default;
-$tile-large-padding-vertical-m: $global-xlarge-margin !default;
-
-$tile-xlarge-padding-vertical: $global-xlarge-margin !default;
-$tile-xlarge-padding-vertical-m: ($global-large-margin + $global-xlarge-margin) !default;
-
-$tile-default-background: $global-background !default;
-
-$tile-muted-background: $global-muted-background !default;
-
-$tile-primary-background: $global-primary-background !default;
-$tile-primary-color-mode: light !default;
-
-$tile-secondary-background: $global-secondary-background !default;
-$tile-secondary-color-mode: light !default;
-
-
-/* ========================================================================
- Component: Tile
- ========================================================================== */
-
-.uk-tile {
- position: relative;
- box-sizing: border-box;
- padding-left: $tile-padding-horizontal;
- padding-right: $tile-padding-horizontal;
- padding-top: $tile-padding-vertical;
- padding-bottom: $tile-padding-vertical;
- @if(mixin-exists(hook-tile)) {@include hook-tile();}
-}
-
-/* Phone landscape and bigger */
-@media (min-width: $breakpoint-small) {
-
- .uk-tile {
- padding-left: $tile-padding-horizontal-s;
- padding-right: $tile-padding-horizontal-s;
- }
-
-}
-
-/* Tablet landscape and bigger */
-@media (min-width: $breakpoint-medium) {
-
- .uk-tile {
- padding-left: $tile-padding-horizontal-m;
- padding-right: $tile-padding-horizontal-m;
- padding-top: $tile-padding-vertical-m;
- padding-bottom: $tile-padding-vertical-m;
- }
-
-}
-
-/*
- * Micro clearfix
- */
-
-.uk-tile::before,
-.uk-tile::after {
- content: "";
- display: table;
-}
-
-.uk-tile::after { clear: both; }
-
-/*
- * Remove margin from the last-child
- */
-
-.uk-tile > :last-child { margin-bottom: 0; }
-
-
-/* Size modifiers
- ========================================================================== */
-
-/*
- * XSmall
- */
-
-.uk-tile-xsmall {
- padding-top: $tile-xsmall-padding-vertical;
- padding-bottom: $tile-xsmall-padding-vertical;
-}
-
-/*
- * Small
- */
-
-.uk-tile-small {
- padding-top: $tile-small-padding-vertical;
- padding-bottom: $tile-small-padding-vertical;
-}
-
-/*
- * Large
- */
-
-.uk-tile-large {
- padding-top: $tile-large-padding-vertical;
- padding-bottom: $tile-large-padding-vertical;
-}
-
-/* Tablet landscape and bigger */
-@media (min-width: $breakpoint-medium) {
-
- .uk-tile-large {
- padding-top: $tile-large-padding-vertical-m;
- padding-bottom: $tile-large-padding-vertical-m;
- }
-
-}
-
-
-/*
- * XLarge
- */
-
-.uk-tile-xlarge {
- padding-top: $tile-xlarge-padding-vertical;
- padding-bottom: $tile-xlarge-padding-vertical;
-}
-
-/* Tablet landscape and bigger */
-@media (min-width: $breakpoint-medium) {
-
- .uk-tile-xlarge {
- padding-top: $tile-xlarge-padding-vertical-m;
- padding-bottom: $tile-xlarge-padding-vertical-m;
- }
-
-}
-
-
-/* Style modifiers
- ========================================================================== */
-
-/*
- * Default
- */
-
-.uk-tile-default {
- background: $tile-default-background;
- @if(mixin-exists(hook-tile-default)) {@include hook-tile-default();}
-}
-
-/*
- * Muted
- */
-
-.uk-tile-muted {
- background: $tile-muted-background;
- @if(mixin-exists(hook-tile-muted)) {@include hook-tile-muted();}
-}
-
-/*
- * Primary
- */
-
-.uk-tile-primary {
- background: $tile-primary-background;
- @if(mixin-exists(hook-tile-primary)) {@include hook-tile-primary();}
-}
-
-// Color Mode
-@if ( $tile-primary-color-mode == light ) { .uk-tile-primary:not(.uk-preserve-color) { @extend .uk-light !optional;} }
-@if ( $tile-primary-color-mode == dark ) { .uk-tile-primary:not(.uk-preserve-color) { @extend .uk-dark !optional;} }
-
-/*
- * Secondary
- */
-
-.uk-tile-secondary {
- background: $tile-secondary-background;
- @if(mixin-exists(hook-tile-secondary)) {@include hook-tile-secondary();}
-}
-
-// Color Mode
-@if ( $tile-secondary-color-mode == light ) { .uk-tile-secondary:not(.uk-preserve-color) { @extend .uk-light !optional;} }
-@if ( $tile-secondary-color-mode == dark ) { .uk-tile-secondary:not(.uk-preserve-color) { @extend .uk-dark !optional;} }
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-tile-misc)) {@include hook-tile-misc();}
-
-// @mixin hook-tile(){}
-// @mixin hook-tile-default(){}
-// @mixin hook-tile-muted(){}
-// @mixin hook-tile-primary(){}
-// @mixin hook-tile-secondary(){}
-// @mixin hook-tile-misc(){}
diff --git a/_sass/uikit/components/tooltip.scss b/_sass/uikit/components/tooltip.scss
deleted file mode 100644
index 1f8e8c88f6..0000000000
--- a/_sass/uikit/components/tooltip.scss
+++ /dev/null
@@ -1,84 +0,0 @@
-// Name: Tooltip
-// Description: Component to create tooltips
-//
-// Component: `uk-tooltip`
-//
-// Modifiers `uk-tooltip-top`
-// `uk-tooltip-top-left`
-// `uk-tooltip-top-right`
-// `uk-tooltip-bottom`
-// `uk-tooltip-bottom-left`
-// `uk-tooltip-bottom-right`
-// `uk-tooltip-left`
-// `uk-tooltip-right`
-//
-// States: `uk-active`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$tooltip-z-index: $global-z-index + 30 !default;
-$tooltip-max-width: 200px !default;
-$tooltip-padding-vertical: 3px !default;
-$tooltip-padding-horizontal: 6px !default;
-$tooltip-background: #666 !default;
-$tooltip-border-radius: 2px !default;
-$tooltip-color: $global-inverse-color !default;
-$tooltip-font-size: 12px !default;
-
-$tooltip-margin: 10px !default;
-
-
-/* ========================================================================
- Component: Tooltip
- ========================================================================== */
-
-/*
- * 1. Hide by default
- * 2. Position
- * 3. Dimensions
- * 4. Style
- */
-
-.uk-tooltip {
- /* 1 */
- display: none;
- /* 2 */
- position: absolute;
- z-index: $tooltip-z-index;
- /* 3 */
- box-sizing: border-box;
- max-width: $tooltip-max-width;
- padding: $tooltip-padding-vertical $tooltip-padding-horizontal;
- /* 4 */
- background: $tooltip-background;
- border-radius: $tooltip-border-radius;
- color: $tooltip-color;
- font-size: $tooltip-font-size;
- @if(mixin-exists(hook-tooltip)) {@include hook-tooltip();}
-}
-
-/* Show */
-.uk-tooltip.uk-active { display: block; }
-
-
-/* Direction / Alignment modifiers
- ========================================================================== */
-
-/* Direction */
-[class*='uk-tooltip-top'] { margin-top: (-$tooltip-margin); }
-[class*='uk-tooltip-bottom'] { margin-top: $tooltip-margin; }
-[class*='uk-tooltip-left'] { margin-left: (-$tooltip-margin); }
-[class*='uk-tooltip-right'] { margin-left: $tooltip-margin; }
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-tooltip-misc)) {@include hook-tooltip-misc();}
-
-// @mixin hook-tooltip(){}
-// @mixin hook-tooltip-misc(){}
diff --git a/_sass/uikit/components/totop.scss b/_sass/uikit/components/totop.scss
deleted file mode 100644
index 4b8aa1d88f..0000000000
--- a/_sass/uikit/components/totop.scss
+++ /dev/null
@@ -1,71 +0,0 @@
-// Name: Totop
-// Description: Component to create an icon to scroll back to top
-//
-// Component: `uk-totop`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$totop-padding: 5px !default;
-$totop-color: $global-muted-color !default;
-
-$totop-hover-color: $global-color !default;
-
-$totop-active-color: $global-emphasis-color !default;
-
-
-/* ========================================================================
- Component: Totop
- ========================================================================== */
-
-/*
- * Addopts `uk-icon`
- */
-
-.uk-totop {
- padding: $totop-padding;
- color: $totop-color;
- @if(mixin-exists(hook-totop)) {@include hook-totop();}
-}
-
-/* Hover + Focus */
-.uk-totop:hover,
-.uk-totop:focus {
- color: $totop-hover-color;
- outline: none;
- @if(mixin-exists(hook-totop-hover)) {@include hook-totop-hover();}
-}
-
-/* OnClick */
-.uk-totop:active {
- color: $totop-active-color;
- @if(mixin-exists(hook-totop-active)) {@include hook-totop-active();}
-}
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-totop-misc)) {@include hook-totop-misc();}
-
-// @mixin hook-totop(){}
-// @mixin hook-totop-hover(){}
-// @mixin hook-totop-active(){}
-// @mixin hook-totop-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-$inverse-totop-color: $inverse-global-muted-color !default;
-$inverse-totop-hover-color: $inverse-global-color !default;
-$inverse-totop-active-color: $inverse-global-emphasis-color !default;
-
-
-
-// @mixin hook-inverse-totop(){}
-// @mixin hook-inverse-totop-hover(){}
-// @mixin hook-inverse-totop-active(){}
diff --git a/_sass/uikit/components/transition.scss b/_sass/uikit/components/transition.scss
deleted file mode 100644
index c99927433b..0000000000
--- a/_sass/uikit/components/transition.scss
+++ /dev/null
@@ -1,145 +0,0 @@
-// Name: Transition
-// Description: Utilities for transitions
-//
-// Component: `uk-transition-*`
-//
-// Modifiers: `uk-transition-fade`
-// `uk-transition-scale-up`
-// `uk-transition-scale-down`
-// `uk-transition-slide-top-*`
-// `uk-transition-slide-bottom-*`
-// `uk-transition-slide-left-*`
-// `uk-transition-slide-right-*`
-// `uk-transition-opaque`
-// `uk-transition-slow`
-//
-// Sub-objects: `uk-transition-toggle`,
-// `uk-transition-active`
-//
-// States: `uk-hover`
-// `uk-active`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$transition-duration: 0.3s !default;
-
-$transition-scale: 1.1 !default;
-
-$transition-slide-small-translate: 10px !default;
-$transition-slide-medium-translate: 50px !default;
-
-$transition-slow-duration: 0.7s !default;
-
-
-/* ========================================================================
- Component: Transition
- ========================================================================== */
-
-/*
- * Using multiple selectors to exclude `uk-transition-toggle`
- * Note: Transitions don't work with `uk-postion-center-*` classes because they also use `transform`
- * Just put the transition in an extra `div`
- */
-
-.uk-transition-fade,
-[class*='uk-transition-scale'],
-[class*='uk-transition-slide'] {
- transition: $transition-duration ease-out;
- transition-property: opacity, transform, filter;
-}
-
-.uk-transition-toggle:focus { outline: none; }
-
-/*
- * Fade
- */
-
-.uk-transition-fade { opacity: 0; }
-
-/* Show */
-.uk-transition-toggle:hover [class*='uk-transition-fade'],
-.uk-transition-toggle.uk-hover [class*='uk-transition-fade'],
-.uk-transition-toggle:focus [class*='uk-transition-fade'],
-.uk-transition-active.uk-active [class*='uk-transition-fade'] { opacity: 1; }
-
-/*
- * Scale
- * Note: Using `scale3d` for better image rendering
- */
-
-[class*='uk-transition-scale'] { opacity: 0; }
-
-.uk-transition-scale-up { transform: scale3d(1,1,1); }
-
-.uk-transition-scale-down { transform: scale3d($transition-scale,$transition-scale,1); }
-
-/* Show */
-.uk-transition-toggle:hover .uk-transition-scale-up,
-.uk-transition-toggle.uk-hover .uk-transition-scale-up,
-.uk-transition-toggle:focus .uk-transition-scale-up,
-.uk-transition-active.uk-active .uk-transition-scale-up {
- opacity: 1;
- transform: scale3d($transition-scale,$transition-scale,1);
-}
-
-.uk-transition-toggle:hover .uk-transition-scale-down,
-.uk-transition-toggle.uk-hover .uk-transition-scale-down,
-.uk-transition-toggle:focus .uk-transition-scale-down,
-.uk-transition-active.uk-active .uk-transition-scale-down {
- opacity: 1;
- transform: scale3d(1,1,1);
-}
-
-/*
- * Slide
- */
-
-[class*='uk-transition-slide'] { opacity: 0; }
-
-.uk-transition-slide-top { transform: translateY(-100%); }
-.uk-transition-slide-bottom { transform: translateY(100%); }
-.uk-transition-slide-left { transform: translateX(-100%); }
-.uk-transition-slide-right { transform: translateX(100%); }
-
-.uk-transition-slide-top-small { transform: translateY(-$transition-slide-small-translate); }
-.uk-transition-slide-bottom-small { transform: translateY($transition-slide-small-translate); }
-.uk-transition-slide-left-small { transform: translateX(-$transition-slide-small-translate); }
-.uk-transition-slide-right-small { transform: translateX($transition-slide-small-translate); }
-
-.uk-transition-slide-top-medium { transform: translateY(-$transition-slide-medium-translate); }
-.uk-transition-slide-bottom-medium { transform: translateY($transition-slide-medium-translate); }
-.uk-transition-slide-left-medium { transform: translateX(-$transition-slide-medium-translate); }
-.uk-transition-slide-right-medium { transform: translateX($transition-slide-medium-translate); }
-
-/* Show */
-.uk-transition-toggle:hover [class*='uk-transition-slide'],
-.uk-transition-toggle.uk-hover [class*='uk-transition-slide'],
-.uk-transition-toggle:focus [class*='uk-transition-slide'],
-.uk-transition-active.uk-active [class*='uk-transition-slide'] {
- opacity: 1;
- transform: translateX(0) translateY(0);
-}
-
-
-/* Opacity modifier
-========================================================================== */
-
-.uk-transition-opaque { opacity: 1; }
-
-
-/* Duration modifiers
-========================================================================== */
-
-.uk-transition-slow { transition-duration: $transition-slow-duration; }
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-transition-misc)) {@include hook-transition-misc();}
-
-// @mixin hook-transition-misc(){}
diff --git a/_sass/uikit/components/utility.scss b/_sass/uikit/components/utility.scss
deleted file mode 100644
index 2ac1777683..0000000000
--- a/_sass/uikit/components/utility.scss
+++ /dev/null
@@ -1,570 +0,0 @@
-// Name: Utility
-// Description: Utilities collection
-//
-// Component: `uk-panel-*`
-// `uk-clearfix`
-// `uk-float-*`
-// `uk-overflow-*`
-// `uk-resize-*`
-// `uk-display-*`
-// `uk-inline-*`
-// `uk-height-*`
-// `uk-responsive-*`
-// `uk-preserve-width`
-// `uk-border-*`
-// `uk-box-shadow-*`
-// `uk-box-shadow-bottom`
-// `uk-dropcap`
-// `uk-leader`
-// `uk-logo`
-// `uk-svg`
-// `uk-blend-*`
-// `uk-transform-*`
-// `uk-transform-origin-*`
-//
-// States: `uk-disabled`
-// `uk-drag`
-// `uk-dragover`
-// `uk-preserve`
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$panel-scrollable-height: 170px !default;
-$panel-scrollable-padding: 10px !default;
-$panel-scrollable-border-width: $global-border-width !default;
-$panel-scrollable-border: $global-border !default;
-
-$height-small-height: 150px !default;
-$height-medium-height: 300px !default;
-$height-large-height: 450px !default;
-
-$border-rounded-border-radius: 5px !default;
-
-$box-shadow-duration: 0.1s !default;
-
-$box-shadow-bottom-height: 30px !default;
-$box-shadow-bottom-border-radius: 100% !default;
-$box-shadow-bottom-background: #444 !default;
-$box-shadow-bottom-blur: 20px !default;
-
-$dropcap-margin-right: 10px !default;
-$dropcap-font-size: (($global-line-height * 3) * 1em) !default;
-
-$leader-fill-content: '.' !default;
-$leader-fill-margin-left: $global-small-gutter !default;
-
-$logo-font-size: $global-large-font-size !default;
-$logo-font-family: $global-font-family !default;
-$logo-color: $global-color !default;
-$logo-hover-color: $global-color !default;
-
-$dragover-box-shadow: 0 0 20px rgba(100,100,100,0.3) !default;
-
-
-/* ========================================================================
- Component: Utility
- ========================================================================== */
-
-
-/* Panel
- ========================================================================== */
-
-.uk-panel {
- position: relative;
- box-sizing: border-box;
-}
-
-/*
- * Micro clearfix
- */
-
-.uk-panel::before,
-.uk-panel::after {
- content: "";
- display: table;
-}
-
-.uk-panel::after { clear: both; }
-
-/*
- * Remove margin from the last-child
- */
-
-.uk-panel > :last-child { margin-bottom: 0; }
-
-
-/*
- * Scrollable
- */
-
-.uk-panel-scrollable {
- height: $panel-scrollable-height;
- padding: $panel-scrollable-padding;
- border: $panel-scrollable-border-width solid $panel-scrollable-border;
- overflow: auto;
- -webkit-overflow-scrolling: touch;
- resize: both;
- @if(mixin-exists(hook-panel-scrollable)) {@include hook-panel-scrollable();}
-}
-
-
-/* Clearfix
- ========================================================================== */
-
-/*
- * 1. `table-cell` is used with `::before` because `table` creates a 1px gap when it becomes a flex item, only in Webkit
- * 2. `table` is used again with `::after` because `clear` only works with block elements.
- * Note: `display: block` with `overflow: hidden` is currently not working in the latest Safari
- */
-
-/* 1 */
-.uk-clearfix::before {
- content: "";
- display: table-cell;
-}
-
-/* 2 */
-.uk-clearfix::after {
- content: "";
- display: table;
- clear: both;
-}
-
-
-/* Float
- ========================================================================== */
-
-/*
- * 1. Prevent content overflow
- */
-
-.uk-float-left { float: left; }
-.uk-float-right { float: right; }
-
-/* 1 */
-[class*='uk-float-'] { max-width: 100%; }
-
-
-/* Overfow
- ========================================================================== */
-
-.uk-overflow-hidden { overflow: hidden; }
-
-/*
- * Enable scrollbars if content is clipped
- * Note: Firefox ignores `padding-bottom` for the scrollable overflow https://bugzilla.mozilla.org/show_bug.cgi?id=748518
- */
-
-.uk-overflow-auto {
- overflow: auto;
- -webkit-overflow-scrolling: touch;
-}
-
-.uk-overflow-auto > :last-child { margin-bottom: 0; }
-
-
-/* Resize
- ========================================================================== */
-
-.uk-resize { resize: both; }
-.uk-resize-vertical { resize: vertical; }
-
-
-/* Display
- ========================================================================== */
-
-.uk-display-block { display: block !important; }
-.uk-display-inline { display: inline !important; }
-.uk-display-inline-block { display: inline-block !important; }
-
-
-/* Inline
- ========================================================================== */
-
-/*
- * 1. Container fits its content
- * 2. Create position context
- * 3. Prevent content overflow
- * 4. Behave like most inline-block elements
- * 5. Force hardware acceleration without creating a new stacking context
- * to fix 1px glitch when combined with overlays and transitions in Webkit
- * 6. Clip child elements
- */
-
-[class*='uk-inline'] {
- /* 1 */
- display: inline-block;
- /* 2 */
- position: relative;
- /* 3 */
- max-width: 100%;
- /* 4 */
- vertical-align: middle;
- /* 5 */
- -webkit-backface-visibility: hidden;
-}
-
-.uk-inline-clip {
- /* 6 */
- overflow: hidden;
-}
-
-
-/* Height
- ========================================================================== */
-
-[class*='uk-height'] { box-sizing: border-box; }
-
-/*
- * Only works if parent element has a height set
- */
-
-.uk-height-1-1 { height: 100%; }
-
-/*
- * Useful to create image teasers
- */
-
-.uk-height-viewport { min-height: 100vh; }
-
-/*
- * Pixel
- * Useful for `overflow: auto`
- */
-
-.uk-height-small { height: $height-small-height; }
-.uk-height-medium { height: $height-medium-height; }
-.uk-height-large { height: $height-large-height; }
-
-.uk-height-max-small { max-height: $height-small-height; }
-.uk-height-max-medium { max-height: $height-medium-height; }
-.uk-height-max-large { max-height: $height-large-height; }
-
-
-/* Responsive objects
- ========================================================================== */
-
-/*
- * Preserve original dimensions
- * Because `img, `video`, `canvas` and `audio` are already responsive by default, see Base component
- */
-
-.uk-preserve-width,
-.uk-preserve-width audio,
-.uk-preserve-width canvas,
-.uk-preserve-width img,
-.uk-preserve-width svg,
-.uk-preserve-width video { max-width: none; }
-
-/*
- * Responsiveness
- * Corrects `max-width` and `max-height` behavior if padding and border are used
- */
-
-.uk-responsive-width,
-.uk-responsive-height { box-sizing: border-box; }
-
-/*
- * 1. Set a maximum width. `important` needed to override `uk-preserve-width img`
- * 2. Auto scale the height. Only needed if `height` attribute is present
- */
-
-.uk-responsive-width {
- /* 1 */
- max-width: 100% !important;
- /* 2 */
- height: auto;
-}
-
-/*
- * 1. Set a maximum height. Only works if the parent element has a fixed height
- * 2. Auto scale the width. Only needed if `width` attribute is present
- * 3. Reset max-width, which `img, `video`, `canvas` and `audio` already have by default
- */
-
-.uk-responsive-height {
- /* 1 */
- max-height: 100%;
- /* 2 */
- width: auto;
- /* 3 */
- max-width: none;
-}
-
-
-/* Border
- ========================================================================== */
-
-.uk-border-circle { border-radius: 50%; }
-.uk-border-rounded { border-radius: $border-rounded-border-radius; }
-
-/*
- * Fix `overflow: hidden` to be ignored with border-radius and CSS transforms in Webkit
- */
-
-.uk-inline-clip[class*='uk-border-'] { -webkit-transform: translateZ(0); }
-
-
-/* Box-shadow
- ========================================================================== */
-
-.uk-box-shadow-small { box-shadow: $global-small-box-shadow; }
-.uk-box-shadow-medium { box-shadow: $global-medium-box-shadow; }
-.uk-box-shadow-large { box-shadow: $global-large-box-shadow; }
-.uk-box-shadow-xlarge { box-shadow: $global-xlarge-box-shadow; }
-
-/*
- * Hover
- */
-
-[class*='uk-box-shadow-hover'] { transition: box-shadow $box-shadow-duration ease-in-out; }
-
-.uk-box-shadow-hover-small:hover { box-shadow: $global-small-box-shadow; }
-.uk-box-shadow-hover-medium:hover { box-shadow: $global-medium-box-shadow; }
-.uk-box-shadow-hover-large:hover { box-shadow: $global-large-box-shadow; }
-.uk-box-shadow-hover-xlarge:hover { box-shadow: $global-xlarge-box-shadow; }
-
-
-/* Box-shadow bottom
- ========================================================================== */
-
-/*
- * 1. Set position.
- * 2. Set style
- * 3. Blur doesn't work on pseudo elements with negative `z-index` in Edge.
- * Solved by using `before` and add position context to child elements.
- */
-
-@supports (filter: blur(0)) {
-
- .uk-box-shadow-bottom {
- display: inline-block;
- position: relative;
- max-width: 100%;
- vertical-align: middle;
- }
-
- .uk-box-shadow-bottom::before {
- content: '';
- /* 1 */
- position: absolute;
- bottom: (-$box-shadow-bottom-height);
- left: 0;
- right: 0;
- /* 2 */
- height: $box-shadow-bottom-height;
- border-radius: $box-shadow-bottom-border-radius;
- background: $box-shadow-bottom-background;
- filter: blur($box-shadow-bottom-blur);
- @if(mixin-exists(hook-box-shadow-bottom)) {@include hook-box-shadow-bottom();}
- }
-
- /* 3 */
- .uk-box-shadow-bottom > * { position: relative; }
-
-}
-
-
-/* Drop cap
- ========================================================================== */
-
-.uk-dropcap::first-letter,
-.uk-dropcap > p:first-of-type::first-letter {
- display: block;
- margin-right: $dropcap-margin-right;
- float: left;
- font-size: $dropcap-font-size;
- line-height: 1;
- @if(mixin-exists(hook-dropcap)) {@include hook-dropcap();}
-}
-
-
-/* Leader
- ========================================================================== */
-
-.uk-leader { overflow: hidden; }
-
-/*
- * 1. Place element in text flow
- * 2. Never break into a new line
- * 3. Get a string back with as many repeating characters to fill the container
- * 4. Prevent wrapping. Overflowing characters will be clipped by the container
- */
-
-.uk-leader-fill::after {
- /* 1 */
- display: inline-block;
- margin-left: $leader-fill-margin-left;
- /* 2 */
- width: 0;
- /* 3 */
- content: attr(data-fill);
- /* 4 */
- white-space: nowrap;
- @if(mixin-exists(hook-leader)) {@include hook-leader();}
-}
-
-/*
- * Hide if media does not match
- */
-
-.uk-leader-fill.uk-leader-hide::after { display: none; }
-
-/* Pass fill character to JS */
-.var-leader-fill:before { content: $leader-fill-content; }
-
-
-/* Logo
- ========================================================================== */
-
-/*
- * 1. Required for `a`
- */
-
-.uk-logo {
- font-size: $logo-font-size;
- font-family: $logo-font-family;
- color: $logo-color;
- /* 1 */
- text-decoration: none;
- @if(mixin-exists(hook-logo)) {@include hook-logo();}
-}
-
-/* Hover + Focus */
-.uk-logo:hover,
-.uk-logo:focus {
- color: $logo-hover-color;
- outline: none;
- /* 1 */
- text-decoration: none;
- @if(mixin-exists(hook-logo-hover)) {@include hook-logo-hover();}
-}
-
-.uk-logo-inverse { display: none; }
-
-
-/* SVG
- ========================================================================== */
-
-/*
- * 1. Fill all SVG elements with the current text color if no `fill` attribute is set
- * 2. Set the fill and stroke color of all SVG elements to the current text color
- * 3. Fix for uppercase attribute names in Edge. Will be fixed in Windows 10 builds 16251+
- */
-
-/* 1 */
-.uk-svg,
-/* 2 */
-.uk-svg:not(.uk-preserve) [fill*='#']:not(.uk-preserve),
-.uk-svg:not(.uk-preserve) [FILL*='#']:not(.uk-preserve) { fill: currentcolor; } // 3
-.uk-svg:not(.uk-preserve) [stroke*='#']:not(.uk-preserve),
-.uk-svg:not(.uk-preserve) [STROKE*='#']:not(.uk-preserve) { stroke: currentcolor; } // 3
-
-/*
- * Fix Firefox blurry SVG rendering: https://bugzilla.mozilla.org/show_bug.cgi?id=1046835
- */
-
-.uk-svg { transform: translate(0,0); }
-
-
-/* Disabled State
- ========================================================================== */
-
-.uk-disabled { pointer-events: none; }
-
-
-/* Drag State
- ========================================================================== */
-
-/*
- * 1. Needed if moving over elements with have their own cursor on hover, e.g. links or buttons
- * 2. Fix dragging over iframes
- */
-
-.uk-drag,
-/* 1 */
-.uk-drag * { cursor: move; }
-
-/* 2 */
-.uk-drag iframe { pointer-events: none; }
-
-
-/* Dragover State
- ========================================================================== */
-
-/*
- * Create a box-shadow when dragging a file over the upload area
- */
-
-.uk-dragover { box-shadow: $dragover-box-shadow; }
-
-
-/* Blend modes
- ========================================================================== */
-
-.uk-blend-multiply { mix-blend-mode: multiply; }
-.uk-blend-screen { mix-blend-mode: screen; }
-.uk-blend-overlay { mix-blend-mode: overlay; }
-.uk-blend-darken { mix-blend-mode: darken; }
-.uk-blend-lighten { mix-blend-mode: lighten; }
-.uk-blend-color-dodge { mix-blend-mode: color-dodge; }
-.uk-blend-color-burn { mix-blend-mode: color-burn; }
-.uk-blend-hard-light { mix-blend-mode: hard-light; }
-.uk-blend-soft-light { mix-blend-mode: soft-light; }
-.uk-blend-difference { mix-blend-mode: difference; }
-.uk-blend-exclusion { mix-blend-mode: exclusion; }
-.uk-blend-hue { mix-blend-mode: hue; }
-.uk-blend-saturation { mix-blend-mode: saturation; }
-.uk-blend-color { mix-blend-mode: color; }
-.uk-blend-luminosity { mix-blend-mode: luminosity; }
-
-
-/* Transform
-========================================================================== */
-
-.uk-transform-center { transform: translate(-50%, -50%); }
-
-
-/* Transform Origin
-========================================================================== */
-
-.uk-transform-origin-top-left { transform-origin: 0 0; }
-.uk-transform-origin-top-center { transform-origin: 50% 0; }
-.uk-transform-origin-top-right { transform-origin: 100% 0; }
-.uk-transform-origin-center-left { transform-origin: 0 50%; }
-.uk-transform-origin-center-right { transform-origin: 100% 50%; }
-.uk-transform-origin-bottom-left { transform-origin: 0 100%; }
-.uk-transform-origin-bottom-center { transform-origin: 50% 100%; }
-.uk-transform-origin-bottom-right { transform-origin: 100% 100%; }
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-utility-misc)) {@include hook-utility-misc();}
-
-// @mixin hook-panel-scrollable(){}
-// @mixin hook-box-shadow-bottom(){}
-// @mixin hook-dropcap(){}
-// @mixin hook-leader(){}
-// @mixin hook-logo(){}
-// @mixin hook-logo-hover(){}
-// @mixin hook-utility-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-$inverse-logo-color: $inverse-global-color !default;
-$inverse-logo-hover-color: $inverse-global-color !default;
-
-
-
-// @mixin hook-inverse-dropcap(){}
-// @mixin hook-inverse-leader(){}
-// @mixin hook-inverse-logo(){}
-// @mixin hook-inverse-logo-hover(){}
diff --git a/_sass/uikit/components/variables.scss b/_sass/uikit/components/variables.scss
deleted file mode 100644
index a08406a05d..0000000000
--- a/_sass/uikit/components/variables.scss
+++ /dev/null
@@ -1,117 +0,0 @@
-//
-// Component: Variables
-// Description: Defines common values which are used across all components
-//
-// ========================================================================
-
-
-// Breakpoints
-// ========================================================================
-
-// Phone Portrait: Galaxy (360x640), iPhone 6 (375x667), iPhone 6+ (414x736)
-// Phone Landscape: Galaxy (640x360), iPhone 6 (667x375), iPhone 6+ (736x414)
-// Tablet Portrait: iPad (768x1024), Galaxy Tab (800x1280),
-// Tablet Landscape: iPad (1024x768), iPad Pro (1024x1366),
-// Desktop: Galaxy Tab (1280x800), iPad Pro (1366x1024)
-
-$breakpoint-small: 640px !default; // Phone landscape
-$breakpoint-medium: 960px !default; // Tablet Landscape
-$breakpoint-large: 1200px !default; // Desktop
-$breakpoint-xlarge: 1600px !default; // Large Screens
-
-$breakpoint-xsmall-max: ($breakpoint-small - 1) !default;
-$breakpoint-small-max: ($breakpoint-medium - 1) !default;
-$breakpoint-medium-max: ($breakpoint-large - 1) !default;
-$breakpoint-large-max: ($breakpoint-xlarge - 1) !default;
-
-
-// Global variables
-// ========================================================================
-
-//
-// Typography
-//
-
-$global-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif !default;
-$global-font-size: 16px !default;
-$global-line-height: 1.5 !default; // 24px
-
-$global-xxlarge-font-size: 2.625rem !default; // 42px
-$global-xlarge-font-size: 2rem !default; // 32px
-$global-large-font-size: 1.5rem !default; // 24px
-$global-medium-font-size: 1.25rem !default; // 20px
-$global-small-font-size: 0.875rem !default; // 14px
-
-//
-// Colors
-//
-
-$global-color: #666 !default;
-$global-emphasis-color: #333 !default;
-$global-muted-color: #999 !default;
-
-$global-link-color: #1e87f0 !default;
-$global-link-hover-color: #0f6ecd !default;
-
-$global-inverse-color: #fff !default;
-
-//
-// Backgrounds
-//
-
-$global-background: #fff !default;
-
-$global-muted-background: #f8f8f8 !default;
-$global-primary-background: #1e87f0 !default;
-$global-secondary-background: #222 !default;
-
-$global-success-background: #32d296 !default;
-$global-warning-background: #faa05a !default;
-$global-danger-background: #f0506e !default;
-
-//
-// Borders
-//
-
-$global-border-width: 1px !default;
-$global-border: #e5e5e5 !default;
-
-//
-// Box-Shadows
-//
-
-$global-small-box-shadow: 0 2px 8px rgba(0,0,0,0.08) !default;
-$global-medium-box-shadow: 0 5px 15px rgba(0,0,0,0.08) !default;
-$global-large-box-shadow: 0 14px 25px rgba(0,0,0,0.16) !default;
-$global-xlarge-box-shadow: 0 28px 50px rgba(0,0,0,0.16) !default;
-
-//
-// Spacings
-//
-
-// Used in margin, section, list
-$global-margin: 20px !default;
-$global-small-margin: 10px !default;
-$global-medium-margin: 40px !default;
-$global-large-margin: 70px !default;
-$global-xlarge-margin: 140px !default;
-
-// Used in grid, column, container, align, card, padding
-$global-gutter: 30px !default;
-$global-small-gutter: 15px !default;
-$global-medium-gutter: 40px !default;
-$global-large-gutter: 70px !default;
-
-//
-// Controls
-//
-
-$global-control-height: 40px !default;
-$global-control-small-height: 30px !default;
-$global-control-large-height: 55px !default;
-
-//
-// Z-index
-//
-
-$global-z-index: 1000 !default;
\ No newline at end of file
diff --git a/_sass/uikit/components/visibility.scss b/_sass/uikit/components/visibility.scss
deleted file mode 100644
index ee800a1537..0000000000
--- a/_sass/uikit/components/visibility.scss
+++ /dev/null
@@ -1,151 +0,0 @@
-// Name: Visibility
-// Description: Utilities to show or hide content on breakpoints, hover or touch
-//
-// Component: `uk-hidden-*`
-// `uk-visible-*`
-// `uk-invisible`
-// `uk-visible-toggle`
-// `uk-hidden-hover`
-// `uk-invisible-hover`
-// `uk-hidden-touch`
-// `uk-hidden-notouch`
-//
-// ========================================================================
-
-
-/* ========================================================================
- Component: Visibility
- ========================================================================== */
-
-/*
- * Hidden
- * `hidden` attribute also set here to make it stronger
- */
-
-[hidden],
-.uk-hidden { display: none !important; }
-
-/* Phone landscape and bigger */
-@media (min-width: $breakpoint-small) {
-
- .uk-hidden\@s { display: none !important; }
-
-}
-
-/* Tablet landscape and bigger */
-@media (min-width: $breakpoint-medium) {
-
- .uk-hidden\@m { display: none !important; }
-
-}
-
-/* Desktop and bigger */
-@media (min-width: $breakpoint-large) {
-
- .uk-hidden\@l { display: none !important; }
-
-}
-
-/* Large screen and bigger */
-@media (min-width: $breakpoint-xlarge) {
-
- .uk-hidden\@xl { display: none !important; }
-
-}
-
-/*
- * Visible
- */
-
-/* Phone portrait and smaller */
-@media (max-width: $breakpoint-xsmall-max) {
-
- .uk-visible\@s { display: none !important; }
-
-}
-
-/* Phone landscape and smaller */
-@media (max-width: $breakpoint-small-max) {
-
- .uk-visible\@m { display: none !important; }
-
-}
-
-/* Tablet landscape and smaller */
-@media (max-width: $breakpoint-medium-max) {
-
- .uk-visible\@l { display: none !important; }
-
-}
-
-/* Desktop and smaller */
-@media (max-width: $breakpoint-large-max) {
-
- .uk-visible\@xl { display: none !important; }
-
-}
-
-
-/* Visibility
- ========================================================================== */
-
-.uk-invisible { visibility: hidden !important; }
-
-
-/* Hover
- ========================================================================== */
-
-/*
- * Hidden
- * Can't use `display: hidden` because it's not focusable. This is accessible through keyboard.
- */
-
-.uk-visible-toggle:not(:hover):not(.uk-hover) .uk-hidden-hover:not(:focus) {
- position: absolute !important;
- width: 0 !important;
- height: 0 !important;
- padding: 0 !important;
- margin: 0 !important;
- overflow: hidden !important;
-}
-
-/*
- * Invisible
- * Can't use `visibility: hidden` because it's not focusable. This is accessible through keyboard.
- */
-
-.uk-visible-toggle:not(:hover):not(.uk-hover) .uk-invisible-hover:not(:focus) { opacity: 0 !important; }
-
-
-/* Touch
- ========================================================================== */
-
-/*
- * Hide if primary pointing device has limited accuracy, e.g. a touch screen.
- * Works on mobile browsers: Safari, Chrome and Android browser
- */
-
-@media (pointer: coarse) {
- .uk-hidden-touch { display: none !important; }
-}
-
-/*
- * Hide if primary pointing device is accurate, e.g. mouse.
- * 1. Fallback for IE11 and Firefox, because `pointer` is not supported
- * 2. Reset if supported
- */
-
-/* 1 */
-.uk-hidden-notouch { display: none !important; }
-
-@media (pointer: coarse) {
- .uk-hidden-notouch { display: block !important; }
-}
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-visibility-misc)) {@include hook-visibility-misc();}
-
-// @mixin hook-visibility-misc(){}
diff --git a/_sass/uikit/components/width.scss b/_sass/uikit/components/width.scss
deleted file mode 100644
index 7f4a2cb533..0000000000
--- a/_sass/uikit/components/width.scss
+++ /dev/null
@@ -1,398 +0,0 @@
-// Name: Width
-// Description: Utilities for widths
-//
-// Component: `uk-child-width-*`
-// `uk-width-*`
-//
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$width-small-width: 150px !default;
-$width-medium-width: 300px !default;
-$width-large-width: 450px !default;
-$width-xlarge-width: 600px !default;
-$width-xxlarge-width: 750px !default;
-
-
-/* ========================================================================
- Component: Width
- ========================================================================== */
-
-
-/* Equal child widths
- ========================================================================== */
-
-[class*='uk-child-width'] > * {
- box-sizing: border-box;
- width: 100%;
-}
-
-.uk-child-width-1-2 > * { width: 50%; }
-.uk-child-width-1-3 > * { width: unquote('calc(100% * 1 / 3.001)'); }
-.uk-child-width-1-4 > * { width: 25%; }
-.uk-child-width-1-5 > * { width: 20%; }
-.uk-child-width-1-6 > * { width: unquote('calc(100% * 1 / 6.001)'); }
-
-.uk-child-width-auto > * { width: auto; }
-
-/*
- * Instead of 0, 1px is needed to make cell wrap into next row if predecessor is 100% wide
- * and the grid gutter is 0 pixels wide
- */
-
-.uk-child-width-expand > * { width: 1px; }
-
-/*
- * 1. Make `width: 1px` work, because according to the spec flex items won’t shrink
- * below their minimum content size. To change this, set the min-width.
- * Only needed for Firefox. All other browsers ignore this.
- *
- * 2. `width` is ignored when wrapping flex items in Safari
- * https://github.com/philipwalton/flexbugs#11-min-and-max-size-declarations-are-ignored-when-wrapping-flex-items
- */
-
-.uk-child-width-expand > :not([class*='uk-width']) {
- flex: 1;
- /* 1 */
- min-width: 0;
- /* 2 */
- flex-basis: 1px;
-}
-
-/* Phone landscape and bigger */
-@media (min-width: $breakpoint-small) {
-
- .uk-child-width-1-1\@s > * { width: 100%; }
- .uk-child-width-1-2\@s > * { width: 50%; }
- .uk-child-width-1-3\@s > * { width: unquote('calc(100% * 1 / 3.001)'); }
- .uk-child-width-1-4\@s > * { width: 25%; }
- .uk-child-width-1-5\@s > * { width: 20%; }
- .uk-child-width-1-6\@s > * { width: unquote('calc(100% * 1 / 6.001)'); }
-
- .uk-child-width-auto\@s > * { width: auto; }
- .uk-child-width-expand\@s > * { width: 1px; }
-
- .uk-child-width-expand\@s > :not([class*='uk-width']) {
- flex: 1;
- min-width: 0;
- flex-basis: 1px;
- }
-
-}
-
-/* Tablet landscape and bigger */
-@media (min-width: $breakpoint-medium) {
-
- .uk-child-width-1-1\@m > * { width: 100%; }
- .uk-child-width-1-2\@m > * { width: 50%; }
- .uk-child-width-1-3\@m > * { width: unquote('calc(100% * 1 / 3.001)'); }
- .uk-child-width-1-4\@m > * { width: 25%; }
- .uk-child-width-1-5\@m > * { width: 20%; }
- .uk-child-width-1-6\@m > * { width: unquote('calc(100% * 1 / 6.001)'); }
-
- .uk-child-width-auto\@m > * { width: auto; }
- .uk-child-width-expand\@m > * { width: 1px; }
-
- .uk-child-width-expand\@m > :not([class*='uk-width']) {
- flex: 1;
- min-width: 0;
- flex-basis: 1px;
- }
-
-}
-
-/* Desktop and bigger */
-@media (min-width: $breakpoint-large) {
-
- .uk-child-width-1-1\@l > * { width: 100%; }
- .uk-child-width-1-2\@l > * { width: 50%; }
- .uk-child-width-1-3\@l > * { width: unquote('calc(100% * 1 / 3.001)'); }
- .uk-child-width-1-4\@l > * { width: 25%; }
- .uk-child-width-1-5\@l > * { width: 20%; }
- .uk-child-width-1-6\@l > * { width: unquote('calc(100% * 1 / 6.001)'); }
-
- .uk-child-width-auto\@l > * { width: auto; }
- .uk-child-width-expand\@l > * { width: 1px; }
-
- .uk-child-width-expand\@l > :not([class*='uk-width']) {
- flex: 1;
- min-width: 0;
- flex-basis: 1px;
- }
-
-}
-
-/* Large screen and bigger */
-@media (min-width: $breakpoint-xlarge) {
-
- .uk-child-width-1-1\@xl > * { width: 100%; }
- .uk-child-width-1-2\@xl > * { width: 50%; }
- .uk-child-width-1-3\@xl > * { width: unquote('calc(100% * 1 / 3.001)'); }
- .uk-child-width-1-4\@xl > * { width: 25%; }
- .uk-child-width-1-5\@xl > * { width: 20%; }
- .uk-child-width-1-6\@xl > * { width: unquote('calc(100% * 1 / 6.001)'); }
-
- .uk-child-width-auto\@xl > * { width: auto; }
- .uk-child-width-expand\@xl > * { width: 1px; }
-
- .uk-child-width-expand\@xl > :not([class*='uk-width']) {
- flex: 1;
- min-width: 0;
- flex-basis: 1px;
- }
-
-}
-
-
-/* Single Widths
- ========================================================================== */
-
-/*
- * 1. `max-width` is needed for the pixel-based classes
- */
-
-[class*='uk-width'] {
- box-sizing: border-box;
- width: 100%;
- /* 1 */
- max-width: 100%;
-}
-
-/* Halves */
-.uk-width-1-2 { width: 50%; }
-
-/* Thirds */
-.uk-width-1-3 { width: unquote('calc(100% * 1 / 3.001)'); }
-.uk-width-2-3 { width: unquote('calc(100% * 2 / 3.001)'); }
-
-/* Quarters */
-.uk-width-1-4 { width: 25%; }
-.uk-width-3-4 { width: 75%; }
-
-/* Fifths */
-.uk-width-1-5 { width: 20%; }
-.uk-width-2-5 { width: 40%; }
-.uk-width-3-5 { width: 60%; }
-.uk-width-4-5 { width: 80%; }
-
-/* Sixths */
-.uk-width-1-6 { width: unquote('calc(100% * 1 / 6.001)'); }
-.uk-width-5-6 { width: unquote('calc(100% * 5 / 6.001)'); }
-
-/* Pixel */
-.uk-width-small { width: $width-small-width; }
-.uk-width-medium { width: $width-medium-width; }
-.uk-width-large { width: $width-large-width; }
-.uk-width-xlarge { width: $width-xlarge-width; }
-.uk-width-xxlarge { width: $width-xxlarge-width; }
-
-/* Auto */
-.uk-width-auto { width: auto; }
-
-/* Expand */
-.uk-width-expand {
- width: 1px;
- flex: 1;
- min-width: 0;
- flex-basis: 1px;
-}
-
-/* Phone landscape and bigger */
-@media (min-width: $breakpoint-small) {
-
- /* Whole */
- .uk-width-1-1\@s { width: 100%; }
-
- /* Halves */
- .uk-width-1-2\@s { width: 50%; }
-
- /* Thirds */
- .uk-width-1-3\@s { width: unquote('calc(100% * 1 / 3.001)'); }
- .uk-width-2-3\@s { width: unquote('calc(100% * 2 / 3.001)'); }
-
- /* Quarters */
- .uk-width-1-4\@s { width: 25%; }
- .uk-width-3-4\@s { width: 75%; }
-
- /* Fifths */
- .uk-width-1-5\@s { width: 20%; }
- .uk-width-2-5\@s { width: 40%; }
- .uk-width-3-5\@s { width: 60%; }
- .uk-width-4-5\@s { width: 80%; }
-
- /* Sixths */
- .uk-width-1-6\@s { width: unquote('calc(100% * 1 / 6.001)'); }
- .uk-width-5-6\@s { width: unquote('calc(100% * 5 / 6.001)'); }
-
- /* Pixel */
- .uk-width-small\@s { width: $width-small-width; }
- .uk-width-medium\@s { width: $width-medium-width; }
- .uk-width-large\@s { width: $width-large-width; }
- .uk-width-xlarge\@s { width: $width-xlarge-width; }
- .uk-width-xxlarge\@s { width: $width-xxlarge-width; }
-
- /* Auto */
- .uk-width-auto\@s { width: auto; }
-
- /* Expand */
- .uk-width-expand\@s {
- width: 1px;
- flex: 1;
- min-width: 0;
- flex-basis: 1px;
- }
-
-}
-
-/* Tablet landscape and bigger */
-@media (min-width: $breakpoint-medium) {
-
- /* Whole */
- .uk-width-1-1\@m { width: 100%; }
-
- /* Halves */
- .uk-width-1-2\@m { width: 50%; }
-
- /* Thirds */
- .uk-width-1-3\@m { width: unquote('calc(100% * 1 / 3.001)'); }
- .uk-width-2-3\@m { width: unquote('calc(100% * 2 / 3.001)'); }
-
- /* Quarters */
- .uk-width-1-4\@m { width: 25%; }
- .uk-width-3-4\@m { width: 75%; }
-
- /* Fifths */
- .uk-width-1-5\@m { width: 20%; }
- .uk-width-2-5\@m { width: 40%; }
- .uk-width-3-5\@m { width: 60%; }
- .uk-width-4-5\@m { width: 80%; }
-
- /* Sixths */
- .uk-width-1-6\@m { width: unquote('calc(100% * 1 / 6.001)'); }
- .uk-width-5-6\@m { width: unquote('calc(100% * 5 / 6.001)'); }
-
- /* Pixel */
- .uk-width-small\@m { width: $width-small-width; }
- .uk-width-medium\@m { width: $width-medium-width; }
- .uk-width-large\@m { width: $width-large-width; }
- .uk-width-xlarge\@m { width: $width-xlarge-width; }
- .uk-width-xxlarge\@m { width: $width-xxlarge-width; }
-
- /* Auto */
- .uk-width-auto\@m { width: auto; }
-
- /* Expand */
- .uk-width-expand\@m {
- width: 1px;
- flex: 1;
- min-width: 0;
- flex-basis: 1px;
- }
-
-}
-
-/* Desktop and bigger */
-@media (min-width: $breakpoint-large) {
-
- /* Whole */
- .uk-width-1-1\@l { width: 100%; }
-
- /* Halves */
- .uk-width-1-2\@l { width: 50%; }
-
- /* Thirds */
- .uk-width-1-3\@l { width: unquote('calc(100% * 1 / 3.001)'); }
- .uk-width-2-3\@l { width: unquote('calc(100% * 2 / 3.001)'); }
-
- /* Quarters */
- .uk-width-1-4\@l { width: 25%; }
- .uk-width-3-4\@l { width: 75%; }
-
- /* Fifths */
- .uk-width-1-5\@l { width: 20%; }
- .uk-width-2-5\@l { width: 40%; }
- .uk-width-3-5\@l { width: 60%; }
- .uk-width-4-5\@l { width: 80%; }
-
- /* Sixths */
- .uk-width-1-6\@l { width: unquote('calc(100% * 1 / 6.001)'); }
- .uk-width-5-6\@l { width: unquote('calc(100% * 5 / 6.001)'); }
-
- /* Pixel */
- .uk-width-small\@l { width: $width-small-width; }
- .uk-width-medium\@l { width: $width-medium-width; }
- .uk-width-large\@l { width: $width-large-width; }
- .uk-width-xlarge\@l { width: $width-xlarge-width; }
- .uk-width-xxlarge\@l { width: $width-xxlarge-width; }
-
- /* Auto */
- .uk-width-auto\@l { width: auto; }
-
- /* Expand */
- .uk-width-expand\@l {
- width: 1px;
- flex: 1;
- min-width: 0;
- flex-basis: 1px;
- }
-
-}
-
-/* Large screen and bigger */
-@media (min-width: $breakpoint-xlarge) {
-
- /* Whole */
- .uk-width-1-1\@xl { width: 100%; }
-
- /* Halves */
- .uk-width-1-2\@xl { width: 50%; }
-
- /* Thirds */
- .uk-width-1-3\@xl { width: unquote('calc(100% * 1 / 3.001)'); }
- .uk-width-2-3\@xl { width: unquote('calc(100% * 2 / 3.001)'); }
-
- /* Quarters */
- .uk-width-1-4\@xl { width: 25%; }
- .uk-width-3-4\@xl { width: 75%; }
-
- /* Fifths */
- .uk-width-1-5\@xl { width: 20%; }
- .uk-width-2-5\@xl { width: 40%; }
- .uk-width-3-5\@xl { width: 60%; }
- .uk-width-4-5\@xl { width: 80%; }
-
- /* Sixths */
- .uk-width-1-6\@xl { width: unquote('calc(100% * 1 / 6.001)'); }
- .uk-width-5-6\@xl { width: unquote('calc(100% * 5 / 6.001)'); }
-
- /* Pixel */
- .uk-width-small\@xl { width: $width-small-width; }
- .uk-width-medium\@xl { width: $width-medium-width; }
- .uk-width-large\@xl { width: $width-large-width; }
- .uk-width-xlarge\@xl { width: $width-xlarge-width; }
- .uk-width-xxlarge\@xl { width: $width-xxlarge-width; }
-
- /* Auto */
- .uk-width-auto\@xl { width: auto; }
-
- /* Expand */
- .uk-width-expand\@xl {
- width: 1px;
- flex: 1;
- min-width: 0;
- flex-basis: 1px;
- }
-
-}
-
-
-// Hooks
-// ========================================================================
-
-@if(mixin-exists(hook-width-misc)) {@include hook-width-misc();}
-
-// @mixin hook-width-misc(){}
diff --git a/_sass/uikit/mixins-theme.scss b/_sass/uikit/mixins-theme.scss
deleted file mode 100644
index 993cf20969..0000000000
--- a/_sass/uikit/mixins-theme.scss
+++ /dev/null
@@ -1,2033 +0,0 @@
-@mixin hook-accordion(){}
-@mixin hook-accordion-item(){}
-@mixin hook-accordion-title(){
-
- overflow: hidden;
-
- &::after {
- content: "";
- width: ($accordion-title-line-height * 1em);
- height: ($accordion-title-line-height * 1em);
- float: right;
- @include svg-fill($internal-accordion-close-image, "#000", $accordion-icon-color);
- background-repeat: no-repeat;
- background-position: 50% 50%;
- }
-
- .uk-open > &::after { @include svg-fill($internal-accordion-open-image, "#000", $accordion-icon-color); }
-
-}
-@mixin hook-accordion-title-hover(){}
-@mixin hook-accordion-content(){}
-@mixin hook-accordion-misc(){}
-@mixin hook-inverse-accordion-item(){}
-@mixin hook-inverse-accordion-title(){}
-@mixin hook-inverse-accordion-title-hover(){}
-@mixin hook-inverse-component-accordion(){
-
- .uk-accordion-title::after { @include svg-fill($internal-accordion-close-image, "#000", $inverse-global-color); }
-
- .uk-open > .uk-accordion-title::after { @include svg-fill($internal-accordion-open-image, "#000", $inverse-global-color); }
-
-}
-@mixin hook-align-misc(){}
-@mixin hook-alert(){}
-@mixin hook-alert-close(){
- color: inherit;
- opacity: $alert-close-opacity;
-}
-@mixin hook-alert-close-hover(){
- color: inherit;
- opacity: $alert-close-hover-opacity;
-}
-@mixin hook-alert-primary(){}
-@mixin hook-alert-success(){}
-@mixin hook-alert-warning(){}
-@mixin hook-alert-danger(){}
-@mixin hook-alert-misc(){
-
- /*
- * Content
- */
-
- .uk-alert h1,
- .uk-alert h2,
- .uk-alert h3,
- .uk-alert h4,
- .uk-alert h5,
- .uk-alert h6 { color: inherit; }
-
- .uk-alert a:not([class]) {
- color: inherit;
- text-decoration: underline;
- }
-
- .uk-alert a:not([class]):hover {
- color: inherit;
- text-decoration: underline;
- }
-
-}
-@mixin hook-article(){}
-@mixin hook-article-adjacent(){}
-@mixin hook-article-title(){}
-@mixin hook-article-meta(){
-
- a { color: $article-meta-link-color; }
-
- a:hover {
- color: $article-meta-link-hover-color;
- text-decoration: none;
- }
-
-}
-@mixin hook-article-misc(){}
-@mixin hook-inverse-article-title(){}
-@mixin hook-inverse-article-meta(){}
-@mixin hook-inverse-component-article(){
-
- .uk-article-title {
- @if(mixin-exists(hook-inverse-article-title)) {@include hook-inverse-article-title();}
- }
-
- .uk-article-meta {
- color: $inverse-article-meta-color;
- @if(mixin-exists(hook-inverse-article-meta)) {@include hook-inverse-article-meta();}
- }
-
-}
-@mixin hook-animation-misc(){}
-@mixin hook-background-misc(){}
-@mixin hook-badge(){}
-@mixin hook-badge-hover(){}
-@mixin hook-badge-misc(){}
-@mixin hook-inverse-badge(){}
-@mixin hook-inverse-badge-hover(){}
-@mixin hook-inverse-component-badge(){
-
- .uk-badge {
- background-color: $inverse-badge-background;
- color: $inverse-badge-color;
- @if(mixin-exists(hook-inverse-badge)) {@include hook-inverse-badge();}
- }
-
- .uk-badge:hover,
- .uk-badge:focus {
- color: $inverse-badge-hover-color;
- @if(mixin-exists(hook-inverse-badge-hover)) {@include hook-inverse-badge-hover();}
- }
-
-}
-@mixin hook-base-body(){}
-@mixin hook-base-link(){}
-@mixin hook-base-link-hover(){}
-@mixin hook-base-code(){
- padding: $base-code-padding-vertical $base-code-padding-horizontal;
- background: $base-code-background;
-}
-@mixin hook-base-heading(){}
-@mixin hook-base-h1(){}
-@mixin hook-base-h2(){}
-@mixin hook-base-h3(){}
-@mixin hook-base-h4(){}
-@mixin hook-base-h5(){}
-@mixin hook-base-h6(){}
-@mixin hook-base-hr(){}
-@mixin hook-base-blockquote(){
- color: $base-blockquote-color;
-}
-@mixin hook-base-blockquote-footer(){
-
- color: $base-blockquote-footer-color;
-
- &::before { content: "— "; }
-
-}
-@mixin hook-base-pre(){
- padding: $base-pre-padding;
- border: $base-pre-border-width solid $base-pre-border;
- border-radius: $base-pre-border-radius;
- background: $base-pre-background;
-}
-@mixin hook-base-misc(){}
-@mixin hook-inverse-base-link(){}
-@mixin hook-inverse-base-link-hover(){}
-@mixin hook-inverse-base-code(){
- background: $inverse-global-muted-background;
-}
-@mixin hook-inverse-base-heading(){}
-@mixin hook-inverse-base-h1(){}
-@mixin hook-inverse-base-h2(){}
-@mixin hook-inverse-base-h3(){}
-@mixin hook-inverse-base-h4(){}
-@mixin hook-inverse-base-h5(){}
-@mixin hook-inverse-base-h6(){}
-@mixin hook-inverse-base-blockquote(){ color: $inverse-base-blockquote-color; }
-@mixin hook-inverse-base-blockquote-footer(){ color: $inverse-base-blockquote-footer-color; }
-@mixin hook-inverse-base-hr(){}
-@mixin hook-inverse-component-base(){
-
- color: $inverse-base-color;
-
- // Base
- // ========================================================================
-
- //
- // Link
- //
-
- a,
- .uk-link {
- color: $inverse-base-link-color;
- @if(mixin-exists(hook-inverse-base-link)) {@include hook-inverse-base-link();}
- }
-
- a:hover,
- .uk-link:hover {
- color: $inverse-base-link-hover-color;
- @if(mixin-exists(hook-inverse-base-link-hover)) {@include hook-inverse-base-link-hover();}
- }
-
- //
- // Code
- //
-
- :not(pre) > code,
- :not(pre) > kbd,
- :not(pre) > samp {
- color: $inverse-base-code-color;
- @if(mixin-exists(hook-inverse-base-code)) {@include hook-inverse-base-code();}
- }
-
- //
- // Emphasize
- //
-
- em { color: $inverse-base-em-color; }
-
- //
- // Headings
- //
-
- h1, .uk-h1,
- h2, .uk-h2,
- h3, .uk-h3,
- h4, .uk-h4,
- h5, .uk-h5,
- h6, .uk-h6 {
- color: $inverse-base-heading-color;
- @if(mixin-exists(hook-inverse-base-heading)) {@include hook-inverse-base-heading();}
- }
-
- h1, .uk-h1 {
- @if(mixin-exists(hook-inverse-base-h1)) {@include hook-inverse-base-h1();}
- }
-
- h2, .uk-h2 {
- @if(mixin-exists(hook-inverse-base-h2)) {@include hook-inverse-base-h2();}
- }
-
- h3, .uk-h3 {
- @if(mixin-exists(hook-inverse-base-h3)) {@include hook-inverse-base-h3();}
- }
-
- h4, .uk-h4 {
- @if(mixin-exists(hook-inverse-base-h4)) {@include hook-inverse-base-h4();}
- }
-
- h5, .uk-h5 {
- @if(mixin-exists(hook-inverse-base-h5)) {@include hook-inverse-base-h5();}
- }
-
- h6, .uk-h6 {
- @if(mixin-exists(hook-inverse-base-h6)) {@include hook-inverse-base-h6();}
- }
-
- //
- // Blockquotes
- //
-
- blockquote {
- @if(mixin-exists(hook-inverse-base-blockquote)) {@include hook-inverse-base-blockquote();}
- }
-
- blockquote footer {
- @if(mixin-exists(hook-inverse-base-blockquote-footer)) {@include hook-inverse-base-blockquote-footer();}
- }
-
- //
- // Horizontal rules
- //
-
- hr, .uk-hr {
- border-top-color: $inverse-base-hr-border;
- @if(mixin-exists(hook-inverse-base-hr)) {@include hook-inverse-base-hr();}
- }
-
-}
-@mixin hook-breadcrumb(){}
-@mixin hook-breadcrumb-item(){}
-@mixin hook-breadcrumb-item-hover(){}
-@mixin hook-breadcrumb-item-disabled(){}
-@mixin hook-breadcrumb-item-active(){}
-@mixin hook-breadcrumb-divider(){}
-@mixin hook-breadcrumb-misc(){}
-@mixin hook-inverse-breadcrumb-item(){}
-@mixin hook-inverse-breadcrumb-item-hover(){}
-@mixin hook-inverse-breadcrumb-item-disabled(){}
-@mixin hook-inverse-breadcrumb-item-active(){}
-@mixin hook-inverse-breadcrumb-divider(){}
-@mixin hook-inverse-component-breadcrumb(){
-
- .uk-breadcrumb > * > * {
- color: $inverse-breadcrumb-item-color;
- @if(mixin-exists(hook-inverse-breadcrumb-item)) {@include hook-inverse-breadcrumb-item();}
- }
-
- .uk-breadcrumb > * > :hover,
- .uk-breadcrumb > * > :focus {
- color: $inverse-breadcrumb-item-hover-color;
- @if(mixin-exists(hook-inverse-breadcrumb-item-hover)) {@include hook-inverse-breadcrumb-item-hover();}
- }
-
-
- .uk-breadcrumb > .uk-disabled > * {
- @if(mixin-exists(hook-inverse-breadcrumb-item-disabled)) {@include hook-inverse-breadcrumb-item-disabled();}
- }
-
- .uk-breadcrumb > :last-child > * {
- color: $inverse-breadcrumb-item-active-color;
- @if(mixin-exists(hook-inverse-breadcrumb-item-active)) {@include hook-inverse-breadcrumb-item-active();}
- }
-
- //
- // Divider
- //
-
- .uk-breadcrumb > :nth-child(n+2):not(.uk-first-column)::before {
- color: $inverse-breadcrumb-divider-color;
- @if(mixin-exists(hook-inverse-breadcrumb-divider)) {@include hook-inverse-breadcrumb-divider();}
- }
-
-}
-@mixin hook-button(){
- text-transform: $button-text-transform;
- transition: 0.1s ease-in-out;
- transition-property: color, background-color, border-color;
-}
-@mixin hook-button-hover(){}
-@mixin hook-button-focus(){}
-@mixin hook-button-active(){}
-@mixin hook-button-default(){ border: $button-border-width solid $button-default-border; }
-@mixin hook-button-default-hover(){ border-color: $button-default-hover-border; }
-@mixin hook-button-default-active(){ border-color: $button-default-active-border; }
-@mixin hook-button-primary(){ border: $button-border-width solid transparent; }
-@mixin hook-button-primary-hover(){}
-@mixin hook-button-primary-active(){}
-@mixin hook-button-secondary(){ border: $button-border-width solid transparent; }
-@mixin hook-button-secondary-hover(){}
-@mixin hook-button-secondary-active(){}
-@mixin hook-button-danger(){ border: $button-border-width solid transparent; }
-@mixin hook-button-danger-hover(){}
-@mixin hook-button-danger-active(){}
-@mixin hook-button-disabled(){ border-color: $button-disabled-border; }
-@mixin hook-button-small(){}
-@mixin hook-button-large(){}
-@mixin hook-button-text(){
-
- position: relative;
-
- &::before {
- content: "";
- position: absolute;
- bottom: 0;
- left: 0;
- right: 100%;
- border-bottom: $button-text-border-width solid $button-text-border;
- transition: right 0.3s ease-out;
- }
-
-}
-@mixin hook-button-text-hover(){
-
- &::before { right: 0; }
-
-}
-@mixin hook-button-text-disabled(){
-
- &::before { display: none; }
-
-}
-@mixin hook-button-link(){}
-@mixin hook-button-misc(){
-
- /* Group
- ========================================================================== */
-
- /*
- * Collapse border
- */
-
- .uk-button-group > .uk-button:nth-child(n+2),
- .uk-button-group > div:nth-child(n+2) .uk-button { margin-left: (-$button-border-width); }
-
- /*
- * Create position context to superimpose the successor elements border
- * Known issue: If you use an `a` element as button and an icon inside,
- * the active state will not work if you click the icon inside the button
- * Workaround: Just use a `button` or `input` element as button
- */
-
- .uk-button-group .uk-button:hover,
- .uk-button-group .uk-button:focus,
- .uk-button-group .uk-button:active,
- .uk-button-group .uk-button.uk-active {
- position: relative;
- z-index: 1;
- }
-
-}
-@mixin hook-inverse-button-default(){ border-color: $inverse-global-color; }
-@mixin hook-inverse-button-default-hover(){ border-color: $inverse-global-emphasis-color; }
-@mixin hook-inverse-button-default-active(){ border-color: $inverse-global-emphasis-color; }
-@mixin hook-inverse-button-primary(){}
-@mixin hook-inverse-button-primary-hover(){}
-@mixin hook-inverse-button-primary-active(){}
-@mixin hook-inverse-button-secondary(){}
-@mixin hook-inverse-button-secondary-hover(){}
-@mixin hook-inverse-button-secondary-active(){}
-@mixin hook-inverse-button-text(){
- &::before { border-bottom-color: $inverse-global-emphasis-color; }
-}
-@mixin hook-inverse-button-text-hover(){}
-@mixin hook-inverse-button-text-disabled(){}
-@mixin hook-inverse-button-link(){}
-@mixin hook-inverse-component-button(){
-
- //
- // Default
- //
-
- .uk-button-default {
- background-color: $inverse-button-default-background;
- color: $inverse-button-default-color;
- @if(mixin-exists(hook-inverse-button-default)) {@include hook-inverse-button-default();}
- }
-
- .uk-button-default:hover,
- .uk-button-default:focus {
- background-color: $inverse-button-default-hover-background;
- color: $inverse-button-default-hover-color;
- @if(mixin-exists(hook-inverse-button-default-hover)) {@include hook-inverse-button-default-hover();}
- }
-
- .uk-button-default:active,
- .uk-button-default.uk-active {
- background-color: $inverse-button-default-active-background;
- color: $inverse-button-default-active-color;
- @if(mixin-exists(hook-inverse-button-default-active)) {@include hook-inverse-button-default-active();}
- }
-
- //
- // Primary
- //
-
- .uk-button-primary {
- background-color: $inverse-button-primary-background;
- color: $inverse-button-primary-color;
- @if(mixin-exists(hook-inverse-button-primary)) {@include hook-inverse-button-primary();}
- }
-
- .uk-button-primary:hover,
- .uk-button-primary:focus {
- background-color: $inverse-button-primary-hover-background;
- color: $inverse-button-primary-hover-color;
- @if(mixin-exists(hook-inverse-button-primary-hover)) {@include hook-inverse-button-primary-hover();}
- }
-
- .uk-button-primary:active,
- .uk-button-primary.uk-active {
- background-color: $inverse-button-primary-active-background;
- color: $inverse-button-primary-active-color;
- @if(mixin-exists(hook-inverse-button-primary-active)) {@include hook-inverse-button-primary-active();}
- }
-
- //
- // Secondary
- //
-
- .uk-button-secondary {
- background-color: $inverse-button-secondary-background;
- color: $inverse-button-secondary-color;
- @if(mixin-exists(hook-inverse-button-secondary)) {@include hook-inverse-button-secondary();}
- }
-
- .uk-button-secondary:hover,
- .uk-button-secondary:focus {
- background-color: $inverse-button-secondary-hover-background;
- color: $inverse-button-secondary-hover-color;
- @if(mixin-exists(hook-inverse-button-secondary-hover)) {@include hook-inverse-button-secondary-hover();}
- }
-
- .uk-button-secondary:active,
- .uk-button-secondary.uk-active {
- background-color: $inverse-button-secondary-active-background;
- color: $inverse-button-secondary-active-color;
- @if(mixin-exists(hook-inverse-button-secondary-active)) {@include hook-inverse-button-secondary-active();}
- }
-
- //
- // Text
- //
-
- .uk-button-text {
- color: $inverse-button-text-color;
- @if(mixin-exists(hook-inverse-button-text)) {@include hook-inverse-button-text();}
- }
-
- .uk-button-text:hover,
- .uk-button-text:focus {
- color: $inverse-button-text-hover-color;
- @if(mixin-exists(hook-inverse-button-text-hover)) {@include hook-inverse-button-text-hover();}
- }
-
- .uk-button-text:disabled {
- color: $inverse-button-text-disabled-color;
- @if(mixin-exists(hook-inverse-button-text-disabled)) {@include hook-inverse-button-text-disabled();}
- }
-
- //
- // Link
- //
-
- .uk-button-link {
- color: $inverse-button-link-color;
- @if(mixin-exists(hook-inverse-button-link)) {@include hook-inverse-button-link();}
- }
-
- .uk-button-link:hover,
- .uk-button-link:focus { color: $inverse-button-link-hover-color; }
-
-
-}
-@mixin hook-card(){ transition: box-shadow 0.1s ease-in-out; }
-@mixin hook-card-body(){}
-@mixin hook-card-header(){}
-@mixin hook-card-footer(){}
-@mixin hook-card-media(){}
-@mixin hook-card-media-top(){}
-@mixin hook-card-media-bottom(){}
-@mixin hook-card-media-left(){}
-@mixin hook-card-media-right(){}
-@mixin hook-card-title(){}
-@mixin hook-card-badge(){}
-@mixin hook-card-hover(){ box-shadow: $card-hover-box-shadow; }
-@mixin hook-card-default(){ box-shadow: $card-default-box-shadow; }
-@mixin hook-card-default-title(){}
-@mixin hook-card-default-hover(){ box-shadow: $card-default-hover-box-shadow; }
-@mixin hook-card-default-header(){ border-bottom: $card-default-header-border-width solid $card-default-header-border; }
-@mixin hook-card-default-footer(){ border-top: $card-default-footer-border-width solid $card-default-footer-border; }
-@mixin hook-card-primary(){ box-shadow: $card-primary-box-shadow; }
-@mixin hook-card-primary-title(){}
-@mixin hook-card-primary-hover(){ box-shadow: $card-primary-hover-box-shadow; }
-@mixin hook-card-secondary(){ box-shadow: $card-secondary-box-shadow; }
-@mixin hook-card-secondary-title(){}
-@mixin hook-card-secondary-hover(){ box-shadow: $card-secondary-hover-box-shadow; }
-@mixin hook-card-misc(){
-
- /*
- * Default
- */
-
- .uk-card-body .uk-nav-default { margin: (-$card-body-padding-vertical + 15px) (-$card-body-padding-horizontal); }
- .uk-card-title + .uk-nav-default { margin-top: 0; }
-
- .uk-card-body .uk-nav-default > li > a,
- .uk-card-body .uk-nav-default .uk-nav-header,
- .uk-card-body .uk-nav-default .uk-nav-divider {
- padding-left: $card-body-padding-horizontal;
- padding-right: $card-body-padding-horizontal;
- }
-
- .uk-card-body .uk-nav-default .uk-nav-sub { padding-left: $nav-sublist-deeper-padding-left + $card-body-padding-horizontal; }
-
-
- /* Desktop and bigger */
- @media (min-width: $breakpoint-large) {
-
- .uk-card-body .uk-nav-default { margin: (-$card-body-padding-vertical-l + 15px) (-$card-body-padding-horizontal-l); }
- .uk-card-title + .uk-nav-default { margin-top: 0; }
-
- .uk-card-body .uk-nav-default > li > a,
- .uk-card-body .uk-nav-default .uk-nav-header,
- .uk-card-body .uk-nav-default .uk-nav-divider {
- padding-left: $card-body-padding-horizontal-l;
- padding-right: $card-body-padding-horizontal-l;
- }
-
- .uk-card-body .uk-nav-default .uk-nav-sub { padding-left: $nav-sublist-deeper-padding-left + $card-body-padding-horizontal-l; }
-
- }
-
- /*
- * Small
- */
-
- .uk-card-small .uk-nav-default { margin: (-$card-small-body-padding-vertical + 15px) (-$card-small-body-padding-horizontal); }
- .uk-card-small .uk-card-title + .uk-nav-default { margin-top: 0; }
-
- .uk-card-small .uk-nav-default > li > a,
- .uk-card-small .uk-nav-default .uk-nav-header,
- .uk-card-small .uk-nav-default .uk-nav-divider {
- padding-left: $card-small-body-padding-horizontal;
- padding-right: $card-small-body-padding-horizontal;
- }
-
- .uk-card-small .uk-nav-default .uk-nav-sub { padding-left: $nav-sublist-deeper-padding-left + $card-small-body-padding-horizontal; }
-
- /*
- * Large
- */
-
- /* Desktop and bigger */
- @media (min-width: $breakpoint-large) {
-
- .uk-card-large .uk-nav-default { margin: (-$card-large-body-padding-vertical-l + 15px) (-$card-large-body-padding-horizontal-l); }
- .uk-card-large .uk-card-title + .uk-nav-default { margin-top: 0; }
-
- }
-
-}
-@mixin hook-close(){
- transition: 0.1s ease-in-out;
- transition-property: color, opacity;
-}
-@mixin hook-close-hover(){}
-@mixin hook-close-misc(){}
-@mixin hook-inverse-close(){}
-@mixin hook-inverse-close-hover(){}
-@mixin hook-inverse-component-close(){
-
- .uk-close {
- color: $inverse-close-color;
- @if(mixin-exists(hook-inverse-close)) {@include hook-inverse-close();}
- }
-
- .uk-close:hover,
- .uk-close:focus {
- color: $inverse-close-hover-color;
- @if(mixin-exists(hook-inverse-close-hover)) {@include hook-inverse-close-hover();}
- }
-
-}
-@mixin hook-column-misc(){}
-@mixin hook-inverse-component-column(){
-
- .uk-column-divider { column-rule-color: $inverse-column-divider-rule-color; }
-
-}
-@mixin hook-comment(){}
-@mixin hook-comment-body(){}
-@mixin hook-comment-header(){}
-@mixin hook-comment-title(){}
-@mixin hook-comment-meta(){}
-@mixin hook-comment-avatar(){}
-@mixin hook-comment-list-adjacent(){}
-@mixin hook-comment-list-sub(){}
-@mixin hook-comment-list-sub-adjacent(){}
-@mixin hook-comment-primary(){
- padding: $comment-primary-padding;
- background-color: $comment-primary-background;
-}
-@mixin hook-comment-misc(){}
-@mixin hook-container-misc(){}
-@mixin hook-countdown(){}
-@mixin hook-countdown-item(){}
-@mixin hook-countdown-number(){}
-@mixin hook-countdown-separator(){}
-@mixin hook-countdown-label(){}
-@mixin hook-countdown-misc(){}
-@mixin hook-inverse-countdown-item(){}
-@mixin hook-inverse-countdown-number(){}
-@mixin hook-inverse-countdown-separator(){}
-@mixin hook-inverse-countdown-label(){}
-@mixin hook-inverse-component-countdown(){
-
- .uk-countdown-number,
- .uk-countdown-separator {
- @if(mixin-exists(hook-inverse-countdown-item)) {@include hook-inverse-countdown-item();}
- }
-
- .uk-countdown-number {
- @if(mixin-exists(hook-inverse-countdown-number)) {@include hook-inverse-countdown-number();}
- }
-
- .uk-countdown-separator {
- @if(mixin-exists(hook-inverse-countdown-separator)) {@include hook-inverse-countdown-separator();}
- }
-
- .uk-countdown-label {
- @if(mixin-exists(hook-inverse-countdown-label)) {@include hook-inverse-countdown-label();}
- }
-
-}
-@mixin hook-cover-misc(){}
-@mixin hook-description-list-term(){
- font-size: $description-list-term-font-size;
- font-weight: $description-list-term-font-weight;
- text-transform: $description-list-term-text-transform;
-}
-@mixin hook-description-list-description(){}
-@mixin hook-description-list-divider-term(){}
-@mixin hook-description-list-misc(){}
-@mixin svg-fill($src, $color-default, $color-new, $property: background-image){
-
- $escape-color-default: escape($color-default) !default;
- $escape-color-new: escape("#{$color-new}") !default;
-
- $data-uri: data-uri('image/svg+xml;charset=UTF-8', "#{$src}") !default;
- $replace-src: replace("#{$data-uri}", "#{$escape-color-default}", "#{$escape-color-new}", "g") !default;
-
- #{$property}: unquote($replace-src);
-}
-@mixin hook-divider-icon(){}
-@mixin hook-divider-icon-line(){}
-@mixin hook-divider-icon-line-left(){}
-@mixin hook-divider-icon-line-right(){}
-@mixin hook-divider-small(){}
-@mixin hook-divider-misc(){}
-@mixin hook-inverse-divider-icon(){}
-@mixin hook-inverse-divider-icon-line(){}
-@mixin hook-inverse-divider-small(){}
-@mixin hook-inverse-component-divider(){
-
- .uk-divider-icon {
- @include svg-fill($internal-divider-icon-image, "#000", $inverse-divider-icon-color);
- @if(mixin-exists(hook-inverse-divider-icon)) {@include hook-inverse-divider-icon();}
- }
-
- .uk-divider-icon::before,
- .uk-divider-icon::after {
- border-bottom-color: $inverse-divider-icon-line-border;
- @if(mixin-exists(hook-inverse-divider-icon-line)) {@include hook-inverse-divider-icon-line();}
- }
-
- .uk-divider-small::after {
- border-top-color: $inverse-divider-small-border;
- @if(mixin-exists(hook-inverse-divider-small)) {@include hook-inverse-divider-small();}
- }
-
-}
-@mixin hook-dotnav(){}
-@mixin hook-dotnav-item(){
- border: $dotnav-item-border-width solid $dotnav-item-border;
- transition: 0.2s ease-in-out;
- transition-property: background-color, border-color;
-}
-@mixin hook-dotnav-item-hover(){ border-color: $dotnav-item-hover-border; }
-@mixin hook-dotnav-item-onclick(){ border-color: $dotnav-item-onclick-border; }
-@mixin hook-dotnav-item-active(){ border-color: $dotnav-item-active-border; }
-@mixin hook-dotnav-misc(){}
-@mixin hook-inverse-dotnav-item(){ border-color: rgba($inverse-global-color, 0.9); }
-@mixin hook-inverse-dotnav-item-hover(){ border-color: transparent; }
-@mixin hook-inverse-dotnav-item-onclick(){ border-color: transparent; }
-@mixin hook-inverse-dotnav-item-active(){ border-color: transparent; }
-@mixin hook-inverse-component-dotnav(){
-
- .uk-dotnav > * > * {
- background-color: $inverse-dotnav-item-background;
- @if(mixin-exists(hook-inverse-dotnav-item)) {@include hook-inverse-dotnav-item();}
- }
-
- .uk-dotnav > * > :hover,
- .uk-dotnav > * > :focus {
- background-color: $inverse-dotnav-item-hover-background;
- @if(mixin-exists(hook-inverse-dotnav-item-hover)) {@include hook-inverse-dotnav-item-hover();}
- }
-
- .uk-dotnav > * > :active {
- background-color: $inverse-dotnav-item-onclick-background;
- @if(mixin-exists(hook-inverse-dotnav-item-onclick)) {@include hook-inverse-dotnav-item-onclick();}
- }
-
- .uk-dotnav > .uk-active > * {
- background-color: $inverse-dotnav-item-active-background;
- @if(mixin-exists(hook-inverse-dotnav-item-active)) {@include hook-inverse-dotnav-item-active();}
- }
-
-}
-@mixin hook-drop-misc(){}
-@mixin hook-dropdown(){ box-shadow: $dropdown-box-shadow; }
-@mixin hook-dropdown-nav(){ font-size: $dropdown-nav-font-size; }
-@mixin hook-dropdown-nav-item(){}
-@mixin hook-dropdown-nav-item-hover(){}
-@mixin hook-dropdown-nav-header(){}
-@mixin hook-dropdown-nav-divider(){}
-@mixin hook-dropdown-misc(){}
-@mixin hook-flex-misc(){}
-@mixin hook-form-range(){}
-@mixin hook-form-range-thumb(){ border: $form-range-thumb-border-width solid $form-range-thumb-border; }
-@mixin hook-form-range-track(){ border-radius: $form-range-track-border-radius; }
-@mixin hook-form-range-track-focus(){}
-@mixin hook-form-range-misc(){}
-@mixin hook-form(){
- border: $form-border-width solid $form-border;
- transition: 0.2s ease-in-out;
- transition-property: color, background-color, border;
-}
-@mixin hook-form-single-line(){}
-@mixin hook-form-multi-line(){}
-@mixin hook-form-focus(){ border-color: $form-focus-border; }
-@mixin hook-form-disabled(){ border-color: $form-disabled-border; }
-@mixin hook-form-danger(){ border-color: $form-danger-border; }
-@mixin hook-form-success(){ border-color: $form-success-border; }
-@mixin hook-form-blank(){ border-color: transparent; }
-@mixin hook-form-blank-focus(){
- border-color: $form-blank-focus-border;
- border-style: $form-blank-focus-border-style;
-}
-@mixin hook-form-radio(){
- border: $form-radio-border-width solid $form-radio-border;
- transition: 0.2s ease-in-out;
- transition-property: background-color, border;
-}
-@mixin hook-form-radio-focus(){ border-color: $form-radio-focus-border; }
-@mixin hook-form-radio-checked(){ border-color: $form-radio-checked-border; }
-@mixin hook-form-radio-checked-focus(){}
-@mixin hook-form-radio-disabled(){ border-color: $form-radio-disabled-border; }
-@mixin hook-form-legend(){}
-@mixin hook-form-label(){
- color: $form-label-color;
- font-size: $form-label-font-size;
-}
-@mixin hook-form-stacked-label(){}
-@mixin hook-form-horizontal-label(){}
-@mixin hook-form-misc(){}
-@mixin hook-inverse-form(){ border-color: $inverse-global-border; }
-@mixin hook-inverse-form-focus(){ border-color: $inverse-global-color; }
-@mixin hook-inverse-form-radio(){ border-color: $inverse-global-border; }
-@mixin hook-inverse-form-radio-focus(){ border-color: $inverse-global-color; }
-@mixin hook-inverse-form-radio-checked(){ border-color: $inverse-global-color; }
-@mixin hook-inverse-form-radio-checked-focus(){}
-@mixin hook-inverse-form-label(){ color: $inverse-form-label-color; }
-@mixin hook-inverse-component-form(){
-
- .uk-input,
- .uk-select,
- .uk-textarea {
- background-color: $inverse-form-background;
- color: $inverse-form-color;
- background-clip: padding-box;
- @if(mixin-exists(hook-inverse-form)) {@include hook-inverse-form();}
-
- &:focus {
- background-color: $inverse-form-focus-background;
- color: $inverse-form-focus-color;
- @if(mixin-exists(hook-inverse-form-focus)) {@include hook-inverse-form-focus();}
- }
- }
-
- //
- // Placeholder
- //
-
- .uk-input:-ms-input-placeholder { color: $inverse-form-placeholder-color !important; }
- .uk-input::placeholder { color: $inverse-form-placeholder-color; }
-
- .uk-textarea:-ms-input-placeholder { color: $inverse-form-placeholder-color !important; }
- .uk-textarea::placeholder { color: $inverse-form-placeholder-color; }
-
- //
- // Radio and checkbox
- //
-
- .uk-select:not([multiple]):not([size]) { @include svg-fill($internal-form-select-image, "#000", $inverse-form-select-icon-color); }
-
- //
- // Radio and checkbox
- //
-
- .uk-radio,
- .uk-checkbox {
- background-color: $inverse-form-radio-background;
- @if(mixin-exists(hook-inverse-form-radio)) {@include hook-inverse-form-radio();}
- }
-
- // Focus
- .uk-radio:focus,
- .uk-checkbox:focus {
- @if(mixin-exists(hook-inverse-form-radio-focus)) {@include hook-inverse-form-radio-focus();}
- }
-
- // Checked
- .uk-radio:checked,
- .uk-checkbox:checked,
- .uk-checkbox:indeterminate {
- background-color: $inverse-form-radio-checked-background;
- @if(mixin-exists(hook-inverse-form-radio-checked)) {@include hook-inverse-form-radio-checked();}
- }
-
- // Focus
- .uk-radio:checked:focus,
- .uk-checkbox:checked:focus,
- .uk-checkbox:indeterminate:focus {
- background-color: $inverse-form-radio-checked-focus-background;
- @if(mixin-exists(hook-inverse-form-radio-checked-focus)) {@include hook-inverse-form-radio-checked-focus();}
- }
-
- // Icon
- .uk-radio:checked { @include svg-fill($internal-form-radio-image, "#000", $inverse-form-radio-checked-icon-color); }
- .uk-checkbox:checked { @include svg-fill($internal-form-checkbox-image, "#000", $inverse-form-radio-checked-icon-color); }
- .uk-checkbox:indeterminate { @include svg-fill($internal-form-checkbox-indeterminate-image, "#000", $inverse-form-radio-checked-icon-color); }
-
- // Label
- .uk-form-label {
- @if(mixin-exists(hook-inverse-form-label)) {@include hook-inverse-form-label();}
- }
-
-}
-@mixin hook-grid-misc(){}
-@mixin hook-inverse-component-grid(){
-
- .uk-grid-divider > :not(.uk-first-column)::before { border-left-color: $inverse-grid-divider-border; }
- .uk-grid-divider.uk-grid-stack > .uk-grid-margin::before { border-top-color: $inverse-grid-divider-border; }
-
-}
-@mixin hook-heading-primary(){}
-@mixin hook-heading-hero(){}
-@mixin hook-heading-divider(){}
-@mixin hook-heading-bullet(){}
-@mixin hook-heading-line(){}
-@mixin hook-heading-misc(){}
-@mixin hook-inverse-heading-primary(){}
-@mixin hook-inverse-heading-hero(){}
-@mixin hook-inverse-heading-divider(){}
-@mixin hook-inverse-heading-bullet(){}
-@mixin hook-inverse-heading-line(){}
-@mixin hook-inverse-component-heading(){
-
- .uk-heading-primary {
- @if(mixin-exists(hook-inverse-heading-primary)) {@include hook-inverse-heading-primary();}
- }
-
- .uk-heading-hero {
- @if(mixin-exists(hook-inverse-heading-hero)) {@include hook-inverse-heading-hero();}
- }
-
- .uk-heading-divider {
- border-bottom-color: $inverse-heading-divider-border;
- @if(mixin-exists(hook-inverse-heading-divider)) {@include hook-inverse-heading-divider();}
- }
-
- .uk-heading-bullet::before {
- border-left-color: $inverse-heading-bullet-border;
- @if(mixin-exists(hook-inverse-heading-bullet)) {@include hook-inverse-heading-bullet();}
- }
-
- .uk-heading-line > ::before,
- .uk-heading-line > ::after {
- border-bottom-color: $inverse-heading-line-border;
- @if(mixin-exists(hook-inverse-heading-line)) {@include hook-inverse-heading-line();}
- }
-
-}
-@mixin hook-icon-link(){}
-@mixin hook-icon-link-hover(){}
-@mixin hook-icon-link-active(){}
-@mixin hook-icon-button(){
- transition: 0.1s ease-in-out;
- transition-property: color, background-color
-}
-@mixin hook-icon-button-hover(){}
-@mixin hook-icon-button-active(){}
-@mixin hook-icon-misc(){}
-@mixin hook-inverse-icon-link(){}
-@mixin hook-inverse-icon-link-hover(){}
-@mixin hook-inverse-icon-link-active(){}
-@mixin hook-inverse-icon-button(){}
-@mixin hook-inverse-icon-button-hover(){}
-@mixin hook-inverse-icon-button-active(){}
-@mixin hook-inverse-component-icon(){
-
- //
- // Link
- //
-
- .uk-icon-link {
- color: $inverse-icon-link-color;
- @if(mixin-exists(hook-inverse-icon-link)) {@include hook-inverse-icon-link();}
- }
-
- .uk-icon-link:hover,
- .uk-icon-link:focus {
- color: $inverse-icon-link-hover-color;
- @if(mixin-exists(hook-inverse-icon-link-hover)) {@include hook-inverse-icon-link-hover();}
- }
-
- .uk-icon-link:active,
- .uk-active > .uk-icon-link {
- color: $inverse-icon-link-active-color;
- @if(mixin-exists(hook-inverse-icon-link-active)) {@include hook-inverse-icon-link-active();}
- }
-
- //
- // Button
- //
-
- .uk-icon-button {
- background-color: $inverse-icon-button-background;
- color: $inverse-icon-button-color;
- @if(mixin-exists(hook-inverse-icon-button)) {@include hook-inverse-icon-button();}
- }
-
- .uk-icon-button:hover,
- .uk-icon-button:focus {
- background-color: $inverse-icon-button-hover-background;
- color: $inverse-icon-button-hover-color;
- @if(mixin-exists(hook-inverse-icon-button-hover)) {@include hook-inverse-icon-button-hover();}
- }
-
- .uk-icon-button:active {
- background-color: $inverse-icon-button-active-background;
- color: $inverse-icon-button-active-color;
- @if(mixin-exists(hook-inverse-icon-button-active)) {@include hook-inverse-icon-button-active();}
- }
-
-}
-@mixin hook-iconnav(){}
-@mixin hook-iconnav-item(){}
-@mixin hook-iconnav-item-hover(){}
-@mixin hook-iconnav-item-active(){}
-@mixin hook-iconnav-misc(){}
-@mixin hook-inverse-iconnav-item(){}
-@mixin hook-inverse-iconnav-item-hover(){}
-@mixin hook-inverse-iconnav-item-active(){}
-@mixin hook-inverse-component-iconnav(){
-
- .uk-iconnav > * > a {
- color: $inverse-iconnav-item-color;
- @if(mixin-exists(hook-inverse-iconnav-item)) {@include hook-inverse-iconnav-item();}
- }
-
- .uk-iconnav > * > a:hover,
- .uk-iconnav > * > a:focus {
- color: $inverse-iconnav-item-hover-color;
- @if(mixin-exists(hook-inverse-iconnav-item-hover)) {@include hook-inverse-iconnav-item-hover();}
- }
-
- .uk-iconnav > .uk-active > a {
- color: $inverse-iconnav-item-active-color;
- @if(mixin-exists(hook-inverse-iconnav-item-active)) {@include hook-inverse-iconnav-item-active();}
- }
-
-}
-@mixin hook-inverse-component-link(){
-
- a.uk-link-muted,
- .uk-link-muted a {
- color: $inverse-link-muted-color;
- @if(mixin-exists(hook-inverse-link-muted)) {@include hook-inverse-link-muted();}
- }
-
- a.uk-link-muted:hover,
- .uk-link-muted a:hover {
- color: $inverse-link-muted-hover-color;
- @if(mixin-exists(hook-inverse-link-muted-hover)) {@include hook-inverse-link-muted-hover();}
- }
-
- a.uk-link-text:hover,
- .uk-link-text a:hover {
- color: $inverse-link-text-hover-color;
- @if(mixin-exists(hook-inverse-link-text-hover)) {@include hook-inverse-link-text-hover();}
- }
-
- a.uk-link-heading:hover,
- .uk-link-heading a:hover {
- color: $inverse-link-heading-hover-color;
- @if(mixin-exists(hook-inverse-link-heading-hover)) {@include hook-inverse-link-heading-hover();}
- }
-
-}
-@mixin hook-inverse-component-list(){
-
- .uk-list-divider > li:nth-child(n+2) {
- border-top-color: $inverse-list-divider-border;
- @if(mixin-exists(hook-inverse-list-divider)) {@include hook-inverse-list-divider();}
- }
-
- .uk-list-striped > li {
- @if(mixin-exists(hook-inverse-list-striped)) {@include hook-inverse-list-striped();}
- }
-
- .uk-list-striped > li:nth-of-type(odd) { background-color: $inverse-list-striped-background; }
-
- .uk-list-bullet > li::before {
- @include svg-fill($internal-list-bullet-image, "#000", $inverse-list-bullet-icon-color);
- @if(mixin-exists(hook-inverse-list-bullet)) {@include hook-inverse-list-bullet();}
- }
-
-}
-@mixin hook-inverse-component-totop(){
-
- .uk-totop {
- color: $inverse-totop-color;
- @if(mixin-exists(hook-inverse-totop)) {@include hook-inverse-totop();}
- }
-
- .uk-totop:hover,
- .uk-totop:focus {
- color: $inverse-totop-hover-color;
- @if(mixin-exists(hook-inverse-totop-hover)) {@include hook-inverse-totop-hover();}
- }
-
- .uk-totop:active {
- color: $inverse-totop-active-color;
- @if(mixin-exists(hook-inverse-totop-active)) {@include hook-inverse-totop-active();}
- }
-
-}
-@mixin hook-inverse-component-label(){
-
- .uk-label {
- background-color: $inverse-label-background;
- color: $inverse-label-color;
- @if(mixin-exists(hook-inverse-label)) {@include hook-inverse-label();}
- }
-
-}
-@mixin hook-inverse-component-search(){
-
- //
- // Input
- //
-
- .uk-search-input { color: $inverse-search-color; }
-
- .uk-search-input:-ms-input-placeholder { color: $inverse-search-placeholder-color !important; }
- .uk-search-input::placeholder { color: $inverse-search-placeholder-color; }
-
-
- //
- // Icon
- //
-
- .uk-search .uk-search-icon { color: $inverse-search-icon-color; }
-
- .uk-search .uk-search-icon:hover { color: $inverse-search-icon-color; }
-
- //
- // Style modifier
- //
-
- .uk-search-default .uk-search-input {
- background-color: $inverse-search-default-background;
- @if(mixin-exists(hook-inverse-search-default-input)) {@include hook-inverse-search-default-input();}
- }
- .uk-search-default .uk-search-input:focus {
- background-color: $inverse-search-default-background;
- @if(mixin-exists(hook-inverse-search-default-input-focus)) {@include hook-inverse-search-default-input-focus();}
- }
-
- .uk-search-navbar .uk-search-input {
- background-color: $inverse-search-navbar-background;
- @if(mixin-exists(hook-inverse-search-navbar-input)) {@include hook-inverse-search-navbar-input();}
- }
-
- .uk-search-large .uk-search-input {
- background-color: $inverse-search-large-background;
- @if(mixin-exists(hook-inverse-search-large-input)) {@include hook-inverse-search-large-input();}
- }
-
- //
- // Toggle
- //
-
- .uk-search-toggle {
- color: $inverse-search-toggle-color;
- @if(mixin-exists(hook-inverse-search-toggle)) {@include hook-inverse-search-toggle();}
- }
-
- .uk-search-toggle:hover,
- .uk-search-toggle:focus {
- color: $inverse-search-toggle-hover-color;
- @if(mixin-exists(hook-inverse-search-toggle-hover)) {@include hook-inverse-search-toggle-hover();}
- }
-
-}
-@mixin hook-inverse-component-nav(){
-
- //
- // Parent icon modifier
- //
-
- .uk-nav-parent-icon > .uk-parent > a::after {
- @include svg-fill($internal-nav-parent-close-image, "#000", $inverse-nav-parent-icon-color);
- @if(mixin-exists(hook-inverse-nav-parent-icon)) {@include hook-inverse-nav-parent-icon();}
- }
-
- .uk-nav-parent-icon > .uk-parent.uk-open > a::after { @include svg-fill($internal-nav-parent-open-image, "#000", $inverse-nav-parent-icon-color); }
-
- //
- // Default
- //
-
- .uk-nav-default > li > a {
- color: $inverse-nav-default-item-color;
- @if(mixin-exists(hook-inverse-nav-default-item)) {@include hook-inverse-nav-default-item();}
- }
-
- .uk-nav-default > li > a:hover,
- .uk-nav-default > li > a:focus {
- color: $inverse-nav-default-item-hover-color;
- @if(mixin-exists(hook-inverse-nav-default-item-hover)) {@include hook-inverse-nav-default-item-hover();}
- }
-
- .uk-nav-default > li.uk-active > a {
- color: $inverse-nav-default-item-active-color;
- @if(mixin-exists(hook-inverse-nav-default-item-active)) {@include hook-inverse-nav-default-item-active();}
- }
-
- .uk-nav-default .uk-nav-header {
- color: $inverse-nav-default-header-color;
- @if(mixin-exists(hook-inverse-nav-default-header)) {@include hook-inverse-nav-default-header();}
- }
-
- .uk-nav-default .uk-nav-divider {
- border-top-color: $inverse-nav-default-divider-border;
- @if(mixin-exists(hook-inverse-nav-default-divider)) {@include hook-inverse-nav-default-divider();}
- }
-
- .uk-nav-default .uk-nav-sub a { color: $inverse-nav-default-sublist-item-color; }
-
- .uk-nav-default .uk-nav-sub a:hover,
- .uk-nav-default .uk-nav-sub a:focus { color: $inverse-nav-default-sublist-item-hover-color; }
-
- //
- // Primary
- //
-
- .uk-nav-primary > li > a {
- color: $inverse-nav-primary-item-color;
- @if(mixin-exists(hook-inverse-nav-primary-item)) {@include hook-inverse-nav-primary-item();}
- }
-
- .uk-nav-primary > li > a:hover,
- .uk-nav-primary > li > a:focus {
- color: $inverse-nav-primary-item-hover-color;
- @if(mixin-exists(hook-inverse-nav-primary-item-hover)) {@include hook-inverse-nav-primary-item-hover();}
- }
-
- .uk-nav-primary > li.uk-active > a {
- color: $inverse-nav-primary-item-active-color;
- @if(mixin-exists(hook-inverse-nav-primary-item-active)) {@include hook-inverse-nav-primary-item-active();}
- }
-
- .uk-nav-primary .uk-nav-header {
- color: $inverse-nav-primary-header-color;
- @if(mixin-exists(hook-inverse-nav-primary-header)) {@include hook-inverse-nav-primary-header();}
- }
-
- .uk-nav-primary .uk-nav-divider {
- border-top-color: $inverse-nav-primary-divider-border;
- @if(mixin-exists(hook-inverse-nav-primary-divider)) {@include hook-inverse-nav-primary-divider();}
- }
-
- .uk-nav-primary .uk-nav-sub a { color: $inverse-nav-primary-sublist-item-color; }
-
- .uk-nav-primary .uk-nav-sub a:hover,
- .uk-nav-primary .uk-nav-sub a:focus { color: $inverse-nav-primary-sublist-item-hover-color; }
-
-}
-@mixin hook-inverse-component-navbar(){
-
- .uk-navbar-nav > li > a {
- color: $inverse-navbar-nav-item-color;
- @if(mixin-exists(hook-inverse-navbar-nav-item)) {@include hook-inverse-navbar-nav-item();}
- }
-
- .uk-navbar-nav > li:hover > a,
- .uk-navbar-nav > li > a:focus,
- .uk-navbar-nav > li > a.uk-open {
- color: $inverse-navbar-nav-item-hover-color;
- @if(mixin-exists(hook-inverse-navbar-nav-item-hover)) {@include hook-inverse-navbar-nav-item-hover();}
- }
-
- .uk-navbar-nav > li > a:active {
- color: $inverse-navbar-nav-item-onclick-color;
- @if(mixin-exists(hook-inverse-navbar-nav-item-onclick)) {@include hook-inverse-navbar-nav-item-onclick();}
- }
-
- .uk-navbar-nav > li.uk-active > a {
- color: $inverse-navbar-nav-item-active-color;
- @if(mixin-exists(hook-inverse-navbar-nav-item-active)) {@include hook-inverse-navbar-nav-item-active();}
- }
-
- .uk-navbar-item {
- color: $inverse-navbar-item-color;
- @if(mixin-exists(hook-inverse-navbar-item)) {@include hook-inverse-navbar-item();}
- }
-
- .uk-navbar-toggle {
- color: $inverse-navbar-toggle-color;
- @if(mixin-exists(hook-inverse-navbar-toggle)) {@include hook-inverse-navbar-toggle();}
- }
-
- .uk-navbar-toggle:hover,
- .uk-navbar-toggle:focus,
- .uk-navbar-toggle.uk-open {
- color: $inverse-navbar-toggle-hover-color;
- @if(mixin-exists(hook-inverse-navbar-toggle-hover)) {@include hook-inverse-navbar-toggle-hover();}
- }
-
-}
-@mixin hook-inverse-component-subnav(){
-
- .uk-subnav > * > :first-child {
- color: $inverse-subnav-item-color;
- @if(mixin-exists(hook-inverse-subnav-item)) {@include hook-inverse-subnav-item();}
- }
-
- .uk-subnav > * > a:hover,
- .uk-subnav > * > a:focus {
- color: $inverse-subnav-item-hover-color;
- @if(mixin-exists(hook-inverse-subnav-item-hover)) {@include hook-inverse-subnav-item-hover();}
- }
-
- .uk-subnav > .uk-active > a {
- color: $inverse-subnav-item-active-color;
- @if(mixin-exists(hook-inverse-subnav-item-active)) {@include hook-inverse-subnav-item-active();}
- }
-
- //
- // Divider
- //
-
- .uk-subnav-divider > :nth-child(n+2):not(.uk-first-column)::before {
- border-left-color: $inverse-subnav-divider-border;
- @if(mixin-exists(hook-inverse-subnav-divider)) {@include hook-inverse-subnav-divider();}
- }
-
- //
- // Pill
- //
-
- .uk-subnav-pill > * > :first-child {
- background-color: $inverse-subnav-pill-item-background;
- color: $inverse-subnav-pill-item-color;
- @if(mixin-exists(hook-inverse-subnav-pill-item)) {@include hook-inverse-subnav-pill-item();}
- }
-
- .uk-subnav-pill > * > a:hover,
- .uk-subnav-pill > * > a:focus {
- background-color: $inverse-subnav-pill-item-hover-background;
- color: $inverse-subnav-pill-item-hover-color;
- @if(mixin-exists(hook-inverse-subnav-pill-item-hover)) {@include hook-inverse-subnav-pill-item-hover();}
- }
-
- .uk-subnav-pill > * > a:active {
- background-color: $inverse-subnav-pill-item-onclick-background;
- color: $inverse-subnav-pill-item-onclick-color;
- @if(mixin-exists(hook-inverse-subnav-pill-item-onclick)) {@include hook-inverse-subnav-pill-item-onclick();}
- }
-
- .uk-subnav-pill > .uk-active > a {
- background-color: $inverse-subnav-pill-item-active-background;
- color: $inverse-subnav-pill-item-active-color;
- @if(mixin-exists(hook-inverse-subnav-pill-item-active)) {@include hook-inverse-subnav-pill-item-active();}
- }
-
- //
- // Disabled
- //
-
- .uk-subnav > .uk-disabled > a {
- color: $inverse-subnav-item-disabled-color;
- @if(mixin-exists(hook-inverse-subnav-item-disabled)) {@include hook-inverse-subnav-item-disabled();}
- }
-
-}
-@mixin hook-inverse-component-pagination(){
-
- .uk-pagination > * > * {
- color: $inverse-pagination-item-color;
- @if(mixin-exists(hook-inverse-pagination-item)) {@include hook-inverse-pagination-item();}
- }
-
- .uk-pagination > * > :hover,
- .uk-pagination > * > :focus {
- color: $inverse-pagination-item-hover-color;
- @if(mixin-exists(hook-inverse-pagination-item-hover)) {@include hook-inverse-pagination-item-hover();}
- }
-
- .uk-pagination > .uk-active > * {
- color: $inverse-pagination-item-active-color;
- @if(mixin-exists(hook-inverse-pagination-item-active)) {@include hook-inverse-pagination-item-active();}
- }
-
- .uk-pagination > .uk-disabled > * {
- color: $inverse-pagination-item-disabled-color;
- @if(mixin-exists(hook-inverse-pagination-item-disabled)) {@include hook-inverse-pagination-item-disabled();}
- }
-
-}
-@mixin hook-inverse-component-tab(){
-
- .uk-tab {
- @if(mixin-exists(hook-inverse-tab)) {@include hook-inverse-tab();}
- }
-
- .uk-tab > * > a {
- color: $inverse-tab-item-color;
- @if(mixin-exists(hook-inverse-tab-item)) {@include hook-inverse-tab-item();}
- }
-
- .uk-tab > * > a:hover,
- .uk-tab > * > a:focus{
- color: $inverse-tab-item-hover-color;
- @if(mixin-exists(hook-inverse-tab-item-hover)) {@include hook-inverse-tab-item-hover();}
- }
-
- .uk-tab > .uk-active > a {
- color: $inverse-tab-item-active-color;
- @if(mixin-exists(hook-inverse-tab-item-active)) {@include hook-inverse-tab-item-active();}
- }
-
- .uk-tab > .uk-disabled > a {
- color: $inverse-tab-item-disabled-color;
- @if(mixin-exists(hook-inverse-tab-item-disabled)) {@include hook-inverse-tab-item-disabled();}
- }
-
-}
-@mixin hook-inverse-component-slidenav(){
-
- .uk-slidenav {
- color: $inverse-slidenav-color;
- @if(mixin-exists(hook-inverse-slidenav)) {@include hook-inverse-slidenav();}
- }
-
- .uk-slidenav:hover,
- .uk-slidenav:focus {
- color: $inverse-slidenav-hover-color;
- @if(mixin-exists(hook-inverse-slidenav-hover)) {@include hook-inverse-slidenav-hover();}
- }
-
- .uk-slidenav:active {
- color: $inverse-slidenav-active-color;
- @if(mixin-exists(hook-inverse-slidenav-active)) {@include hook-inverse-slidenav-active();}
- }
-
-}
-@mixin hook-inverse-component-text(){
-
- .uk-text-lead {
- color: $inverse-text-lead-color;
- @if(mixin-exists(hook-inverse-text-lead)) {@include hook-inverse-text-lead();}
- }
-
- .uk-text-meta {
- color: $inverse-text-meta-color;
- @if(mixin-exists(hook-inverse-text-meta)) {@include hook-inverse-text-meta();}
- }
-
- .uk-text-muted { color: $inverse-text-muted-color !important; }
- .uk-text-primary { color: $inverse-text-primary-color !important; }
-
-}
-@mixin hook-inverse-component-utility(){
-
- .uk-dropcap::first-letter,
- .uk-dropcap p:first-of-type::first-letter {
- @if(mixin-exists(hook-inverse-dropcap)) {@include hook-inverse-dropcap();}
- }
-
- .uk-leader-fill {
- @if(mixin-exists(hook-inverse-leader)) {@include hook-inverse-leader();}
- }
-
- .uk-logo {
- color: $inverse-logo-color;
- @if(mixin-exists(hook-inverse-logo)) {@include hook-inverse-logo();}
- }
-
- .uk-logo:hover,
- .uk-logo:focus {
- color: $inverse-logo-hover-color;
- @if(mixin-exists(hook-inverse-logo-hover)) {@include hook-inverse-logo-hover();}
- }
-
- .uk-logo > :not(.uk-logo-inverse):not(:only-of-type) { display: none; }
- .uk-logo-inverse { display: inline; }
-
-}
-@mixin hook-inverse(){
- @include hook-inverse-component-base();
- @include hook-inverse-component-link();
- @include hook-inverse-component-heading();
- @include hook-inverse-component-divider();
- @include hook-inverse-component-list();
- @include hook-inverse-component-icon();
- @include hook-inverse-component-form();
- @include hook-inverse-component-button();
- @include hook-inverse-component-grid();
- @include hook-inverse-component-close();
- @include hook-inverse-component-totop();
- @include hook-inverse-component-badge();
- @include hook-inverse-component-label();
- @include hook-inverse-component-article();
- @include hook-inverse-component-search();
- @include hook-inverse-component-nav();
- @include hook-inverse-component-navbar();
- @include hook-inverse-component-subnav();
- @include hook-inverse-component-breadcrumb();
- @include hook-inverse-component-pagination();
- @include hook-inverse-component-tab();
- @include hook-inverse-component-slidenav();
- @include hook-inverse-component-dotnav();
- @include hook-inverse-component-accordion();
- @include hook-inverse-component-iconnav();
- @include hook-inverse-component-text();
- @include hook-inverse-component-column();
- @include hook-inverse-component-utility();
-}
-@mixin hook-label(){
- border-radius: $label-border-radius;
- text-transform: $label-text-transform;
-}
-@mixin hook-label-success(){}
-@mixin hook-label-warning(){}
-@mixin hook-label-danger(){}
-@mixin hook-label-misc(){}
-@mixin hook-inverse-label(){}
-@mixin hook-lightbox(){}
-@mixin hook-lightbox-item(){}
-@mixin hook-lightbox-toolbar(){}
-@mixin hook-lightbox-toolbar-icon(){}
-@mixin hook-lightbox-toolbar-icon-hover(){}
-@mixin hook-lightbox-button(){}
-@mixin hook-lightbox-button-hover(){}
-@mixin hook-lightbox-misc(){}
-@mixin hook-link-muted(){}
-@mixin hook-link-muted-hover(){}
-@mixin hook-link-text(){}
-@mixin hook-link-text-hover(){}
-@mixin hook-link-heading(){}
-@mixin hook-link-heading-hover(){}
-@mixin hook-link-reset(){}
-@mixin hook-link-misc(){}
-@mixin hook-inverse-link-muted(){}
-@mixin hook-inverse-link-muted-hover(){}
-@mixin hook-inverse-link-text-hover(){}
-@mixin hook-inverse-link-heading-hover(){}
-@mixin hook-list-divider(){}
-@mixin hook-list-striped(){
-
- &:nth-of-type(odd) {
- border-top: $list-striped-border-width solid $list-striped-border;
- border-bottom: $list-striped-border-width solid $list-striped-border;
- }
-
-}
-@mixin hook-list-bullet(){}
-@mixin hook-list-misc(){}
-@mixin hook-inverse-list-divider(){}
-@mixin hook-inverse-list-striped(){
-
- &:nth-of-type(odd) {
- border-top-color: $inverse-global-border;
- border-bottom-color: $inverse-global-border;
- }
-
-}
-@mixin hook-inverse-list-bullet(){}
-@mixin hook-margin-misc(){}
-@mixin hook-marker(){
- border-radius: 500px;
-}
-@mixin hook-marker-hover(){}
-@mixin hook-marker-misc(){}
-@mixin hook-inverse-marker(){}
-@mixin hook-inverse-marker-hover(){}
-@mixin hook-inverse-component-marker(){
-
- .uk-marker {
- background: $inverse-marker-background;
- color: $inverse-marker-color;
- @if(mixin-exists(hook-inverse-marker)) {@include hook-inverse-marker();}
- }
-
- .uk-marker:hover,
- .uk-marker:focus {
- color: $inverse-marker-hover-color;
- @if(mixin-exists(hook-inverse-marker-hover)) {@include hook-inverse-marker-hover();}
- }
-
-}
-@mixin hook-modal(){}
-@mixin hook-modal-dialog(){}
-@mixin hook-modal-full(){}
-@mixin hook-modal-body(){}
-@mixin hook-modal-header(){ border-bottom: $modal-header-border-width solid $modal-header-border; }
-@mixin hook-modal-footer(){ border-top: $modal-footer-border-width solid $modal-footer-border; }
-@mixin hook-modal-title(){}
-@mixin hook-modal-close(){}
-@mixin hook-modal-close-hover(){}
-@mixin hook-modal-close-default(){}
-@mixin hook-modal-close-default-hover(){}
-@mixin hook-modal-close-outside(){}
-@mixin hook-modal-close-outside-hover(){}
-@mixin hook-modal-close-full(){
- top: 0;
- right: 0;
- padding: $modal-close-full-padding;
- background: $modal-close-full-background;
-}
-@mixin hook-modal-close-full-hover(){}
-@mixin hook-modal-misc(){}
-@mixin hook-nav-sub(){}
-@mixin hook-nav-parent-icon(){}
-@mixin hook-nav-header(){}
-@mixin hook-nav-divider(){}
-@mixin hook-nav-default(){ font-size: $nav-default-font-size; }
-@mixin hook-nav-default-item(){}
-@mixin hook-nav-default-item-hover(){}
-@mixin hook-nav-default-item-active(){}
-@mixin hook-nav-default-header(){}
-@mixin hook-nav-default-divider(){}
-@mixin hook-nav-primary(){}
-@mixin hook-nav-primary-item(){}
-@mixin hook-nav-primary-item-hover(){}
-@mixin hook-nav-primary-item-active(){}
-@mixin hook-nav-primary-header(){}
-@mixin hook-nav-primary-divider(){}
-@mixin hook-nav-misc(){}
-@mixin hook-inverse-nav-parent-icon(){}
-@mixin hook-inverse-nav-default-item(){}
-@mixin hook-inverse-nav-default-item-hover(){}
-@mixin hook-inverse-nav-default-item-active(){}
-@mixin hook-inverse-nav-default-header(){}
-@mixin hook-inverse-nav-default-divider(){}
-@mixin hook-inverse-nav-primary-item(){}
-@mixin hook-inverse-nav-primary-item-hover(){}
-@mixin hook-inverse-nav-primary-item-active(){}
-@mixin hook-inverse-nav-primary-header(){}
-@mixin hook-inverse-nav-primary-divider(){}
-@mixin hook-navbar(){}
-@mixin hook-navbar-container(){}
-@mixin hook-navbar-nav-item(){
- text-transform: $navbar-nav-item-text-transform;
- transition: 0.1s ease-in-out;
- transition-property: color, background-color;
-}
-@mixin hook-navbar-nav-item-hover(){}
-@mixin hook-navbar-nav-item-onclick(){}
-@mixin hook-navbar-nav-item-active(){}
-@mixin hook-navbar-item(){}
-@mixin hook-navbar-toggle(){}
-@mixin hook-navbar-toggle-hover(){}
-@mixin hook-navbar-toggle-icon(){}
-@mixin hook-navbar-toggle-icon-hover(){}
-@mixin hook-navbar-subtitle(){}
-@mixin hook-navbar-transparent(){}
-@mixin hook-navbar-sticky(){}
-@mixin hook-navbar-dropdown(){ box-shadow: $navbar-dropdown-box-shadow; }
-@mixin hook-navbar-dropdown-dropbar(){ box-shadow: none; }
-@mixin hook-navbar-dropdown-nav(){ font-size: $navbar-dropdown-nav-font-size; }
-@mixin hook-navbar-dropdown-nav-item(){}
-@mixin hook-navbar-dropdown-nav-item-hover(){}
-@mixin hook-navbar-dropdown-nav-item-active(){}
-@mixin hook-navbar-dropdown-nav-header(){}
-@mixin hook-navbar-dropdown-nav-divider(){}
-@mixin hook-navbar-dropbar(){}
-@mixin hook-navbar-dropbar-slide(){ box-shadow: $navbar-dropbar-box-shadow; }
-@mixin hook-navbar-misc(){
-
- /*
- * Navbar
- */
-
- .uk-navbar-container > .uk-container .uk-navbar-left {
- margin-left: (-$navbar-nav-item-padding-horizontal);
- margin-right: (-$navbar-nav-item-padding-horizontal);
- }
- .uk-navbar-container > .uk-container .uk-navbar-right { margin-right: (-$navbar-nav-item-padding-horizontal); }
-
- /*
- * Grid Divider
- */
-
- .uk-navbar-dropdown-grid > * { position: relative; }
-
- .uk-navbar-dropdown-grid > :not(.uk-first-column)::before {
- content: "";
- position: absolute;
- top: 0;
- bottom: 0;
- left: ($navbar-dropdown-grid-gutter-horizontal / 2);
- border-left: $navbar-dropdown-grid-divider-border-width solid $navbar-dropdown-grid-divider-border;
- }
-
- /* Vertical */
- .uk-navbar-dropdown-grid.uk-grid-stack > .uk-grid-margin::before {
- content: "";
- position: absolute;
- top: -($navbar-dropdown-grid-gutter-vertical / 2);
- left: $navbar-dropdown-grid-gutter-horizontal;
- right: 0;
- border-top: $navbar-dropdown-grid-divider-border-width solid $navbar-dropdown-grid-divider-border;
- }
-
-}
-@mixin hook-inverse-navbar-nav-item(){}
-@mixin hook-inverse-navbar-nav-item-hover(){}
-@mixin hook-inverse-navbar-nav-item-onclick(){}
-@mixin hook-inverse-navbar-nav-item-active(){}
-@mixin hook-inverse-navbar-item(){}
-@mixin hook-inverse-navbar-toggle(){}
-@mixin hook-inverse-navbar-toggle-hover(){}
-@mixin hook-notification(){}
-@mixin hook-notification-message(){}
-@mixin hook-notification-close(){}
-@mixin hook-notification-message-primary(){}
-@mixin hook-notification-message-success(){}
-@mixin hook-notification-message-warning(){}
-@mixin hook-notification-message-danger(){}
-@mixin hook-notification-misc(){}
-@mixin hook-offcanvas-bar(){}
-@mixin hook-offcanvas-close(){}
-@mixin hook-offcanvas-overlay(){}
-@mixin hook-offcanvas-misc(){}
-@mixin hook-overlay(){}
-@mixin hook-overlay-icon(){}
-@mixin hook-overlay-default(){}
-@mixin hook-overlay-primary(){}
-@mixin hook-overlay-misc(){}
-@mixin hook-padding-misc(){}
-@mixin hook-pagination(){}
-@mixin hook-pagination-item(){ transition: color 0.1s ease-in-out; }
-@mixin hook-pagination-item-hover(){}
-@mixin hook-pagination-item-active(){}
-@mixin hook-pagination-item-disabled(){}
-@mixin hook-pagination-misc(){}
-@mixin hook-inverse-pagination-item(){}
-@mixin hook-inverse-pagination-item-hover(){}
-@mixin hook-inverse-pagination-item-active(){}
-@mixin hook-inverse-pagination-item-disabled(){}
-@mixin hook-placeholder(){ border: $placeholder-border-width dashed $placeholder-border; }
-@mixin hook-placeholder-misc(){}
-@mixin hook-position-misc(){}
-@mixin hook-print(){}
-@mixin hook-progress(){
- border-radius: $progress-border-radius;
- overflow: hidden;
-}
-@mixin hook-progress-bar(){}
-@mixin hook-progress-misc(){}
-@mixin hook-search-input(){}
-@mixin hook-search-default-input(){ border: $search-default-border-width solid $search-default-border; }
-@mixin hook-search-default-input-focus(){}
-@mixin hook-search-navbar-input(){}
-@mixin hook-search-large-input(){}
-@mixin hook-search-toggle(){}
-@mixin hook-search-toggle-hover(){}
-@mixin hook-search-misc(){}
-@mixin hook-inverse-search-default-input(){ border-color: $inverse-global-border; }
-@mixin hook-inverse-search-default-input-focus(){}
-@mixin hook-inverse-search-navbar-input(){}
-@mixin hook-inverse-search-large-input(){}
-@mixin hook-inverse-search-toggle(){}
-@mixin hook-inverse-search-toggle-hover(){}
-@mixin hook-section(){}
-@mixin hook-section-default(){}
-@mixin hook-section-muted(){}
-@mixin hook-section-primary(){}
-@mixin hook-section-secondary(){}
-@mixin hook-section-overlap(){}
-@mixin hook-section-misc(){}
-@mixin hook-slidenav(){ transition: color 0.1s ease-in-out; }
-@mixin hook-slidenav-hover(){}
-@mixin hook-slidenav-active(){}
-@mixin hook-slidenav-previous(){}
-@mixin hook-slidenav-next(){}
-@mixin hook-slidenav-large(){}
-@mixin hook-slidenav-container(){}
-@mixin hook-slidenav-misc(){}
-@mixin hook-inverse-slidenav(){}
-@mixin hook-inverse-slidenav-hover(){}
-@mixin hook-inverse-slidenav-active(){}
-@mixin hook-slider(){}
-@mixin hook-slider-misc(){}
-@mixin hook-slideshow(){}
-@mixin hook-slideshow-misc(){}
-@mixin hook-sortable(){}
-@mixin hook-sortable-drag(){}
-@mixin hook-sortable-placeholder(){}
-@mixin hook-sortable-empty(){}
-@mixin hook-sortable-misc(){}
-@mixin hook-spinner(){}
-@mixin hook-spinner-misc(){}
-@mixin hook-sticky-misc(){}
-@mixin hook-subnav(){}
-@mixin hook-subnav-item(){
- font-size: $subnav-item-font-size;
- text-transform: $subnav-item-text-transform;
- transition: 0.1s ease-in-out;
- transition-property: color, background-color;
-}
-@mixin hook-subnav-item-hover(){}
-@mixin hook-subnav-item-active(){}
-@mixin hook-subnav-divider(){}
-@mixin hook-subnav-pill-item(){}
-@mixin hook-subnav-pill-item-hover(){}
-@mixin hook-subnav-pill-item-onclick(){}
-@mixin hook-subnav-pill-item-active(){}
-@mixin hook-subnav-item-disabled(){}
-@mixin hook-subnav-misc(){}
-@mixin hook-inverse-subnav-item(){}
-@mixin hook-inverse-subnav-item-hover(){}
-@mixin hook-inverse-subnav-item-active(){}
-@mixin hook-inverse-subnav-divider(){}
-@mixin hook-inverse-subnav-pill-item(){}
-@mixin hook-inverse-subnav-pill-item-hover(){}
-@mixin hook-inverse-subnav-pill-item-onclick(){}
-@mixin hook-inverse-subnav-pill-item-active(){}
-@mixin hook-inverse-subnav-item-disabled(){}
-@mixin hook-switcher-misc(){}
-@mixin hook-tab(){
-
- position: relative;
-
- &::before {
- content: "";
- position: absolute;
- bottom: 0;
- left: $tab-margin-horizontal;
- right: 0;
- border-bottom: $tab-border-width solid $tab-border;
- }
-
-}
-@mixin hook-tab-item(){
- border-bottom: $tab-item-border-width solid transparent;
- font-size: $tab-item-font-size;
- text-transform: $tab-item-text-transform;
- transition: color 0.1s ease-in-out;
-}
-@mixin hook-tab-item-hover(){}
-@mixin hook-tab-item-active(){ border-color: $tab-item-active-border; }
-@mixin hook-tab-item-disabled(){}
-@mixin hook-tab-bottom(){
-
- &::before {
- top: 0;
- bottom: auto;
- }
-
-}
-@mixin hook-tab-bottom-item(){
- border-top: $tab-item-border-width solid transparent;
- border-bottom: none;
-}
-@mixin hook-tab-left(){
-
- &::before {
- top: 0;
- bottom: 0;
- left: auto;
- right: 0;
- border-left: $tab-border-width solid $tab-border;
- border-bottom: none;
- }
-
-}
-@mixin hook-tab-right(){
-
- &::before {
- top: 0;
- bottom: 0;
- left: 0;
- right: auto;
- border-left: $tab-border-width solid $tab-border;
- border-bottom: none;
- }
-
-}
-@mixin hook-tab-left-item(){
- border-right: $tab-item-border-width solid transparent;
- border-bottom: none;
-}
-@mixin hook-tab-right-item(){
- border-left: $tab-item-border-width solid transparent;
- border-bottom: none;
-}
-@mixin hook-tab-misc(){
-
- .uk-tab .uk-dropdown { margin-left: ($tab-margin-horizontal + $tab-item-padding-horizontal) }
-
-}
-@mixin hook-inverse-tab(){
-
- &::before { border-color: $inverse-tab-border; }
-
-}
-@mixin hook-inverse-tab-item(){}
-@mixin hook-inverse-tab-item-hover(){}
-@mixin hook-inverse-tab-item-active(){ border-color: $inverse-global-primary-background; }
-@mixin hook-inverse-tab-item-disabled(){}
-@mixin hook-table(){}
-@mixin hook-table-header-cell(){ text-transform: uppercase; }
-@mixin hook-table-cell(){}
-@mixin hook-table-footer(){}
-@mixin hook-table-caption(){}
-@mixin hook-table-row-active(){}
-@mixin hook-table-divider(){}
-@mixin hook-table-striped(){
- border-top: $table-striped-border-width solid $table-striped-border;
- border-bottom: $table-striped-border-width solid $table-striped-border;
-}
-@mixin hook-table-hover(){}
-@mixin hook-table-small(){}
-@mixin hook-table-large(){}
-@mixin hook-table-misc(){
-
- .uk-table tbody tr { transition: background-color 0.1s linear; }
-
-}
-@mixin hook-inverse-table-header-cell(){}
-@mixin hook-inverse-table-caption(){}
-@mixin hook-inverse-table-row-active(){}
-@mixin hook-inverse-table-divider(){}
-@mixin hook-inverse-table-striped(){
- border-top-color: $inverse-global-border;
- border-bottom-color: $inverse-global-border;
-}
-@mixin hook-inverse-table-hover(){}
-@mixin hook-inverse-component-table(){
-
- .uk-table th {
- color: $inverse-table-header-cell-color;
- @if(mixin-exists(hook-inverse-table-header-cell)) {@include hook-inverse-table-header-cell();}
- }
-
- .uk-table caption {
- color: $inverse-table-caption-color;
- @if(mixin-exists(hook-inverse-table-caption)) {@include hook-inverse-table-caption();}
- }
-
- .uk-table > tr.uk-active,
- .uk-table tbody tr.uk-active {
- background: $inverse-table-row-active-background;
- @if(mixin-exists(hook-inverse-table-row-active)) {@include hook-inverse-table-row-active();}
- }
-
- .uk-table-divider > tr:not(:first-child),
- .uk-table-divider > :not(:first-child) > tr,
- .uk-table-divider > :first-child > tr:not(:first-child) {
- border-top-color: $inverse-table-divider-border;
- @if(mixin-exists(hook-inverse-table-divider)) {@include hook-inverse-table-divider();}
- }
-
- .uk-table-striped > tr:nth-of-type(odd),
- .uk-table-striped tbody tr:nth-of-type(odd) {
- background: $inverse-table-striped-row-background;
- @if(mixin-exists(hook-inverse-table-striped)) {@include hook-inverse-table-striped();}
- }
-
- .uk-table-hover > tr:hover,
- .uk-table-hover tbody tr:hover {
- background: $inverse-table-hover-row-background;
- @if(mixin-exists(hook-inverse-table-hover)) {@include hook-inverse-table-hover();}
- }
-
-}
-@mixin hook-text-lead(){}
-@mixin hook-text-meta(){
-
- a { color: $text-meta-link-color; }
-
- a:hover {
- color: $text-meta-link-hover-color;
- text-decoration: none;
- }
-
-}
-@mixin hook-text-small(){}
-@mixin hook-text-large(){}
-@mixin hook-text-background(){}
-@mixin hook-text-misc(){}
-@mixin hook-inverse-text-lead(){}
-@mixin hook-inverse-text-meta(){}
-@mixin hook-thumbnav(){}
-@mixin hook-thumbnav-item(){
-
- position: relative;
-
- &::after {
- content: "";
- position: absolute;
- top: 0;
- bottom: 0;
- left: 0;
- right: 0;
- background: $thumbnav-item-background;
- transition: background-color 0.1s ease-in-out;
- }
-
-}
-@mixin hook-thumbnav-item-hover(){
- &::after { background-color: $thumbnav-item-hover-background; }
-}
-@mixin hook-thumbnav-item-active(){
- &::after { background-color: $thumbnav-item-active-background; }
-}
-@mixin hook-thumbnav-misc(){}
-@mixin hook-inverse-thumbnav-item(){}
-@mixin hook-inverse-thumbnav-item-hover(){}
-@mixin hook-inverse-thumbnav-item-active(){}
-@mixin hook-inverse-component-thumbnav(){
-
- .uk-thumbnav > * > * {
- @if(mixin-exists(hook-inverse-thumbnav-item)) {@include hook-inverse-thumbnav-item();}
- }
-
- .uk-thumbnav > * > :hover,
- .uk-thumbnav > * > :focus {
- @if(mixin-exists(hook-inverse-thumbnav-item-hover)) {@include hook-inverse-thumbnav-item-hover();}
- }
-
- .uk-thumbnav > .uk-active > * {
- @if(mixin-exists(hook-inverse-thumbnav-item-active)) {@include hook-inverse-thumbnav-item-active();}
- }
-
-}
-@mixin hook-tile(){}
-@mixin hook-tile-default(){}
-@mixin hook-tile-muted(){}
-@mixin hook-tile-primary(){}
-@mixin hook-tile-secondary(){}
-@mixin hook-tile-misc(){}
-@mixin hook-tooltip(){}
-@mixin hook-tooltip-misc(){}
-@mixin hook-totop(){ transition: color 0.1s ease-in-out; }
-@mixin hook-totop-hover(){}
-@mixin hook-totop-active(){}
-@mixin hook-totop-misc(){}
-@mixin hook-inverse-totop(){}
-@mixin hook-inverse-totop-hover(){}
-@mixin hook-inverse-totop-active(){}
-@mixin hook-transition-misc(){}
-@mixin hook-panel-scrollable(){}
-@mixin hook-box-shadow-bottom(){}
-@mixin hook-dropcap(){
- // Prevent line wrap
- margin-bottom: -2px;
-}
-@mixin hook-leader(){}
-@mixin hook-logo(){}
-@mixin hook-logo-hover(){}
-@mixin hook-utility-misc(){}
-@mixin hook-inverse-dropcap(){}
-@mixin hook-inverse-leader(){}
-@mixin hook-inverse-logo(){}
-@mixin hook-inverse-logo-hover(){}
-@mixin hook-visibility-misc(){}
-@mixin hook-width-misc(){}
\ No newline at end of file
diff --git a/_sass/uikit/mixins.scss b/_sass/uikit/mixins.scss
deleted file mode 100644
index 573b2f37f7..0000000000
--- a/_sass/uikit/mixins.scss
+++ /dev/null
@@ -1,1644 +0,0 @@
-@mixin hook-accordion(){}
-@mixin hook-accordion-item(){}
-@mixin hook-accordion-title(){}
-@mixin hook-accordion-title-hover(){}
-@mixin hook-accordion-content(){}
-@mixin hook-accordion-misc(){}
-@mixin hook-inverse-accordion-item(){}
-@mixin hook-inverse-accordion-title(){}
-@mixin hook-inverse-accordion-title-hover(){}
-@mixin hook-inverse-component-accordion(){
-
- .uk-accordion > :nth-child(n+2) {
- @if(mixin-exists(hook-inverse-accordion-item)) {@include hook-inverse-accordion-item();}
- }
-
- .uk-accordion-title {
- color: $inverse-accordion-title-color;
- @if(mixin-exists(hook-inverse-accordion-title)) {@include hook-inverse-accordion-title();}
- }
-
- .uk-accordion-title:hover,
- .uk-accordion-title:focus {
- color: $inverse-accordion-title-hover-color;
- @if(mixin-exists(hook-inverse-accordion-title-hover)) {@include hook-inverse-accordion-title-hover();}
- }
-
-}
-@mixin hook-align-misc(){}
-@mixin hook-alert(){}
-@mixin hook-alert-close(){}
-@mixin hook-alert-close-hover(){}
-@mixin hook-alert-primary(){}
-@mixin hook-alert-success(){}
-@mixin hook-alert-warning(){}
-@mixin hook-alert-danger(){}
-@mixin hook-alert-misc(){}
-@mixin hook-article(){}
-@mixin hook-article-adjacent(){}
-@mixin hook-article-title(){}
-@mixin hook-article-meta(){}
-@mixin hook-article-misc(){}
-@mixin hook-inverse-article-title(){}
-@mixin hook-inverse-article-meta(){}
-@mixin hook-inverse-component-article(){
-
- .uk-article-title {
- @if(mixin-exists(hook-inverse-article-title)) {@include hook-inverse-article-title();}
- }
-
- .uk-article-meta {
- color: $inverse-article-meta-color;
- @if(mixin-exists(hook-inverse-article-meta)) {@include hook-inverse-article-meta();}
- }
-
-}
-@mixin hook-animation-misc(){}
-@mixin hook-background-misc(){}
-@mixin hook-badge(){}
-@mixin hook-badge-hover(){}
-@mixin hook-badge-misc(){}
-@mixin hook-inverse-badge(){}
-@mixin hook-inverse-badge-hover(){}
-@mixin hook-inverse-component-badge(){
-
- .uk-badge {
- background-color: $inverse-badge-background;
- color: $inverse-badge-color;
- @if(mixin-exists(hook-inverse-badge)) {@include hook-inverse-badge();}
- }
-
- .uk-badge:hover,
- .uk-badge:focus {
- color: $inverse-badge-hover-color;
- @if(mixin-exists(hook-inverse-badge-hover)) {@include hook-inverse-badge-hover();}
- }
-
-}
-@mixin hook-base-body(){}
-@mixin hook-base-link(){}
-@mixin hook-base-link-hover(){}
-@mixin hook-base-code(){}
-@mixin hook-base-heading(){}
-@mixin hook-base-h1(){}
-@mixin hook-base-h2(){}
-@mixin hook-base-h3(){}
-@mixin hook-base-h4(){}
-@mixin hook-base-h5(){}
-@mixin hook-base-h6(){}
-@mixin hook-base-hr(){}
-@mixin hook-base-blockquote(){}
-@mixin hook-base-blockquote-footer(){}
-@mixin hook-base-pre(){}
-@mixin hook-base-misc(){}
-@mixin hook-inverse-base-link(){}
-@mixin hook-inverse-base-link-hover(){}
-@mixin hook-inverse-base-code(){}
-@mixin hook-inverse-base-heading(){}
-@mixin hook-inverse-base-h1(){}
-@mixin hook-inverse-base-h2(){}
-@mixin hook-inverse-base-h3(){}
-@mixin hook-inverse-base-h4(){}
-@mixin hook-inverse-base-h5(){}
-@mixin hook-inverse-base-h6(){}
-@mixin hook-inverse-base-blockquote(){}
-@mixin hook-inverse-base-blockquote-footer(){}
-@mixin hook-inverse-base-hr(){}
-@mixin hook-inverse-component-base(){
-
- color: $inverse-base-color;
-
- // Base
- // ========================================================================
-
- //
- // Link
- //
-
- a,
- .uk-link {
- color: $inverse-base-link-color;
- @if(mixin-exists(hook-inverse-base-link)) {@include hook-inverse-base-link();}
- }
-
- a:hover,
- .uk-link:hover {
- color: $inverse-base-link-hover-color;
- @if(mixin-exists(hook-inverse-base-link-hover)) {@include hook-inverse-base-link-hover();}
- }
-
- //
- // Code
- //
-
- :not(pre) > code,
- :not(pre) > kbd,
- :not(pre) > samp {
- color: $inverse-base-code-color;
- @if(mixin-exists(hook-inverse-base-code)) {@include hook-inverse-base-code();}
- }
-
- //
- // Emphasize
- //
-
- em { color: $inverse-base-em-color; }
-
- //
- // Headings
- //
-
- h1, .uk-h1,
- h2, .uk-h2,
- h3, .uk-h3,
- h4, .uk-h4,
- h5, .uk-h5,
- h6, .uk-h6 {
- color: $inverse-base-heading-color;
- @if(mixin-exists(hook-inverse-base-heading)) {@include hook-inverse-base-heading();}
- }
-
- h1, .uk-h1 {
- @if(mixin-exists(hook-inverse-base-h1)) {@include hook-inverse-base-h1();}
- }
-
- h2, .uk-h2 {
- @if(mixin-exists(hook-inverse-base-h2)) {@include hook-inverse-base-h2();}
- }
-
- h3, .uk-h3 {
- @if(mixin-exists(hook-inverse-base-h3)) {@include hook-inverse-base-h3();}
- }
-
- h4, .uk-h4 {
- @if(mixin-exists(hook-inverse-base-h4)) {@include hook-inverse-base-h4();}
- }
-
- h5, .uk-h5 {
- @if(mixin-exists(hook-inverse-base-h5)) {@include hook-inverse-base-h5();}
- }
-
- h6, .uk-h6 {
- @if(mixin-exists(hook-inverse-base-h6)) {@include hook-inverse-base-h6();}
- }
-
- //
- // Blockquotes
- //
-
- blockquote {
- @if(mixin-exists(hook-inverse-base-blockquote)) {@include hook-inverse-base-blockquote();}
- }
-
- blockquote footer {
- @if(mixin-exists(hook-inverse-base-blockquote-footer)) {@include hook-inverse-base-blockquote-footer();}
- }
-
- //
- // Horizontal rules
- //
-
- hr, .uk-hr {
- border-top-color: $inverse-base-hr-border;
- @if(mixin-exists(hook-inverse-base-hr)) {@include hook-inverse-base-hr();}
- }
-
-}
-@mixin hook-breadcrumb(){}
-@mixin hook-breadcrumb-item(){}
-@mixin hook-breadcrumb-item-hover(){}
-@mixin hook-breadcrumb-item-disabled(){}
-@mixin hook-breadcrumb-item-active(){}
-@mixin hook-breadcrumb-divider(){}
-@mixin hook-breadcrumb-misc(){}
-@mixin hook-inverse-breadcrumb-item(){}
-@mixin hook-inverse-breadcrumb-item-hover(){}
-@mixin hook-inverse-breadcrumb-item-disabled(){}
-@mixin hook-inverse-breadcrumb-item-active(){}
-@mixin hook-inverse-breadcrumb-divider(){}
-@mixin hook-inverse-component-breadcrumb(){
-
- .uk-breadcrumb > * > * {
- color: $inverse-breadcrumb-item-color;
- @if(mixin-exists(hook-inverse-breadcrumb-item)) {@include hook-inverse-breadcrumb-item();}
- }
-
- .uk-breadcrumb > * > :hover,
- .uk-breadcrumb > * > :focus {
- color: $inverse-breadcrumb-item-hover-color;
- @if(mixin-exists(hook-inverse-breadcrumb-item-hover)) {@include hook-inverse-breadcrumb-item-hover();}
- }
-
-
- .uk-breadcrumb > .uk-disabled > * {
- @if(mixin-exists(hook-inverse-breadcrumb-item-disabled)) {@include hook-inverse-breadcrumb-item-disabled();}
- }
-
- .uk-breadcrumb > :last-child > * {
- color: $inverse-breadcrumb-item-active-color;
- @if(mixin-exists(hook-inverse-breadcrumb-item-active)) {@include hook-inverse-breadcrumb-item-active();}
- }
-
- //
- // Divider
- //
-
- .uk-breadcrumb > :nth-child(n+2):not(.uk-first-column)::before {
- color: $inverse-breadcrumb-divider-color;
- @if(mixin-exists(hook-inverse-breadcrumb-divider)) {@include hook-inverse-breadcrumb-divider();}
- }
-
-}
-@mixin hook-button(){}
-@mixin hook-button-hover(){}
-@mixin hook-button-focus(){}
-@mixin hook-button-active(){}
-@mixin hook-button-default(){}
-@mixin hook-button-default-hover(){}
-@mixin hook-button-default-active(){}
-@mixin hook-button-primary(){}
-@mixin hook-button-primary-hover(){}
-@mixin hook-button-primary-active(){}
-@mixin hook-button-secondary(){}
-@mixin hook-button-secondary-hover(){}
-@mixin hook-button-secondary-active(){}
-@mixin hook-button-danger(){}
-@mixin hook-button-danger-hover(){}
-@mixin hook-button-danger-active(){}
-@mixin hook-button-disabled(){}
-@mixin hook-button-small(){}
-@mixin hook-button-large(){}
-@mixin hook-button-text(){}
-@mixin hook-button-text-hover(){}
-@mixin hook-button-text-disabled(){}
-@mixin hook-button-link(){}
-@mixin hook-button-misc(){}
-@mixin hook-inverse-button-default(){}
-@mixin hook-inverse-button-default-hover(){}
-@mixin hook-inverse-button-default-active(){}
-@mixin hook-inverse-button-primary(){}
-@mixin hook-inverse-button-primary-hover(){}
-@mixin hook-inverse-button-primary-active(){}
-@mixin hook-inverse-button-secondary(){}
-@mixin hook-inverse-button-secondary-hover(){}
-@mixin hook-inverse-button-secondary-active(){}
-@mixin hook-inverse-button-text(){}
-@mixin hook-inverse-button-text-hover(){}
-@mixin hook-inverse-button-text-disabled(){}
-@mixin hook-inverse-button-link(){}
-@mixin hook-inverse-component-button(){
-
- //
- // Default
- //
-
- .uk-button-default {
- background-color: $inverse-button-default-background;
- color: $inverse-button-default-color;
- @if(mixin-exists(hook-inverse-button-default)) {@include hook-inverse-button-default();}
- }
-
- .uk-button-default:hover,
- .uk-button-default:focus {
- background-color: $inverse-button-default-hover-background;
- color: $inverse-button-default-hover-color;
- @if(mixin-exists(hook-inverse-button-default-hover)) {@include hook-inverse-button-default-hover();}
- }
-
- .uk-button-default:active,
- .uk-button-default.uk-active {
- background-color: $inverse-button-default-active-background;
- color: $inverse-button-default-active-color;
- @if(mixin-exists(hook-inverse-button-default-active)) {@include hook-inverse-button-default-active();}
- }
-
- //
- // Primary
- //
-
- .uk-button-primary {
- background-color: $inverse-button-primary-background;
- color: $inverse-button-primary-color;
- @if(mixin-exists(hook-inverse-button-primary)) {@include hook-inverse-button-primary();}
- }
-
- .uk-button-primary:hover,
- .uk-button-primary:focus {
- background-color: $inverse-button-primary-hover-background;
- color: $inverse-button-primary-hover-color;
- @if(mixin-exists(hook-inverse-button-primary-hover)) {@include hook-inverse-button-primary-hover();}
- }
-
- .uk-button-primary:active,
- .uk-button-primary.uk-active {
- background-color: $inverse-button-primary-active-background;
- color: $inverse-button-primary-active-color;
- @if(mixin-exists(hook-inverse-button-primary-active)) {@include hook-inverse-button-primary-active();}
- }
-
- //
- // Secondary
- //
-
- .uk-button-secondary {
- background-color: $inverse-button-secondary-background;
- color: $inverse-button-secondary-color;
- @if(mixin-exists(hook-inverse-button-secondary)) {@include hook-inverse-button-secondary();}
- }
-
- .uk-button-secondary:hover,
- .uk-button-secondary:focus {
- background-color: $inverse-button-secondary-hover-background;
- color: $inverse-button-secondary-hover-color;
- @if(mixin-exists(hook-inverse-button-secondary-hover)) {@include hook-inverse-button-secondary-hover();}
- }
-
- .uk-button-secondary:active,
- .uk-button-secondary.uk-active {
- background-color: $inverse-button-secondary-active-background;
- color: $inverse-button-secondary-active-color;
- @if(mixin-exists(hook-inverse-button-secondary-active)) {@include hook-inverse-button-secondary-active();}
- }
-
- //
- // Text
- //
-
- .uk-button-text {
- color: $inverse-button-text-color;
- @if(mixin-exists(hook-inverse-button-text)) {@include hook-inverse-button-text();}
- }
-
- .uk-button-text:hover,
- .uk-button-text:focus {
- color: $inverse-button-text-hover-color;
- @if(mixin-exists(hook-inverse-button-text-hover)) {@include hook-inverse-button-text-hover();}
- }
-
- .uk-button-text:disabled {
- color: $inverse-button-text-disabled-color;
- @if(mixin-exists(hook-inverse-button-text-disabled)) {@include hook-inverse-button-text-disabled();}
- }
-
- //
- // Link
- //
-
- .uk-button-link {
- color: $inverse-button-link-color;
- @if(mixin-exists(hook-inverse-button-link)) {@include hook-inverse-button-link();}
- }
-
- .uk-button-link:hover,
- .uk-button-link:focus { color: $inverse-button-link-hover-color; }
-
-
-}
-@mixin hook-card(){}
-@mixin hook-card-body(){}
-@mixin hook-card-header(){}
-@mixin hook-card-footer(){}
-@mixin hook-card-media(){}
-@mixin hook-card-media-top(){}
-@mixin hook-card-media-bottom(){}
-@mixin hook-card-media-left(){}
-@mixin hook-card-media-right(){}
-@mixin hook-card-title(){}
-@mixin hook-card-badge(){}
-@mixin hook-card-hover(){}
-@mixin hook-card-default(){}
-@mixin hook-card-default-title(){}
-@mixin hook-card-default-hover(){}
-@mixin hook-card-default-header(){}
-@mixin hook-card-default-footer(){}
-@mixin hook-card-primary(){}
-@mixin hook-card-primary-title(){}
-@mixin hook-card-primary-hover(){}
-@mixin hook-card-secondary(){}
-@mixin hook-card-secondary-title(){}
-@mixin hook-card-secondary-hover(){}
-@mixin hook-card-misc(){}
-@mixin hook-close(){}
-@mixin hook-close-hover(){}
-@mixin hook-close-misc(){}
-@mixin hook-inverse-close(){}
-@mixin hook-inverse-close-hover(){}
-@mixin hook-inverse-component-close(){
-
- .uk-close {
- color: $inverse-close-color;
- @if(mixin-exists(hook-inverse-close)) {@include hook-inverse-close();}
- }
-
- .uk-close:hover,
- .uk-close:focus {
- color: $inverse-close-hover-color;
- @if(mixin-exists(hook-inverse-close-hover)) {@include hook-inverse-close-hover();}
- }
-
-}
-@mixin hook-column-misc(){}
-@mixin hook-inverse-component-column(){
-
- .uk-column-divider { column-rule-color: $inverse-column-divider-rule-color; }
-
-}
-@mixin hook-comment(){}
-@mixin hook-comment-body(){}
-@mixin hook-comment-header(){}
-@mixin hook-comment-title(){}
-@mixin hook-comment-meta(){}
-@mixin hook-comment-avatar(){}
-@mixin hook-comment-list-adjacent(){}
-@mixin hook-comment-list-sub(){}
-@mixin hook-comment-list-sub-adjacent(){}
-@mixin hook-comment-primary(){}
-@mixin hook-comment-misc(){}
-@mixin hook-container-misc(){}
-@mixin hook-countdown(){}
-@mixin hook-countdown-item(){}
-@mixin hook-countdown-number(){}
-@mixin hook-countdown-separator(){}
-@mixin hook-countdown-label(){}
-@mixin hook-countdown-misc(){}
-@mixin hook-inverse-countdown-item(){}
-@mixin hook-inverse-countdown-number(){}
-@mixin hook-inverse-countdown-separator(){}
-@mixin hook-inverse-countdown-label(){}
-@mixin hook-inverse-component-countdown(){
-
- .uk-countdown-number,
- .uk-countdown-separator {
- @if(mixin-exists(hook-inverse-countdown-item)) {@include hook-inverse-countdown-item();}
- }
-
- .uk-countdown-number {
- @if(mixin-exists(hook-inverse-countdown-number)) {@include hook-inverse-countdown-number();}
- }
-
- .uk-countdown-separator {
- @if(mixin-exists(hook-inverse-countdown-separator)) {@include hook-inverse-countdown-separator();}
- }
-
- .uk-countdown-label {
- @if(mixin-exists(hook-inverse-countdown-label)) {@include hook-inverse-countdown-label();}
- }
-
-}
-@mixin hook-cover-misc(){}
-@mixin hook-description-list-term(){}
-@mixin hook-description-list-description(){}
-@mixin hook-description-list-divider-term(){}
-@mixin hook-description-list-misc(){}
-@mixin svg-fill($src, $color-default, $color-new, $property: background-image){
-
- $escape-color-default: escape($color-default) !default;
- $escape-color-new: escape("#{$color-new}") !default;
-
- $data-uri: data-uri('image/svg+xml;charset=UTF-8', "#{$src}") !default;
- $replace-src: replace("#{$data-uri}", "#{$escape-color-default}", "#{$escape-color-new}", "g") !default;
-
- #{$property}: unquote($replace-src);
-}
-@mixin hook-divider-icon(){}
-@mixin hook-divider-icon-line(){}
-@mixin hook-divider-icon-line-left(){}
-@mixin hook-divider-icon-line-right(){}
-@mixin hook-divider-small(){}
-@mixin hook-divider-misc(){}
-@mixin hook-inverse-divider-icon(){}
-@mixin hook-inverse-divider-icon-line(){}
-@mixin hook-inverse-divider-small(){}
-@mixin hook-inverse-component-divider(){
-
- .uk-divider-icon {
- @include svg-fill($internal-divider-icon-image, "#000", $inverse-divider-icon-color);
- @if(mixin-exists(hook-inverse-divider-icon)) {@include hook-inverse-divider-icon();}
- }
-
- .uk-divider-icon::before,
- .uk-divider-icon::after {
- border-bottom-color: $inverse-divider-icon-line-border;
- @if(mixin-exists(hook-inverse-divider-icon-line)) {@include hook-inverse-divider-icon-line();}
- }
-
- .uk-divider-small::after {
- border-top-color: $inverse-divider-small-border;
- @if(mixin-exists(hook-inverse-divider-small)) {@include hook-inverse-divider-small();}
- }
-
-}
-@mixin hook-dotnav(){}
-@mixin hook-dotnav-item(){}
-@mixin hook-dotnav-item-hover(){}
-@mixin hook-dotnav-item-onclick(){}
-@mixin hook-dotnav-item-active(){}
-@mixin hook-dotnav-misc(){}
-@mixin hook-inverse-dotnav-item(){}
-@mixin hook-inverse-dotnav-item-hover(){}
-@mixin hook-inverse-dotnav-item-onclick(){}
-@mixin hook-inverse-dotnav-item-active(){}
-@mixin hook-inverse-component-dotnav(){
-
- .uk-dotnav > * > * {
- background-color: $inverse-dotnav-item-background;
- @if(mixin-exists(hook-inverse-dotnav-item)) {@include hook-inverse-dotnav-item();}
- }
-
- .uk-dotnav > * > :hover,
- .uk-dotnav > * > :focus {
- background-color: $inverse-dotnav-item-hover-background;
- @if(mixin-exists(hook-inverse-dotnav-item-hover)) {@include hook-inverse-dotnav-item-hover();}
- }
-
- .uk-dotnav > * > :active {
- background-color: $inverse-dotnav-item-onclick-background;
- @if(mixin-exists(hook-inverse-dotnav-item-onclick)) {@include hook-inverse-dotnav-item-onclick();}
- }
-
- .uk-dotnav > .uk-active > * {
- background-color: $inverse-dotnav-item-active-background;
- @if(mixin-exists(hook-inverse-dotnav-item-active)) {@include hook-inverse-dotnav-item-active();}
- }
-
-}
-@mixin hook-drop-misc(){}
-@mixin hook-dropdown(){}
-@mixin hook-dropdown-nav(){}
-@mixin hook-dropdown-nav-item(){}
-@mixin hook-dropdown-nav-item-hover(){}
-@mixin hook-dropdown-nav-header(){}
-@mixin hook-dropdown-nav-divider(){}
-@mixin hook-dropdown-misc(){}
-@mixin hook-flex-misc(){}
-@mixin hook-form-range(){}
-@mixin hook-form-range-thumb(){}
-@mixin hook-form-range-track(){}
-@mixin hook-form-range-track-focus(){}
-@mixin hook-form-range-misc(){}
-@mixin hook-form(){}
-@mixin hook-form-single-line(){}
-@mixin hook-form-multi-line(){}
-@mixin hook-form-focus(){}
-@mixin hook-form-disabled(){}
-@mixin hook-form-danger(){}
-@mixin hook-form-success(){}
-@mixin hook-form-blank(){}
-@mixin hook-form-blank-focus(){}
-@mixin hook-form-radio(){}
-@mixin hook-form-radio-focus(){}
-@mixin hook-form-radio-checked(){}
-@mixin hook-form-radio-checked-focus(){}
-@mixin hook-form-radio-disabled(){}
-@mixin hook-form-legend(){}
-@mixin hook-form-label(){}
-@mixin hook-form-stacked-label(){}
-@mixin hook-form-horizontal-label(){}
-@mixin hook-form-misc(){}
-@mixin hook-inverse-form(){}
-@mixin hook-inverse-form-focus(){}
-@mixin hook-inverse-form-radio(){}
-@mixin hook-inverse-form-radio-focus(){}
-@mixin hook-inverse-form-radio-checked(){}
-@mixin hook-inverse-form-radio-checked-focus(){}
-@mixin hook-inverse-form-label(){}
-@mixin hook-inverse-component-form(){
-
- .uk-input,
- .uk-select,
- .uk-textarea {
- background-color: $inverse-form-background;
- color: $inverse-form-color;
- background-clip: padding-box;
- @if(mixin-exists(hook-inverse-form)) {@include hook-inverse-form();}
-
- &:focus {
- background-color: $inverse-form-focus-background;
- color: $inverse-form-focus-color;
- @if(mixin-exists(hook-inverse-form-focus)) {@include hook-inverse-form-focus();}
- }
- }
-
- //
- // Placeholder
- //
-
- .uk-input:-ms-input-placeholder { color: $inverse-form-placeholder-color !important; }
- .uk-input::placeholder { color: $inverse-form-placeholder-color; }
-
- .uk-textarea:-ms-input-placeholder { color: $inverse-form-placeholder-color !important; }
- .uk-textarea::placeholder { color: $inverse-form-placeholder-color; }
-
- //
- // Radio and checkbox
- //
-
- .uk-select:not([multiple]):not([size]) { @include svg-fill($internal-form-select-image, "#000", $inverse-form-select-icon-color); }
-
- //
- // Radio and checkbox
- //
-
- .uk-radio,
- .uk-checkbox {
- background-color: $inverse-form-radio-background;
- @if(mixin-exists(hook-inverse-form-radio)) {@include hook-inverse-form-radio();}
- }
-
- // Focus
- .uk-radio:focus,
- .uk-checkbox:focus {
- @if(mixin-exists(hook-inverse-form-radio-focus)) {@include hook-inverse-form-radio-focus();}
- }
-
- // Checked
- .uk-radio:checked,
- .uk-checkbox:checked,
- .uk-checkbox:indeterminate {
- background-color: $inverse-form-radio-checked-background;
- @if(mixin-exists(hook-inverse-form-radio-checked)) {@include hook-inverse-form-radio-checked();}
- }
-
- // Focus
- .uk-radio:checked:focus,
- .uk-checkbox:checked:focus,
- .uk-checkbox:indeterminate:focus {
- background-color: $inverse-form-radio-checked-focus-background;
- @if(mixin-exists(hook-inverse-form-radio-checked-focus)) {@include hook-inverse-form-radio-checked-focus();}
- }
-
- // Icon
- .uk-radio:checked { @include svg-fill($internal-form-radio-image, "#000", $inverse-form-radio-checked-icon-color); }
- .uk-checkbox:checked { @include svg-fill($internal-form-checkbox-image, "#000", $inverse-form-radio-checked-icon-color); }
- .uk-checkbox:indeterminate { @include svg-fill($internal-form-checkbox-indeterminate-image, "#000", $inverse-form-radio-checked-icon-color); }
-
- // Label
- .uk-form-label {
- @if(mixin-exists(hook-inverse-form-label)) {@include hook-inverse-form-label();}
- }
-
-}
-@mixin hook-grid-misc(){}
-@mixin hook-inverse-component-grid(){
-
- .uk-grid-divider > :not(.uk-first-column)::before { border-left-color: $inverse-grid-divider-border; }
- .uk-grid-divider.uk-grid-stack > .uk-grid-margin::before { border-top-color: $inverse-grid-divider-border; }
-
-}
-@mixin hook-heading-primary(){}
-@mixin hook-heading-hero(){}
-@mixin hook-heading-divider(){}
-@mixin hook-heading-bullet(){}
-@mixin hook-heading-line(){}
-@mixin hook-heading-misc(){}
-@mixin hook-inverse-heading-primary(){}
-@mixin hook-inverse-heading-hero(){}
-@mixin hook-inverse-heading-divider(){}
-@mixin hook-inverse-heading-bullet(){}
-@mixin hook-inverse-heading-line(){}
-@mixin hook-inverse-component-heading(){
-
- .uk-heading-primary {
- @if(mixin-exists(hook-inverse-heading-primary)) {@include hook-inverse-heading-primary();}
- }
-
- .uk-heading-hero {
- @if(mixin-exists(hook-inverse-heading-hero)) {@include hook-inverse-heading-hero();}
- }
-
- .uk-heading-divider {
- border-bottom-color: $inverse-heading-divider-border;
- @if(mixin-exists(hook-inverse-heading-divider)) {@include hook-inverse-heading-divider();}
- }
-
- .uk-heading-bullet::before {
- border-left-color: $inverse-heading-bullet-border;
- @if(mixin-exists(hook-inverse-heading-bullet)) {@include hook-inverse-heading-bullet();}
- }
-
- .uk-heading-line > ::before,
- .uk-heading-line > ::after {
- border-bottom-color: $inverse-heading-line-border;
- @if(mixin-exists(hook-inverse-heading-line)) {@include hook-inverse-heading-line();}
- }
-
-}
-@mixin hook-icon-link(){}
-@mixin hook-icon-link-hover(){}
-@mixin hook-icon-link-active(){}
-@mixin hook-icon-button(){}
-@mixin hook-icon-button-hover(){}
-@mixin hook-icon-button-active(){}
-@mixin hook-icon-misc(){}
-@mixin hook-inverse-icon-link(){}
-@mixin hook-inverse-icon-link-hover(){}
-@mixin hook-inverse-icon-link-active(){}
-@mixin hook-inverse-icon-button(){}
-@mixin hook-inverse-icon-button-hover(){}
-@mixin hook-inverse-icon-button-active(){}
-@mixin hook-inverse-component-icon(){
-
- //
- // Link
- //
-
- .uk-icon-link {
- color: $inverse-icon-link-color;
- @if(mixin-exists(hook-inverse-icon-link)) {@include hook-inverse-icon-link();}
- }
-
- .uk-icon-link:hover,
- .uk-icon-link:focus {
- color: $inverse-icon-link-hover-color;
- @if(mixin-exists(hook-inverse-icon-link-hover)) {@include hook-inverse-icon-link-hover();}
- }
-
- .uk-icon-link:active,
- .uk-active > .uk-icon-link {
- color: $inverse-icon-link-active-color;
- @if(mixin-exists(hook-inverse-icon-link-active)) {@include hook-inverse-icon-link-active();}
- }
-
- //
- // Button
- //
-
- .uk-icon-button {
- background-color: $inverse-icon-button-background;
- color: $inverse-icon-button-color;
- @if(mixin-exists(hook-inverse-icon-button)) {@include hook-inverse-icon-button();}
- }
-
- .uk-icon-button:hover,
- .uk-icon-button:focus {
- background-color: $inverse-icon-button-hover-background;
- color: $inverse-icon-button-hover-color;
- @if(mixin-exists(hook-inverse-icon-button-hover)) {@include hook-inverse-icon-button-hover();}
- }
-
- .uk-icon-button:active {
- background-color: $inverse-icon-button-active-background;
- color: $inverse-icon-button-active-color;
- @if(mixin-exists(hook-inverse-icon-button-active)) {@include hook-inverse-icon-button-active();}
- }
-
-}
-@mixin hook-iconnav(){}
-@mixin hook-iconnav-item(){}
-@mixin hook-iconnav-item-hover(){}
-@mixin hook-iconnav-item-active(){}
-@mixin hook-iconnav-misc(){}
-@mixin hook-inverse-iconnav-item(){}
-@mixin hook-inverse-iconnav-item-hover(){}
-@mixin hook-inverse-iconnav-item-active(){}
-@mixin hook-inverse-component-iconnav(){
-
- .uk-iconnav > * > a {
- color: $inverse-iconnav-item-color;
- @if(mixin-exists(hook-inverse-iconnav-item)) {@include hook-inverse-iconnav-item();}
- }
-
- .uk-iconnav > * > a:hover,
- .uk-iconnav > * > a:focus {
- color: $inverse-iconnav-item-hover-color;
- @if(mixin-exists(hook-inverse-iconnav-item-hover)) {@include hook-inverse-iconnav-item-hover();}
- }
-
- .uk-iconnav > .uk-active > a {
- color: $inverse-iconnav-item-active-color;
- @if(mixin-exists(hook-inverse-iconnav-item-active)) {@include hook-inverse-iconnav-item-active();}
- }
-
-}
-@mixin hook-inverse-component-link(){
-
- a.uk-link-muted,
- .uk-link-muted a {
- color: $inverse-link-muted-color;
- @if(mixin-exists(hook-inverse-link-muted)) {@include hook-inverse-link-muted();}
- }
-
- a.uk-link-muted:hover,
- .uk-link-muted a:hover {
- color: $inverse-link-muted-hover-color;
- @if(mixin-exists(hook-inverse-link-muted-hover)) {@include hook-inverse-link-muted-hover();}
- }
-
- a.uk-link-text:hover,
- .uk-link-text a:hover {
- color: $inverse-link-text-hover-color;
- @if(mixin-exists(hook-inverse-link-text-hover)) {@include hook-inverse-link-text-hover();}
- }
-
- a.uk-link-heading:hover,
- .uk-link-heading a:hover {
- color: $inverse-link-heading-hover-color;
- @if(mixin-exists(hook-inverse-link-heading-hover)) {@include hook-inverse-link-heading-hover();}
- }
-
-}
-@mixin hook-inverse-component-list(){
-
- .uk-list-divider > li:nth-child(n+2) {
- border-top-color: $inverse-list-divider-border;
- @if(mixin-exists(hook-inverse-list-divider)) {@include hook-inverse-list-divider();}
- }
-
- .uk-list-striped > li {
- @if(mixin-exists(hook-inverse-list-striped)) {@include hook-inverse-list-striped();}
- }
-
- .uk-list-striped > li:nth-of-type(odd) { background-color: $inverse-list-striped-background; }
-
- .uk-list-bullet > li::before {
- @include svg-fill($internal-list-bullet-image, "#000", $inverse-list-bullet-icon-color);
- @if(mixin-exists(hook-inverse-list-bullet)) {@include hook-inverse-list-bullet();}
- }
-
-}
-@mixin hook-inverse-component-totop(){
-
- .uk-totop {
- color: $inverse-totop-color;
- @if(mixin-exists(hook-inverse-totop)) {@include hook-inverse-totop();}
- }
-
- .uk-totop:hover,
- .uk-totop:focus {
- color: $inverse-totop-hover-color;
- @if(mixin-exists(hook-inverse-totop-hover)) {@include hook-inverse-totop-hover();}
- }
-
- .uk-totop:active {
- color: $inverse-totop-active-color;
- @if(mixin-exists(hook-inverse-totop-active)) {@include hook-inverse-totop-active();}
- }
-
-}
-@mixin hook-inverse-component-label(){
-
- .uk-label {
- background-color: $inverse-label-background;
- color: $inverse-label-color;
- @if(mixin-exists(hook-inverse-label)) {@include hook-inverse-label();}
- }
-
-}
-@mixin hook-inverse-component-search(){
-
- //
- // Input
- //
-
- .uk-search-input { color: $inverse-search-color; }
-
- .uk-search-input:-ms-input-placeholder { color: $inverse-search-placeholder-color !important; }
- .uk-search-input::placeholder { color: $inverse-search-placeholder-color; }
-
-
- //
- // Icon
- //
-
- .uk-search .uk-search-icon { color: $inverse-search-icon-color; }
-
- .uk-search .uk-search-icon:hover { color: $inverse-search-icon-color; }
-
- //
- // Style modifier
- //
-
- .uk-search-default .uk-search-input {
- background-color: $inverse-search-default-background;
- @if(mixin-exists(hook-inverse-search-default-input)) {@include hook-inverse-search-default-input();}
- }
- .uk-search-default .uk-search-input:focus {
- background-color: $inverse-search-default-background;
- @if(mixin-exists(hook-inverse-search-default-input-focus)) {@include hook-inverse-search-default-input-focus();}
- }
-
- .uk-search-navbar .uk-search-input {
- background-color: $inverse-search-navbar-background;
- @if(mixin-exists(hook-inverse-search-navbar-input)) {@include hook-inverse-search-navbar-input();}
- }
-
- .uk-search-large .uk-search-input {
- background-color: $inverse-search-large-background;
- @if(mixin-exists(hook-inverse-search-large-input)) {@include hook-inverse-search-large-input();}
- }
-
- //
- // Toggle
- //
-
- .uk-search-toggle {
- color: $inverse-search-toggle-color;
- @if(mixin-exists(hook-inverse-search-toggle)) {@include hook-inverse-search-toggle();}
- }
-
- .uk-search-toggle:hover,
- .uk-search-toggle:focus {
- color: $inverse-search-toggle-hover-color;
- @if(mixin-exists(hook-inverse-search-toggle-hover)) {@include hook-inverse-search-toggle-hover();}
- }
-
-}
-@mixin hook-inverse-component-nav(){
-
- //
- // Parent icon modifier
- //
-
- .uk-nav-parent-icon > .uk-parent > a::after {
- @include svg-fill($internal-nav-parent-close-image, "#000", $inverse-nav-parent-icon-color);
- @if(mixin-exists(hook-inverse-nav-parent-icon)) {@include hook-inverse-nav-parent-icon();}
- }
-
- .uk-nav-parent-icon > .uk-parent.uk-open > a::after { @include svg-fill($internal-nav-parent-open-image, "#000", $inverse-nav-parent-icon-color); }
-
- //
- // Default
- //
-
- .uk-nav-default > li > a {
- color: $inverse-nav-default-item-color;
- @if(mixin-exists(hook-inverse-nav-default-item)) {@include hook-inverse-nav-default-item();}
- }
-
- .uk-nav-default > li > a:hover,
- .uk-nav-default > li > a:focus {
- color: $inverse-nav-default-item-hover-color;
- @if(mixin-exists(hook-inverse-nav-default-item-hover)) {@include hook-inverse-nav-default-item-hover();}
- }
-
- .uk-nav-default > li.uk-active > a {
- color: $inverse-nav-default-item-active-color;
- @if(mixin-exists(hook-inverse-nav-default-item-active)) {@include hook-inverse-nav-default-item-active();}
- }
-
- .uk-nav-default .uk-nav-header {
- color: $inverse-nav-default-header-color;
- @if(mixin-exists(hook-inverse-nav-default-header)) {@include hook-inverse-nav-default-header();}
- }
-
- .uk-nav-default .uk-nav-divider {
- border-top-color: $inverse-nav-default-divider-border;
- @if(mixin-exists(hook-inverse-nav-default-divider)) {@include hook-inverse-nav-default-divider();}
- }
-
- .uk-nav-default .uk-nav-sub a { color: $inverse-nav-default-sublist-item-color; }
-
- .uk-nav-default .uk-nav-sub a:hover,
- .uk-nav-default .uk-nav-sub a:focus { color: $inverse-nav-default-sublist-item-hover-color; }
-
- //
- // Primary
- //
-
- .uk-nav-primary > li > a {
- color: $inverse-nav-primary-item-color;
- @if(mixin-exists(hook-inverse-nav-primary-item)) {@include hook-inverse-nav-primary-item();}
- }
-
- .uk-nav-primary > li > a:hover,
- .uk-nav-primary > li > a:focus {
- color: $inverse-nav-primary-item-hover-color;
- @if(mixin-exists(hook-inverse-nav-primary-item-hover)) {@include hook-inverse-nav-primary-item-hover();}
- }
-
- .uk-nav-primary > li.uk-active > a {
- color: $inverse-nav-primary-item-active-color;
- @if(mixin-exists(hook-inverse-nav-primary-item-active)) {@include hook-inverse-nav-primary-item-active();}
- }
-
- .uk-nav-primary .uk-nav-header {
- color: $inverse-nav-primary-header-color;
- @if(mixin-exists(hook-inverse-nav-primary-header)) {@include hook-inverse-nav-primary-header();}
- }
-
- .uk-nav-primary .uk-nav-divider {
- border-top-color: $inverse-nav-primary-divider-border;
- @if(mixin-exists(hook-inverse-nav-primary-divider)) {@include hook-inverse-nav-primary-divider();}
- }
-
- .uk-nav-primary .uk-nav-sub a { color: $inverse-nav-primary-sublist-item-color; }
-
- .uk-nav-primary .uk-nav-sub a:hover,
- .uk-nav-primary .uk-nav-sub a:focus { color: $inverse-nav-primary-sublist-item-hover-color; }
-
-}
-@mixin hook-inverse-component-navbar(){
-
- .uk-navbar-nav > li > a {
- color: $inverse-navbar-nav-item-color;
- @if(mixin-exists(hook-inverse-navbar-nav-item)) {@include hook-inverse-navbar-nav-item();}
- }
-
- .uk-navbar-nav > li:hover > a,
- .uk-navbar-nav > li > a:focus,
- .uk-navbar-nav > li > a.uk-open {
- color: $inverse-navbar-nav-item-hover-color;
- @if(mixin-exists(hook-inverse-navbar-nav-item-hover)) {@include hook-inverse-navbar-nav-item-hover();}
- }
-
- .uk-navbar-nav > li > a:active {
- color: $inverse-navbar-nav-item-onclick-color;
- @if(mixin-exists(hook-inverse-navbar-nav-item-onclick)) {@include hook-inverse-navbar-nav-item-onclick();}
- }
-
- .uk-navbar-nav > li.uk-active > a {
- color: $inverse-navbar-nav-item-active-color;
- @if(mixin-exists(hook-inverse-navbar-nav-item-active)) {@include hook-inverse-navbar-nav-item-active();}
- }
-
- .uk-navbar-item {
- color: $inverse-navbar-item-color;
- @if(mixin-exists(hook-inverse-navbar-item)) {@include hook-inverse-navbar-item();}
- }
-
- .uk-navbar-toggle {
- color: $inverse-navbar-toggle-color;
- @if(mixin-exists(hook-inverse-navbar-toggle)) {@include hook-inverse-navbar-toggle();}
- }
-
- .uk-navbar-toggle:hover,
- .uk-navbar-toggle:focus,
- .uk-navbar-toggle.uk-open {
- color: $inverse-navbar-toggle-hover-color;
- @if(mixin-exists(hook-inverse-navbar-toggle-hover)) {@include hook-inverse-navbar-toggle-hover();}
- }
-
-}
-@mixin hook-inverse-component-subnav(){
-
- .uk-subnav > * > :first-child {
- color: $inverse-subnav-item-color;
- @if(mixin-exists(hook-inverse-subnav-item)) {@include hook-inverse-subnav-item();}
- }
-
- .uk-subnav > * > a:hover,
- .uk-subnav > * > a:focus {
- color: $inverse-subnav-item-hover-color;
- @if(mixin-exists(hook-inverse-subnav-item-hover)) {@include hook-inverse-subnav-item-hover();}
- }
-
- .uk-subnav > .uk-active > a {
- color: $inverse-subnav-item-active-color;
- @if(mixin-exists(hook-inverse-subnav-item-active)) {@include hook-inverse-subnav-item-active();}
- }
-
- //
- // Divider
- //
-
- .uk-subnav-divider > :nth-child(n+2):not(.uk-first-column)::before {
- border-left-color: $inverse-subnav-divider-border;
- @if(mixin-exists(hook-inverse-subnav-divider)) {@include hook-inverse-subnav-divider();}
- }
-
- //
- // Pill
- //
-
- .uk-subnav-pill > * > :first-child {
- background-color: $inverse-subnav-pill-item-background;
- color: $inverse-subnav-pill-item-color;
- @if(mixin-exists(hook-inverse-subnav-pill-item)) {@include hook-inverse-subnav-pill-item();}
- }
-
- .uk-subnav-pill > * > a:hover,
- .uk-subnav-pill > * > a:focus {
- background-color: $inverse-subnav-pill-item-hover-background;
- color: $inverse-subnav-pill-item-hover-color;
- @if(mixin-exists(hook-inverse-subnav-pill-item-hover)) {@include hook-inverse-subnav-pill-item-hover();}
- }
-
- .uk-subnav-pill > * > a:active {
- background-color: $inverse-subnav-pill-item-onclick-background;
- color: $inverse-subnav-pill-item-onclick-color;
- @if(mixin-exists(hook-inverse-subnav-pill-item-onclick)) {@include hook-inverse-subnav-pill-item-onclick();}
- }
-
- .uk-subnav-pill > .uk-active > a {
- background-color: $inverse-subnav-pill-item-active-background;
- color: $inverse-subnav-pill-item-active-color;
- @if(mixin-exists(hook-inverse-subnav-pill-item-active)) {@include hook-inverse-subnav-pill-item-active();}
- }
-
- //
- // Disabled
- //
-
- .uk-subnav > .uk-disabled > a {
- color: $inverse-subnav-item-disabled-color;
- @if(mixin-exists(hook-inverse-subnav-item-disabled)) {@include hook-inverse-subnav-item-disabled();}
- }
-
-}
-@mixin hook-inverse-component-pagination(){
-
- .uk-pagination > * > * {
- color: $inverse-pagination-item-color;
- @if(mixin-exists(hook-inverse-pagination-item)) {@include hook-inverse-pagination-item();}
- }
-
- .uk-pagination > * > :hover,
- .uk-pagination > * > :focus {
- color: $inverse-pagination-item-hover-color;
- @if(mixin-exists(hook-inverse-pagination-item-hover)) {@include hook-inverse-pagination-item-hover();}
- }
-
- .uk-pagination > .uk-active > * {
- color: $inverse-pagination-item-active-color;
- @if(mixin-exists(hook-inverse-pagination-item-active)) {@include hook-inverse-pagination-item-active();}
- }
-
- .uk-pagination > .uk-disabled > * {
- color: $inverse-pagination-item-disabled-color;
- @if(mixin-exists(hook-inverse-pagination-item-disabled)) {@include hook-inverse-pagination-item-disabled();}
- }
-
-}
-@mixin hook-inverse-component-tab(){
-
- .uk-tab {
- @if(mixin-exists(hook-inverse-tab)) {@include hook-inverse-tab();}
- }
-
- .uk-tab > * > a {
- color: $inverse-tab-item-color;
- @if(mixin-exists(hook-inverse-tab-item)) {@include hook-inverse-tab-item();}
- }
-
- .uk-tab > * > a:hover,
- .uk-tab > * > a:focus{
- color: $inverse-tab-item-hover-color;
- @if(mixin-exists(hook-inverse-tab-item-hover)) {@include hook-inverse-tab-item-hover();}
- }
-
- .uk-tab > .uk-active > a {
- color: $inverse-tab-item-active-color;
- @if(mixin-exists(hook-inverse-tab-item-active)) {@include hook-inverse-tab-item-active();}
- }
-
- .uk-tab > .uk-disabled > a {
- color: $inverse-tab-item-disabled-color;
- @if(mixin-exists(hook-inverse-tab-item-disabled)) {@include hook-inverse-tab-item-disabled();}
- }
-
-}
-@mixin hook-inverse-component-slidenav(){
-
- .uk-slidenav {
- color: $inverse-slidenav-color;
- @if(mixin-exists(hook-inverse-slidenav)) {@include hook-inverse-slidenav();}
- }
-
- .uk-slidenav:hover,
- .uk-slidenav:focus {
- color: $inverse-slidenav-hover-color;
- @if(mixin-exists(hook-inverse-slidenav-hover)) {@include hook-inverse-slidenav-hover();}
- }
-
- .uk-slidenav:active {
- color: $inverse-slidenav-active-color;
- @if(mixin-exists(hook-inverse-slidenav-active)) {@include hook-inverse-slidenav-active();}
- }
-
-}
-@mixin hook-inverse-component-text(){
-
- .uk-text-lead {
- color: $inverse-text-lead-color;
- @if(mixin-exists(hook-inverse-text-lead)) {@include hook-inverse-text-lead();}
- }
-
- .uk-text-meta {
- color: $inverse-text-meta-color;
- @if(mixin-exists(hook-inverse-text-meta)) {@include hook-inverse-text-meta();}
- }
-
- .uk-text-muted { color: $inverse-text-muted-color !important; }
- .uk-text-primary { color: $inverse-text-primary-color !important; }
-
-}
-@mixin hook-inverse-component-utility(){
-
- .uk-dropcap::first-letter,
- .uk-dropcap p:first-of-type::first-letter {
- @if(mixin-exists(hook-inverse-dropcap)) {@include hook-inverse-dropcap();}
- }
-
- .uk-leader-fill {
- @if(mixin-exists(hook-inverse-leader)) {@include hook-inverse-leader();}
- }
-
- .uk-logo {
- color: $inverse-logo-color;
- @if(mixin-exists(hook-inverse-logo)) {@include hook-inverse-logo();}
- }
-
- .uk-logo:hover,
- .uk-logo:focus {
- color: $inverse-logo-hover-color;
- @if(mixin-exists(hook-inverse-logo-hover)) {@include hook-inverse-logo-hover();}
- }
-
- .uk-logo > :not(.uk-logo-inverse):not(:only-of-type) { display: none; }
- .uk-logo-inverse { display: inline; }
-
-}
-@mixin hook-inverse(){
- @include hook-inverse-component-base();
- @include hook-inverse-component-link();
- @include hook-inverse-component-heading();
- @include hook-inverse-component-divider();
- @include hook-inverse-component-list();
- @include hook-inverse-component-icon();
- @include hook-inverse-component-form();
- @include hook-inverse-component-button();
- @include hook-inverse-component-grid();
- @include hook-inverse-component-close();
- @include hook-inverse-component-totop();
- @include hook-inverse-component-badge();
- @include hook-inverse-component-label();
- @include hook-inverse-component-article();
- @include hook-inverse-component-search();
- @include hook-inverse-component-nav();
- @include hook-inverse-component-navbar();
- @include hook-inverse-component-subnav();
- @include hook-inverse-component-breadcrumb();
- @include hook-inverse-component-pagination();
- @include hook-inverse-component-tab();
- @include hook-inverse-component-slidenav();
- @include hook-inverse-component-dotnav();
- @include hook-inverse-component-accordion();
- @include hook-inverse-component-iconnav();
- @include hook-inverse-component-text();
- @include hook-inverse-component-column();
- @include hook-inverse-component-utility();
-}
-@mixin hook-label(){}
-@mixin hook-label-success(){}
-@mixin hook-label-warning(){}
-@mixin hook-label-danger(){}
-@mixin hook-label-misc(){}
-@mixin hook-inverse-label(){}
-@mixin hook-lightbox(){}
-@mixin hook-lightbox-item(){}
-@mixin hook-lightbox-toolbar(){}
-@mixin hook-lightbox-toolbar-icon(){}
-@mixin hook-lightbox-toolbar-icon-hover(){}
-@mixin hook-lightbox-button(){}
-@mixin hook-lightbox-button-hover(){}
-@mixin hook-lightbox-misc(){}
-@mixin hook-link-muted(){}
-@mixin hook-link-muted-hover(){}
-@mixin hook-link-text(){}
-@mixin hook-link-text-hover(){}
-@mixin hook-link-heading(){}
-@mixin hook-link-heading-hover(){}
-@mixin hook-link-reset(){}
-@mixin hook-link-misc(){}
-@mixin hook-inverse-link-muted(){}
-@mixin hook-inverse-link-muted-hover(){}
-@mixin hook-inverse-link-text-hover(){}
-@mixin hook-inverse-link-heading-hover(){}
-@mixin hook-list-divider(){}
-@mixin hook-list-striped(){}
-@mixin hook-list-bullet(){}
-@mixin hook-list-misc(){}
-@mixin hook-inverse-list-divider(){}
-@mixin hook-inverse-list-striped(){}
-@mixin hook-inverse-list-bullet(){}
-@mixin hook-margin-misc(){}
-@mixin hook-marker(){}
-@mixin hook-marker-hover(){}
-@mixin hook-marker-misc(){}
-@mixin hook-inverse-marker(){}
-@mixin hook-inverse-marker-hover(){}
-@mixin hook-inverse-component-marker(){
-
- .uk-marker {
- background: $inverse-marker-background;
- color: $inverse-marker-color;
- @if(mixin-exists(hook-inverse-marker)) {@include hook-inverse-marker();}
- }
-
- .uk-marker:hover,
- .uk-marker:focus {
- color: $inverse-marker-hover-color;
- @if(mixin-exists(hook-inverse-marker-hover)) {@include hook-inverse-marker-hover();}
- }
-
-}
-@mixin hook-modal(){}
-@mixin hook-modal-dialog(){}
-@mixin hook-modal-full(){}
-@mixin hook-modal-body(){}
-@mixin hook-modal-header(){}
-@mixin hook-modal-footer(){}
-@mixin hook-modal-title(){}
-@mixin hook-modal-close(){}
-@mixin hook-modal-close-hover(){}
-@mixin hook-modal-close-default(){}
-@mixin hook-modal-close-default-hover(){}
-@mixin hook-modal-close-outside(){}
-@mixin hook-modal-close-outside-hover(){}
-@mixin hook-modal-close-full(){}
-@mixin hook-modal-close-full-hover(){}
-@mixin hook-modal-misc(){}
-@mixin hook-nav-sub(){}
-@mixin hook-nav-parent-icon(){}
-@mixin hook-nav-header(){}
-@mixin hook-nav-divider(){}
-@mixin hook-nav-default(){}
-@mixin hook-nav-default-item(){}
-@mixin hook-nav-default-item-hover(){}
-@mixin hook-nav-default-item-active(){}
-@mixin hook-nav-default-header(){}
-@mixin hook-nav-default-divider(){}
-@mixin hook-nav-primary(){}
-@mixin hook-nav-primary-item(){}
-@mixin hook-nav-primary-item-hover(){}
-@mixin hook-nav-primary-item-active(){}
-@mixin hook-nav-primary-header(){}
-@mixin hook-nav-primary-divider(){}
-@mixin hook-nav-misc(){}
-@mixin hook-inverse-nav-parent-icon(){}
-@mixin hook-inverse-nav-default-item(){}
-@mixin hook-inverse-nav-default-item-hover(){}
-@mixin hook-inverse-nav-default-item-active(){}
-@mixin hook-inverse-nav-default-header(){}
-@mixin hook-inverse-nav-default-divider(){}
-@mixin hook-inverse-nav-primary-item(){}
-@mixin hook-inverse-nav-primary-item-hover(){}
-@mixin hook-inverse-nav-primary-item-active(){}
-@mixin hook-inverse-nav-primary-header(){}
-@mixin hook-inverse-nav-primary-divider(){}
-@mixin hook-navbar(){}
-@mixin hook-navbar-container(){}
-@mixin hook-navbar-nav-item(){}
-@mixin hook-navbar-nav-item-hover(){}
-@mixin hook-navbar-nav-item-onclick(){}
-@mixin hook-navbar-nav-item-active(){}
-@mixin hook-navbar-item(){}
-@mixin hook-navbar-toggle(){}
-@mixin hook-navbar-toggle-hover(){}
-@mixin hook-navbar-toggle-icon(){}
-@mixin hook-navbar-toggle-icon-hover(){}
-@mixin hook-navbar-subtitle(){}
-@mixin hook-navbar-transparent(){}
-@mixin hook-navbar-sticky(){}
-@mixin hook-navbar-dropdown(){}
-@mixin hook-navbar-dropdown-dropbar(){}
-@mixin hook-navbar-dropdown-nav(){}
-@mixin hook-navbar-dropdown-nav-item(){}
-@mixin hook-navbar-dropdown-nav-item-hover(){}
-@mixin hook-navbar-dropdown-nav-item-active(){}
-@mixin hook-navbar-dropdown-nav-header(){}
-@mixin hook-navbar-dropdown-nav-divider(){}
-@mixin hook-navbar-dropbar(){}
-@mixin hook-navbar-dropbar-slide(){}
-@mixin hook-navbar-misc(){}
-@mixin hook-inverse-navbar-nav-item(){}
-@mixin hook-inverse-navbar-nav-item-hover(){}
-@mixin hook-inverse-navbar-nav-item-onclick(){}
-@mixin hook-inverse-navbar-nav-item-active(){}
-@mixin hook-inverse-navbar-item(){}
-@mixin hook-inverse-navbar-toggle(){}
-@mixin hook-inverse-navbar-toggle-hover(){}
-@mixin hook-notification(){}
-@mixin hook-notification-message(){}
-@mixin hook-notification-close(){}
-@mixin hook-notification-message-primary(){}
-@mixin hook-notification-message-success(){}
-@mixin hook-notification-message-warning(){}
-@mixin hook-notification-message-danger(){}
-@mixin hook-notification-misc(){}
-@mixin hook-offcanvas-bar(){}
-@mixin hook-offcanvas-close(){}
-@mixin hook-offcanvas-overlay(){}
-@mixin hook-offcanvas-misc(){}
-@mixin hook-overlay(){}
-@mixin hook-overlay-icon(){}
-@mixin hook-overlay-default(){}
-@mixin hook-overlay-primary(){}
-@mixin hook-overlay-misc(){}
-@mixin hook-padding-misc(){}
-@mixin hook-pagination(){}
-@mixin hook-pagination-item(){}
-@mixin hook-pagination-item-hover(){}
-@mixin hook-pagination-item-active(){}
-@mixin hook-pagination-item-disabled(){}
-@mixin hook-pagination-misc(){}
-@mixin hook-inverse-pagination-item(){}
-@mixin hook-inverse-pagination-item-hover(){}
-@mixin hook-inverse-pagination-item-active(){}
-@mixin hook-inverse-pagination-item-disabled(){}
-@mixin hook-placeholder(){}
-@mixin hook-placeholder-misc(){}
-@mixin hook-position-misc(){}
-@mixin hook-print(){}
-@mixin hook-progress(){}
-@mixin hook-progress-bar(){}
-@mixin hook-progress-misc(){}
-@mixin hook-search-input(){}
-@mixin hook-search-default-input(){}
-@mixin hook-search-default-input-focus(){}
-@mixin hook-search-navbar-input(){}
-@mixin hook-search-large-input(){}
-@mixin hook-search-toggle(){}
-@mixin hook-search-toggle-hover(){}
-@mixin hook-search-misc(){}
-@mixin hook-inverse-search-default-input(){}
-@mixin hook-inverse-search-default-input-focus(){}
-@mixin hook-inverse-search-navbar-input(){}
-@mixin hook-inverse-search-large-input(){}
-@mixin hook-inverse-search-toggle(){}
-@mixin hook-inverse-search-toggle-hover(){}
-@mixin hook-section(){}
-@mixin hook-section-default(){}
-@mixin hook-section-muted(){}
-@mixin hook-section-primary(){}
-@mixin hook-section-secondary(){}
-@mixin hook-section-overlap(){}
-@mixin hook-section-misc(){}
-@mixin hook-slidenav(){}
-@mixin hook-slidenav-hover(){}
-@mixin hook-slidenav-active(){}
-@mixin hook-slidenav-previous(){}
-@mixin hook-slidenav-next(){}
-@mixin hook-slidenav-large(){}
-@mixin hook-slidenav-container(){}
-@mixin hook-slidenav-misc(){}
-@mixin hook-inverse-slidenav(){}
-@mixin hook-inverse-slidenav-hover(){}
-@mixin hook-inverse-slidenav-active(){}
-@mixin hook-slider(){}
-@mixin hook-slider-misc(){}
-@mixin hook-slideshow(){}
-@mixin hook-slideshow-misc(){}
-@mixin hook-sortable(){}
-@mixin hook-sortable-drag(){}
-@mixin hook-sortable-placeholder(){}
-@mixin hook-sortable-empty(){}
-@mixin hook-sortable-misc(){}
-@mixin hook-spinner(){}
-@mixin hook-spinner-misc(){}
-@mixin hook-sticky-misc(){}
-@mixin hook-subnav(){}
-@mixin hook-subnav-item(){}
-@mixin hook-subnav-item-hover(){}
-@mixin hook-subnav-item-active(){}
-@mixin hook-subnav-divider(){}
-@mixin hook-subnav-pill-item(){}
-@mixin hook-subnav-pill-item-hover(){}
-@mixin hook-subnav-pill-item-onclick(){}
-@mixin hook-subnav-pill-item-active(){}
-@mixin hook-subnav-item-disabled(){}
-@mixin hook-subnav-misc(){}
-@mixin hook-inverse-subnav-item(){}
-@mixin hook-inverse-subnav-item-hover(){}
-@mixin hook-inverse-subnav-item-active(){}
-@mixin hook-inverse-subnav-divider(){}
-@mixin hook-inverse-subnav-pill-item(){}
-@mixin hook-inverse-subnav-pill-item-hover(){}
-@mixin hook-inverse-subnav-pill-item-onclick(){}
-@mixin hook-inverse-subnav-pill-item-active(){}
-@mixin hook-inverse-subnav-item-disabled(){}
-@mixin hook-switcher-misc(){}
-@mixin hook-tab(){}
-@mixin hook-tab-item(){}
-@mixin hook-tab-item-hover(){}
-@mixin hook-tab-item-active(){}
-@mixin hook-tab-item-disabled(){}
-@mixin hook-tab-bottom(){}
-@mixin hook-tab-bottom-item(){}
-@mixin hook-tab-left(){}
-@mixin hook-tab-right(){}
-@mixin hook-tab-left-item(){}
-@mixin hook-tab-right-item(){}
-@mixin hook-tab-misc(){}
-@mixin hook-inverse-tab(){}
-@mixin hook-inverse-tab-item(){}
-@mixin hook-inverse-tab-item-hover(){}
-@mixin hook-inverse-tab-item-active(){}
-@mixin hook-inverse-tab-item-disabled(){}
-@mixin hook-table(){}
-@mixin hook-table-header-cell(){}
-@mixin hook-table-cell(){}
-@mixin hook-table-footer(){}
-@mixin hook-table-caption(){}
-@mixin hook-table-row-active(){}
-@mixin hook-table-divider(){}
-@mixin hook-table-striped(){}
-@mixin hook-table-hover(){}
-@mixin hook-table-small(){}
-@mixin hook-table-large(){}
-@mixin hook-table-misc(){}
-@mixin hook-inverse-table-header-cell(){}
-@mixin hook-inverse-table-caption(){}
-@mixin hook-inverse-table-row-active(){}
-@mixin hook-inverse-table-divider(){}
-@mixin hook-inverse-table-striped(){}
-@mixin hook-inverse-table-hover(){}
-@mixin hook-inverse-component-table(){
-
- .uk-table th {
- color: $inverse-table-header-cell-color;
- @if(mixin-exists(hook-inverse-table-header-cell)) {@include hook-inverse-table-header-cell();}
- }
-
- .uk-table caption {
- color: $inverse-table-caption-color;
- @if(mixin-exists(hook-inverse-table-caption)) {@include hook-inverse-table-caption();}
- }
-
- .uk-table > tr.uk-active,
- .uk-table tbody tr.uk-active {
- background: $inverse-table-row-active-background;
- @if(mixin-exists(hook-inverse-table-row-active)) {@include hook-inverse-table-row-active();}
- }
-
- .uk-table-divider > tr:not(:first-child),
- .uk-table-divider > :not(:first-child) > tr,
- .uk-table-divider > :first-child > tr:not(:first-child) {
- border-top-color: $inverse-table-divider-border;
- @if(mixin-exists(hook-inverse-table-divider)) {@include hook-inverse-table-divider();}
- }
-
- .uk-table-striped > tr:nth-of-type(odd),
- .uk-table-striped tbody tr:nth-of-type(odd) {
- background: $inverse-table-striped-row-background;
- @if(mixin-exists(hook-inverse-table-striped)) {@include hook-inverse-table-striped();}
- }
-
- .uk-table-hover > tr:hover,
- .uk-table-hover tbody tr:hover {
- background: $inverse-table-hover-row-background;
- @if(mixin-exists(hook-inverse-table-hover)) {@include hook-inverse-table-hover();}
- }
-
-}
-@mixin hook-text-lead(){}
-@mixin hook-text-meta(){}
-@mixin hook-text-small(){}
-@mixin hook-text-large(){}
-@mixin hook-text-background(){}
-@mixin hook-text-misc(){}
-@mixin hook-inverse-text-lead(){}
-@mixin hook-inverse-text-meta(){}
-@mixin hook-thumbnav(){}
-@mixin hook-thumbnav-item(){}
-@mixin hook-thumbnav-item-hover(){}
-@mixin hook-thumbnav-item-active(){}
-@mixin hook-thumbnav-misc(){}
-@mixin hook-inverse-thumbnav-item(){}
-@mixin hook-inverse-thumbnav-item-hover(){}
-@mixin hook-inverse-thumbnav-item-active(){}
-@mixin hook-inverse-component-thumbnav(){
-
- .uk-thumbnav > * > * {
- @if(mixin-exists(hook-inverse-thumbnav-item)) {@include hook-inverse-thumbnav-item();}
- }
-
- .uk-thumbnav > * > :hover,
- .uk-thumbnav > * > :focus {
- @if(mixin-exists(hook-inverse-thumbnav-item-hover)) {@include hook-inverse-thumbnav-item-hover();}
- }
-
- .uk-thumbnav > .uk-active > * {
- @if(mixin-exists(hook-inverse-thumbnav-item-active)) {@include hook-inverse-thumbnav-item-active();}
- }
-
-}
-@mixin hook-tile(){}
-@mixin hook-tile-default(){}
-@mixin hook-tile-muted(){}
-@mixin hook-tile-primary(){}
-@mixin hook-tile-secondary(){}
-@mixin hook-tile-misc(){}
-@mixin hook-tooltip(){}
-@mixin hook-tooltip-misc(){}
-@mixin hook-totop(){}
-@mixin hook-totop-hover(){}
-@mixin hook-totop-active(){}
-@mixin hook-totop-misc(){}
-@mixin hook-inverse-totop(){}
-@mixin hook-inverse-totop-hover(){}
-@mixin hook-inverse-totop-active(){}
-@mixin hook-transition-misc(){}
-@mixin hook-panel-scrollable(){}
-@mixin hook-box-shadow-bottom(){}
-@mixin hook-dropcap(){}
-@mixin hook-leader(){}
-@mixin hook-logo(){}
-@mixin hook-logo-hover(){}
-@mixin hook-utility-misc(){}
-@mixin hook-inverse-dropcap(){}
-@mixin hook-inverse-leader(){}
-@mixin hook-inverse-logo(){}
-@mixin hook-inverse-logo-hover(){}
-@mixin hook-visibility-misc(){}
-@mixin hook-width-misc(){}
\ No newline at end of file
diff --git a/_sass/uikit/theme/_import.scss b/_sass/uikit/theme/_import.scss
deleted file mode 100644
index b08e50b6a3..0000000000
--- a/_sass/uikit/theme/_import.scss
+++ /dev/null
@@ -1,78 +0,0 @@
-// Base
-@import "variables.scss";
-@import "base.scss";
-
-// Elements
-@import "link.scss";
-@import "heading.scss";
-@import "divider.scss";
-@import "list.scss";
-@import "description-list.scss";
-@import "table.scss";
-@import "icon.scss";
-@import "form-range.scss";
-@import "form.scss";
-@import "button.scss";
-
-// Layout
-@import "section.scss";
-@import "container.scss";
-@import "grid.scss";
-@import "tile.scss";
-@import "card.scss";
-
-// Common
-@import "close.scss";
-@import "spinner.scss";
-@import "marker.scss";
-@import "totop.scss";
-@import "alert.scss";
-@import "badge.scss";
-@import "label.scss";
-@import "overlay.scss";
-@import "article.scss";
-@import "comment.scss";
-@import "search.scss";
-
-// Navs
-@import "nav.scss";
-@import "navbar.scss";
-@import "subnav.scss";
-@import "breadcrumb.scss";
-@import "pagination.scss";
-@import "tab.scss";
-@import "slidenav.scss";
-@import "dotnav.scss";
-@import "thumbnav.scss";
-
-// JavaScript
-@import "accordion.scss";
-@import "drop.scss";
-@import "dropdown.scss";
-@import "modal.scss";
-@import "lightbox.scss";
-@import "sticky.scss";
-@import "offcanvas.scss";
-
-// Additional
-@import "iconnav.scss";
-@import "notification.scss";
-@import "tooltip.scss";
-@import "placeholder.scss";
-@import "progress.scss";
-@import "sortable.scss";
-@import "countdown.scss";
-
-// Utilities
-@import "animation.scss";
-@import "width.scss";
-@import "text.scss";
-@import "column.scss";
-@import "background.scss";
-@import "align.scss";
-@import "utility.scss";
-@import "margin.scss";
-@import "padding.scss";
-@import "position.scss";
-@import "transition.scss";
-@import "inverse.scss";
diff --git a/_sass/uikit/theme/accordion.scss b/_sass/uikit/theme/accordion.scss
deleted file mode 100644
index 3e44609f4f..0000000000
--- a/_sass/uikit/theme/accordion.scss
+++ /dev/null
@@ -1,58 +0,0 @@
-//
-// Component: Accordion
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-//
-// New
-//
-
-$accordion-icon-color: $global-color !default;
-$internal-accordion-open-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2213%22%20height%3D%2213%22%20viewBox%3D%220%200%2013%2013%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Crect%20fill%3D%22#000%22%20width%3D%2213%22%20height%3D%221%22%20x%3D%220%22%20y%3D%226%22%20%2F%3E%0A%3C%2Fsvg%3E" !default;
-$internal-accordion-close-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2213%22%20height%3D%2213%22%20viewBox%3D%220%200%2013%2013%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Crect%20fill%3D%22#000%22%20width%3D%2213%22%20height%3D%221%22%20x%3D%220%22%20y%3D%226%22%20%2F%3E%0A%20%20%20%20%3Crect%20fill%3D%22#000%22%20width%3D%221%22%20height%3D%2213%22%20x%3D%226%22%20y%3D%220%22%20%2F%3E%0A%3C%2Fsvg%3E" !default;
-
-
-// Component
-// ========================================================================
-
-// @mixin hook-accordion(){}
-
-
-// Item
-// ========================================================================
-
-// @mixin hook-accordion-item(){}
-
-
-// Title
-// ========================================================================
-
-
-
-// @mixin hook-accordion-title-hover(){}
-
-
-// Content
-// ========================================================================
-
-// @mixin hook-accordion-content(){}
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-accordion-misc(){}
-
-// Inverse
-// ========================================================================
-
-// @mixin hook-inverse-accordion-item(){}
-
-// @mixin hook-inverse-accordion-title(){}
-// @mixin hook-inverse-accordion-title-hover(){}
-
-
diff --git a/_sass/uikit/theme/alert.scss b/_sass/uikit/theme/alert.scss
deleted file mode 100644
index c4baa7ca90..0000000000
--- a/_sass/uikit/theme/alert.scss
+++ /dev/null
@@ -1,46 +0,0 @@
-//
-// Component: Alert
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-//
-// New
-//
-
-$alert-close-opacity: 0.4 !default;
-$alert-close-hover-opacity: 0.8 !default;
-
-
-// Component
-// ========================================================================
-
-// @mixin hook-alert(){}
-
-
-// Close
-// ========================================================================
-
-
-
-
-
-
-// Style modifiers
-// ========================================================================
-
-// @mixin hook-alert-primary(){}
-
-// @mixin hook-alert-success(){}
-
-// @mixin hook-alert-warning(){}
-
-// @mixin hook-alert-danger(){}
-
-
-// Miscellaneous
-// ========================================================================
-
diff --git a/_sass/uikit/theme/align.scss b/_sass/uikit/theme/align.scss
deleted file mode 100644
index 290abd4115..0000000000
--- a/_sass/uikit/theme/align.scss
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-// Component: Align
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-align-misc(){}
\ No newline at end of file
diff --git a/_sass/uikit/theme/animation.scss b/_sass/uikit/theme/animation.scss
deleted file mode 100644
index 03ebbc6eae..0000000000
--- a/_sass/uikit/theme/animation.scss
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-// Component: Animation
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-animation-misc(){}
\ No newline at end of file
diff --git a/_sass/uikit/theme/article.scss b/_sass/uikit/theme/article.scss
deleted file mode 100644
index a698e3ed18..0000000000
--- a/_sass/uikit/theme/article.scss
+++ /dev/null
@@ -1,51 +0,0 @@
-//
-// Component: Article
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-//
-// New
-//
-
-$article-meta-link-color: $article-meta-color !default;
-$article-meta-link-hover-color: $global-color !default;
-
-
-// Component
-// ========================================================================
-
-// @mixin hook-article(){}
-
-
-// Adjacent sibling
-// ========================================================================
-
-// @mixin hook-article-adjacent(){}
-
-
-// Title
-// ========================================================================
-
-// @mixin hook-article-title(){}
-
-
-// Meta
-// ========================================================================
-
-
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-article-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-// @mixin hook-inverse-article-meta(){}
\ No newline at end of file
diff --git a/_sass/uikit/theme/background.scss b/_sass/uikit/theme/background.scss
deleted file mode 100644
index 29e062e9d2..0000000000
--- a/_sass/uikit/theme/background.scss
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-// Component: Background
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-background-misc(){}
\ No newline at end of file
diff --git a/_sass/uikit/theme/badge.scss b/_sass/uikit/theme/badge.scss
deleted file mode 100644
index 22ae937122..0000000000
--- a/_sass/uikit/theme/badge.scss
+++ /dev/null
@@ -1,29 +0,0 @@
-//
-// Component: Badge
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-
-// Component
-// ========================================================================
-
-// @mixin hook-badge(){}
-
-// @mixin hook-badge-hover(){}
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-badge-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-// @mixin hook-inverse-badge(){}
-// @mixin hook-inverse-badge-hover(){}
\ No newline at end of file
diff --git a/_sass/uikit/theme/base.scss b/_sass/uikit/theme/base.scss
deleted file mode 100644
index 2c1c33569e..0000000000
--- a/_sass/uikit/theme/base.scss
+++ /dev/null
@@ -1,116 +0,0 @@
-//
-// Component: Base
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-//
-// New
-//
-
-$base-code-padding-horizontal: 6px !default;
-$base-code-padding-vertical: 2px !default;
-$base-code-background: $global-muted-background !default;
-
-$base-blockquote-color: $global-emphasis-color !default;
-
-$base-blockquote-footer-color: $global-color !default;
-
-$base-pre-padding: 10px !default;
-$base-pre-background: $global-background !default;
-$base-pre-border-width: $global-border-width !default;
-$base-pre-border: $global-border !default;
-$base-pre-border-radius: 3px !default;
-
-
-// Body
-// ========================================================================
-
-// @mixin hook-base-body(){}
-
-
-// Links
-// ========================================================================
-
-// @mixin hook-base-link(){}
-
-// @mixin hook-base-link-hover(){}
-
-
-// Text-level semantics
-// ========================================================================
-
-
-
-
-// Headings
-// ========================================================================
-
-// @mixin hook-base-heading(){}
-
-// @mixin hook-base-h1(){}
-
-// @mixin hook-base-h2(){}
-
-// @mixin hook-base-h3(){}
-
-// @mixin hook-base-h4(){}
-
-// @mixin hook-base-h5(){}
-
-// @mixin hook-base-h6(){}
-
-
-// Horizontal rules
-// ========================================================================
-
-// @mixin hook-base-hr(){}
-
-
-// Blockquotes
-// ========================================================================
-
-
-
-
-
-
-// Preformatted text
-// ========================================================================
-
-
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-base-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-$inverse-base-blockquote-color: $inverse-global-emphasis-color !default;
-$inverse-base-blockquote-footer-color: $inverse-global-color !default;
-
-// @mixin hook-inverse-base-link(){}
-// @mixin hook-inverse-base-link-hover(){}
-
-
-
-// @mixin hook-inverse-base-heading(){}
-
-// @mixin hook-inverse-base-h1(){}
-// @mixin hook-inverse-base-h2(){}
-// @mixin hook-inverse-base-h3(){}
-// @mixin hook-inverse-base-h4(){}
-// @mixin hook-inverse-base-h5(){}
-// @mixin hook-inverse-base-h6(){}
-
-
-
-
-// @mixin hook-inverse-base-hr(){}
\ No newline at end of file
diff --git a/_sass/uikit/theme/breadcrumb.scss b/_sass/uikit/theme/breadcrumb.scss
deleted file mode 100644
index 40c04e5d9e..0000000000
--- a/_sass/uikit/theme/breadcrumb.scss
+++ /dev/null
@@ -1,45 +0,0 @@
-//
-// Component: Breadcrumb
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-
-// Component
-// ========================================================================
-
-// @mixin hook-breadcrumb(){}
-
-
-// Items
-// ========================================================================
-
-// @mixin hook-breadcrumb-item(){}
-
-// @mixin hook-breadcrumb-item-hover(){}
-
-// @mixin hook-breadcrumb-item-disabled(){}
-
-// @mixin hook-breadcrumb-item-active(){}
-
-// @mixin hook-breadcrumb-divider(){}
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-breadcrumb-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-// @mixin hook-inverse-breadcrumb-item(){}
-// @mixin hook-inverse-breadcrumb-item-hover(){}
-// @mixin hook-inverse-breadcrumb-item-disabled(){}
-// @mixin hook-inverse-breadcrumb-item-active(){}
-
-// @mixin hook-inverse-breadcrumb-divider(){}
\ No newline at end of file
diff --git a/_sass/uikit/theme/button.scss b/_sass/uikit/theme/button.scss
deleted file mode 100644
index 6acb5094e1..0000000000
--- a/_sass/uikit/theme/button.scss
+++ /dev/null
@@ -1,161 +0,0 @@
-//
-// Component: Button
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$button-line-height: $global-control-height - ($button-border-width * 2) !default;
-$button-small-line-height: $global-control-small-height - ($button-border-width * 2) !default;
-$button-large-line-height: $global-control-large-height - ($button-border-width * 2) !default;
-
-$button-font-size: $global-small-font-size !default;
-$button-large-font-size: $global-small-font-size !default;
-
-$button-default-background: transparent !default;
-$button-default-hover-background: transparent !default;
-$button-default-active-background: transparent !default;
-
-$button-disabled-background: transparent !default;
-
-$button-text-color: $global-emphasis-color !default;
-$button-text-hover-color: $global-emphasis-color !default;
-
-//
-// New
-//
-
-$button-text-transform: uppercase !default;
-
-$button-border-width: $global-border-width !default;
-
-$button-default-border: $global-border !default;
-$button-default-hover-border: darken($global-border, 20%) !default;
-$button-default-active-border: darken($global-border, 30%) !default;
-
-$button-disabled-border: $global-border !default;
-
-$button-text-border-width: $global-border-width !default;
-$button-text-border: $button-text-hover-color !default;
-
-
-// Component
-// ========================================================================
-
-
-
-// @mixin hook-button-hover(){}
-
-// @mixin hook-button-focus(){}
-
-// @mixin hook-button-active(){}
-
-
-// Style modifiers
-// ========================================================================
-
-
-
-
-
-
-
-//
-// Primary
-//
-
-
-
-// @mixin hook-button-primary-hover(){}
-
-// @mixin hook-button-primary-active(){}
-
-//
-// Secondary
-//
-
-
-
-// @mixin hook-button-secondary-hover(){}
-
-// @mixin hook-button-secondary-active(){}
-
-//
-// Danger
-//
-
-
-
-// @mixin hook-button-danger-hover(){}
-
-// @mixin hook-button-danger-active(){}
-
-
-// Disabled
-// ========================================================================
-
-
-
-
-// Size modifiers
-// ========================================================================
-
-// @mixin hook-button-small(){}
-
-// @mixin hook-button-large(){}
-
-
-// Text modifier
-// ========================================================================
-
-
-
-
-
-
-
-
-// Link modifier
-// ========================================================================
-
-// @mixin hook-button-link(){}
-
-
-// Miscellaneous
-// ========================================================================
-
-
-
-
-// Inverse
-// ========================================================================
-
-$inverse-button-default-background: transparent !default;
-$inverse-button-default-color: $inverse-global-emphasis-color !default;
-$inverse-button-default-hover-background: transparent !default;
-$inverse-button-default-hover-color: $inverse-global-emphasis-color !default;
-$inverse-button-default-active-background: transparent !default;
-$inverse-button-default-active-color: $inverse-global-emphasis-color !default;
-
-$inverse-button-text-color: $inverse-global-emphasis-color !default;
-$inverse-button-text-hover-color: $inverse-global-emphasis-color !default;
-
-
-
-
-
-// @mixin hook-inverse-button-primary(){}
-// @mixin hook-inverse-button-primary-hover(){}
-// @mixin hook-inverse-button-primary-active(){}
-
-// @mixin hook-inverse-button-secondary(){}
-// @mixin hook-inverse-button-secondary-hover(){}
-// @mixin hook-inverse-button-secondary-active(){}
-
-
-// @mixin hook-inverse-button-text-hover(){}
-// @mixin hook-inverse-button-text-disabled(){}
-
-// @mixin hook-inverse-button-link(){}
\ No newline at end of file
diff --git a/_sass/uikit/theme/card.scss b/_sass/uikit/theme/card.scss
deleted file mode 100644
index 9e8fe2bc85..0000000000
--- a/_sass/uikit/theme/card.scss
+++ /dev/null
@@ -1,125 +0,0 @@
-//
-// Component: Card
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$card-hover-background: $global-background !default;
-
-$card-default-background: $global-background !default;
-$card-default-hover-background: $card-default-background !default;
-
-$card-primary-hover-background: $card-primary-background !default;
-
-$card-secondary-hover-background: $card-secondary-background !default;
-
-//
-// New
-//
-
-$card-hover-box-shadow: $global-large-box-shadow !default;
-
-$card-default-box-shadow: $global-medium-box-shadow !default;
-$card-default-hover-box-shadow: $global-large-box-shadow !default;
-
-$card-default-header-border-width: $global-border-width !default;
-$card-default-header-border: $global-border !default;
-
-$card-default-footer-border-width: $global-border-width !default;
-$card-default-footer-border: $global-border !default;
-
-$card-primary-box-shadow: $global-medium-box-shadow !default;
-$card-primary-hover-box-shadow: $global-large-box-shadow !default;
-
-$card-secondary-box-shadow: $global-medium-box-shadow !default;
-$card-secondary-hover-box-shadow: $global-large-box-shadow !default;
-
-
-// Component
-// ========================================================================
-
-
-
-
-// Sections
-// ========================================================================
-
-// @mixin hook-card-body(){}
-
-// @mixin hook-card-header(){}
-
-// @mixin hook-card-footer(){}
-
-
-// Media
-// ========================================================================
-
-// @mixin hook-card-media(){}
-
-// @mixin hook-card-media-top(){}
-
-// @mixin hook-card-media-bottom(){}
-
-// @mixin hook-card-media-left(){}
-
-// @mixin hook-card-media-right(){}
-
-
-// Title
-// ========================================================================
-
-// @mixin hook-card-title(){}
-
-
-// Badge
-// ========================================================================
-
-// @mixin hook-card-badge(){}
-
-
-// Hover modifier
-// ========================================================================
-
-
-
-
-// Style modifiers
-// ========================================================================
-
-
-
-// @mixin hook-card-default-title(){}
-
-
-
-
-
-
-
-//
-// Primary
-//
-
-
-
-// @mixin hook-card-primary-title(){}
-
-
-
-//
-// Secondary
-//
-
-
-
-// @mixin hook-card-secondary-title(){}
-
-
-
-
-// Miscellaneous
-// ========================================================================
-
diff --git a/_sass/uikit/theme/close.scss b/_sass/uikit/theme/close.scss
deleted file mode 100644
index f0762942f8..0000000000
--- a/_sass/uikit/theme/close.scss
+++ /dev/null
@@ -1,29 +0,0 @@
-//
-// Component: Close
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-
-// Component
-// ========================================================================
-
-
-
-// @mixin hook-close-hover(){}
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-close-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-// @mixin hook-inverse-close(){}
-// @mixin hook-inverse-close-hover(){}
\ No newline at end of file
diff --git a/_sass/uikit/theme/column.scss b/_sass/uikit/theme/column.scss
deleted file mode 100644
index 80be850572..0000000000
--- a/_sass/uikit/theme/column.scss
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-// Component: Column
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-column-misc(){}
\ No newline at end of file
diff --git a/_sass/uikit/theme/comment.scss b/_sass/uikit/theme/comment.scss
deleted file mode 100644
index a486c59142..0000000000
--- a/_sass/uikit/theme/comment.scss
+++ /dev/null
@@ -1,69 +0,0 @@
-//
-// Component: Comment
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-//
-// New
-//
-
-$comment-primary-padding: $global-gutter !default;
-$comment-primary-background: $global-muted-background !default;
-
-
-// Component
-// ========================================================================
-
-// @mixin hook-comment(){}
-
-
-// Sections
-// ========================================================================
-
-// @mixin hook-comment-body(){}
-
-// @mixin hook-comment-header(){}
-
-
-// Title
-// ========================================================================
-
-// @mixin hook-comment-title(){}
-
-
-// Meta
-// ========================================================================
-
-// @mixin hook-comment-meta(){}
-
-
-// Avatar
-// ========================================================================
-
-// @mixin hook-comment-avatar(){}
-
-
-// List
-// ========================================================================
-
-// @mixin hook-comment-list-adjacent(){}
-
-// @mixin hook-comment-list-sub(){}
-
-// @mixin hook-comment-list-sub-adjacent(){}
-
-
-// Style modifier
-// ========================================================================
-
-
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-comment-misc(){}
\ No newline at end of file
diff --git a/_sass/uikit/theme/container.scss b/_sass/uikit/theme/container.scss
deleted file mode 100644
index ba77ded72e..0000000000
--- a/_sass/uikit/theme/container.scss
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-// Component: Container
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-container-misc(){}
\ No newline at end of file
diff --git a/_sass/uikit/theme/countdown.scss b/_sass/uikit/theme/countdown.scss
deleted file mode 100644
index 01f1761ca3..0000000000
--- a/_sass/uikit/theme/countdown.scss
+++ /dev/null
@@ -1,53 +0,0 @@
-//
-// Component: Countdown
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-
-// Component
-// ========================================================================
-
-// @mixin hook-countdown(){}
-
-
-// Item
-// ========================================================================
-
-// @mixin hook-countdown-item(){}
-
-
-// Number
-// ========================================================================
-
-// @mixin hook-countdown-number(){}
-
-
-// Separator
-// ========================================================================
-
-// @mixin hook-countdown-separator(){}
-
-
-// Label
-// ========================================================================
-
-// @mixin hook-countdown-label(){}
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-countdown-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-// @mixin hook-inverse-countdown-item(){}
-// @mixin hook-inverse-countdown-number(){}
-// @mixin hook-inverse-countdown-separator(){}
-// @mixin hook-inverse-countdown-label(){}
diff --git a/_sass/uikit/theme/description-list.scss b/_sass/uikit/theme/description-list.scss
deleted file mode 100644
index 8f836d6321..0000000000
--- a/_sass/uikit/theme/description-list.scss
+++ /dev/null
@@ -1,32 +0,0 @@
-//
-// Component: Description list
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$description-list-term-font-size: $global-small-font-size !default;
-$description-list-term-font-weight: normal !default;
-$description-list-term-text-transform: uppercase !default;
-
-
-// Component
-// ========================================================================
-
-
-
-// @mixin hook-description-list-description(){}
-
-
-// Style modifier
-// ========================================================================
-
-// @mixin hook-description-list-divider-term(){}
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-description-list-misc(){}
\ No newline at end of file
diff --git a/_sass/uikit/theme/divider.scss b/_sass/uikit/theme/divider.scss
deleted file mode 100644
index 59e2c9cc62..0000000000
--- a/_sass/uikit/theme/divider.scss
+++ /dev/null
@@ -1,41 +0,0 @@
-//
-// Component: Divider
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-
-// Icon
-// ========================================================================
-
-// @mixin hook-divider-icon(){}
-
-// @mixin hook-divider-icon-line(){}
-
-// @mixin hook-divider-icon-line-left(){}
-
-// @mixin hook-divider-icon-line-right(){}
-
-
-// Small
-// ========================================================================
-
-// @mixin hook-divider-small(){}
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-divider-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-// @mixin hook-inverse-divider-icon(){}
-// @mixin hook-inverse-divider-icon-line(){}
-
-// @mixin hook-inverse-divider-small(){}
\ No newline at end of file
diff --git a/_sass/uikit/theme/dotnav.scss b/_sass/uikit/theme/dotnav.scss
deleted file mode 100644
index 1bc835970f..0000000000
--- a/_sass/uikit/theme/dotnav.scss
+++ /dev/null
@@ -1,52 +0,0 @@
-//
-// Component: Dotnav
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$dotnav-item-background: transparent !default;
-
-//
-// New
-//
-
-$dotnav-item-border-width: 1px !default;
-
-$dotnav-item-border: rgba($global-color, 0.4) !default;
-$dotnav-item-hover-border: transparent !default;
-$dotnav-item-onclick-border: transparent !default;
-$dotnav-item-active-border: transparent !default;
-
-
-// Component
-// ========================================================================
-
-// @mixin hook-dotnav(){}
-
-
-
-
-
-
-
-
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-dotnav-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-$inverse-dotnav-item-background: transparent !default;
-
-// @mixin hook-inverse-dotnav(){}
-
-
-
diff --git a/_sass/uikit/theme/drop.scss b/_sass/uikit/theme/drop.scss
deleted file mode 100644
index 6940984871..0000000000
--- a/_sass/uikit/theme/drop.scss
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-// Component: Drop
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-drop-misc(){}
\ No newline at end of file
diff --git a/_sass/uikit/theme/dropdown.scss b/_sass/uikit/theme/dropdown.scss
deleted file mode 100644
index c5aa02ef44..0000000000
--- a/_sass/uikit/theme/dropdown.scss
+++ /dev/null
@@ -1,45 +0,0 @@
-//
-// Component: Dropdown
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$dropdown-padding: 25px !default;
-$dropdown-background: $global-background !default;
-
-//
-// New
-//
-
-$dropdown-nav-font-size: $global-small-font-size !default;
-
-$dropdown-box-shadow: 0 5px 12px rgba(0,0,0,0.15) !default;
-
-
-// Component
-// ========================================================================
-
-
-
-
-// Nav
-// ========================================================================
-
-
-
-// @mixin hook-dropdown-nav-item(){}
-
-// @mixin hook-dropdown-nav-item-hover(){}
-
-// @mixin hook-dropdown-nav-header(){}
-
-// @mixin hook-dropdown-nav-divider(){}
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-dropdown-misc(){}
\ No newline at end of file
diff --git a/_sass/uikit/theme/form-range.scss b/_sass/uikit/theme/form-range.scss
deleted file mode 100644
index ca424f30e3..0000000000
--- a/_sass/uikit/theme/form-range.scss
+++ /dev/null
@@ -1,45 +0,0 @@
-//
-// Component: Form Range
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$form-range-thumb-background: $global-background !default;
-
-//
-// New
-//
-
-$form-range-thumb-border-width: $global-border-width !default;
-$form-range-thumb-border: darken($global-border, 10%) !default;
-
-$form-range-track-border-radius: 500px !default;
-
-
-// Component
-// ========================================================================
-
-// @mixin hook-form-range(){}
-
-
-// Thumb
-// ========================================================================
-
-
-
-
-// Track
-// ========================================================================
-
-
-
-// @mixin hook-form-range-track-focus(){}
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-form-range-misc(){}
\ No newline at end of file
diff --git a/_sass/uikit/theme/form.scss b/_sass/uikit/theme/form.scss
deleted file mode 100644
index ef80695839..0000000000
--- a/_sass/uikit/theme/form.scss
+++ /dev/null
@@ -1,131 +0,0 @@
-//
-// Component: Form
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$form-line-height: $form-height - (2* $form-border-width) !default;
-
-$form-background: $global-background !default;
-$form-focus-background: $global-background !default;
-
-$form-small-line-height: $form-small-height - (2* $form-border-width) !default;
-$form-large-line-height: $form-large-height - (2* $form-border-width) !default;
-
-$form-radio-background: transparent !default;
-
-$form-stacked-margin-bottom: 5px !default;
-
-//
-// New
-//
-
-$form-border-width: $global-border-width !default;
-$form-border: $global-border !default;
-
-$form-focus-border: $global-primary-background !default;
-
-$form-disabled-border: $global-border !default;
-
-$form-danger-border: $global-danger-background !default;
-$form-success-border: $global-success-background !default;
-
-$form-blank-focus-border: $global-border !default;
-$form-blank-focus-border-style: dashed !default;
-
-$form-radio-border-width: $global-border-width !default;
-$form-radio-border: darken($global-border, 10%) !default;
-
-$form-radio-focus-border: $global-primary-background !default;
-
-$form-radio-checked-border: transparent !default;
-
-$form-radio-disabled-border: $global-border !default;
-
-$form-label-color: $global-emphasis-color !default;
-$form-label-font-size: $global-small-font-size !default;
-
-
-// Component
-// ========================================================================
-
-
-
-// @mixin hook-form-single-line(){}
-
-// @mixin hook-form-multi-line(){}
-
-
-
-
-
-
-// Style modifiers
-// ========================================================================
-
-
-
-
-
-
-
-
-
-
-// Radio and checkbox
-// ========================================================================
-
-
-
-
-
-
-
-// @mixin hook-form-radio-checked-focus(){}
-
-
-
-
-// Legend
-// ========================================================================
-
-// @mixin hook-form-legend(){}
-
-
-// Label
-// ========================================================================
-
-
-
-
-// Layout
-// ========================================================================
-
-// @mixin hook-form-stacked-label(){}
-
-// @mixin hook-form-horizontal-label(){}
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-form-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-$inverse-form-label-color: $inverse-global-emphasis-color !default;
-
-
-
-
-
-
-
-
-// @mixin hook-inverse-form-radio-checked-focus(){}
-
diff --git a/_sass/uikit/theme/grid.scss b/_sass/uikit/theme/grid.scss
deleted file mode 100644
index adc18adbc7..0000000000
--- a/_sass/uikit/theme/grid.scss
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-// Component: Grid
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-grid-misc(){}
\ No newline at end of file
diff --git a/_sass/uikit/theme/heading.scss b/_sass/uikit/theme/heading.scss
deleted file mode 100644
index c6409f0bad..0000000000
--- a/_sass/uikit/theme/heading.scss
+++ /dev/null
@@ -1,59 +0,0 @@
-//
-// Component: Heading
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-
-// Primary
-// ========================================================================
-
-// @mixin hook-heading-primary(){}
-
-
-// Hero
-// ========================================================================
-
-// @mixin hook-heading-hero(){}
-
-
-// Divider
-// ========================================================================
-
-// @mixin hook-heading-divider(){}
-
-
-// Bullet
-// ========================================================================
-
-// @mixin hook-heading-bullet(){}
-
-
-// Line
-// ========================================================================
-
-// @mixin hook-heading-line(){}
-
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-heading-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-// @mixin hook-inverse-heading-primary(){}
-
-// @mixin hook-inverse-heading-hero(){}
-
-// @mixin hook-inverse-heading-divider(){}
-
-// @mixin hook-inverse-heading-bullet(){}
-
-// @mixin hook-inverse-heading-line(){}
diff --git a/_sass/uikit/theme/icon.scss b/_sass/uikit/theme/icon.scss
deleted file mode 100644
index b81c79abd8..0000000000
--- a/_sass/uikit/theme/icon.scss
+++ /dev/null
@@ -1,50 +0,0 @@
-//
-// Component: Icon
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-
-// Style modifiers
-// ========================================================================
-
-//
-// Link
-//
-
-// @mixin hook-icon-link(){}
-
-// @mixin hook-icon-link-hover(){}
-
-// @mixin hook-icon-link-active(){}
-
-//
-// Button
-//
-
-
-
-// @mixin hook-icon-button-hover(){}
-
-// @mixin hook-icon-button-active(){}
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-icon-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-// @mixin hook-inverse-icon-link(){}
-// @mixin hook-inverse-icon-link-hover(){}
-// @mixin hook-inverse-icon-link-active(){}
-
-// @mixin hook-inverse-icon-button(){}
-// @mixin hook-inverse-icon-button-hover(){}
-// @mixin hook-inverse-icon-button-active(){}
\ No newline at end of file
diff --git a/_sass/uikit/theme/iconnav.scss b/_sass/uikit/theme/iconnav.scss
deleted file mode 100644
index 94b4bbf103..0000000000
--- a/_sass/uikit/theme/iconnav.scss
+++ /dev/null
@@ -1,34 +0,0 @@
-//
-// Component: Iconnav
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-
-// Component
-// ========================================================================
-
-// @mixin hook-iconnav(){}
-
-// @mixin hook-iconnav-item(){}
-
-// @mixin hook-iconnav-item-hover(){}
-
-// @mixin hook-iconnav-item-active(){}
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-iconnav-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-// @mixin hook-inverse-iconnav-item(){}
-// @mixin hook-inverse-iconnav-item-hover(){}
-// @mixin hook-inverse-iconnav-item-active(){}
\ No newline at end of file
diff --git a/_sass/uikit/theme/inverse.scss b/_sass/uikit/theme/inverse.scss
deleted file mode 100644
index 75a5a3b168..0000000000
--- a/_sass/uikit/theme/inverse.scss
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-// Component: Inverse
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-
-// Component
-// ========================================================================
-
-// @mixin hook-inverse(){}
\ No newline at end of file
diff --git a/_sass/uikit/theme/label.scss b/_sass/uikit/theme/label.scss
deleted file mode 100644
index ff09ac92cf..0000000000
--- a/_sass/uikit/theme/label.scss
+++ /dev/null
@@ -1,43 +0,0 @@
-//
-// Component: Label
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-//
-// New
-//
-
-$label-border-radius: 2px !default;
-$label-text-transform: uppercase !default;
-
-
-// Component
-// ========================================================================
-
-
-
-
-// Color modifiers
-// ========================================================================
-
-// @mixin hook-label-success(){}
-
-// @mixin hook-label-warning(){}
-
-// @mixin hook-label-danger(){}
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-label-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-// @mixin hook-inverse-label(){}
\ No newline at end of file
diff --git a/_sass/uikit/theme/lightbox.scss b/_sass/uikit/theme/lightbox.scss
deleted file mode 100644
index caabc6250e..0000000000
--- a/_sass/uikit/theme/lightbox.scss
+++ /dev/null
@@ -1,48 +0,0 @@
-//
-// Component: Lightbox
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-
-// Component
-// ========================================================================
-
-// @mixin hook-lightbox(){}
-
-
-// Item
-// ========================================================================
-
-// @mixin hook-lightbox-item(){}
-
-
-// Toolbar
-// ========================================================================
-
-// @mixin hook-lightbox-toolbar(){}
-
-
-// Toolbar Icon
-// ========================================================================
-
-// @mixin hook-lightbox-toolbar-icon(){}
-
-// @mixin hook-lightbox-toolbar-icon-hover(){}
-
-
-// Button
-// ========================================================================
-
-// @mixin hook-lightbox-button(){}
-
-// @mixin hook-lightbox-button-hover(){}
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-lightbox-misc(){}
\ No newline at end of file
diff --git a/_sass/uikit/theme/link.scss b/_sass/uikit/theme/link.scss
deleted file mode 100644
index 0658b58a6d..0000000000
--- a/_sass/uikit/theme/link.scss
+++ /dev/null
@@ -1,55 +0,0 @@
-//
-// Component: Link
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-
-// Muted
-// ========================================================================
-
-// @mixin hook-link-muted(){}
-
-// @mixin hook-link-muted-hover(){}
-
-
-// Text
-// ========================================================================
-
-// @mixin hook-link-text(){}
-
-// @mixin hook-link-text-hover(){}
-
-
-// Heading
-// ========================================================================
-
-// @mixin hook-link-heading(){}
-
-// @mixin hook-link-heading-hover(){}
-
-
-// Reset
-// ========================================================================
-
-// @mixin hook-link-reset(){}
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-link-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-// @mixin hook-inverse-link-muted(){}
-// @mixin hook-inverse-link-muted-hover(){}
-
-// @mixin hook-inverse-link-text-hover(){}
-
-// @mixin hook-inverse-link-heading-hover(){}
diff --git a/_sass/uikit/theme/list.scss b/_sass/uikit/theme/list.scss
deleted file mode 100644
index 67e3c72c8d..0000000000
--- a/_sass/uikit/theme/list.scss
+++ /dev/null
@@ -1,39 +0,0 @@
-//
-// Component: List
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-//
-// New
-//
-
-$list-striped-border-width: $global-border-width !default;
-$list-striped-border: $global-border !default;
-
-
-// Style modifiers
-// ========================================================================
-
-// @mixin hook-list-divider(){}
-
-
-
-// @mixin hook-list-bullet(){}
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-list-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-// @mixin hook-inverse-list-divider(){}
-
-// @mixin hook-inverse-list-bullet(){}
\ No newline at end of file
diff --git a/_sass/uikit/theme/margin.scss b/_sass/uikit/theme/margin.scss
deleted file mode 100644
index a2cdb5ec99..0000000000
--- a/_sass/uikit/theme/margin.scss
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-// Component: Margin
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-margin-misc(){}
\ No newline at end of file
diff --git a/_sass/uikit/theme/marker.scss b/_sass/uikit/theme/marker.scss
deleted file mode 100644
index 1e4fd5f379..0000000000
--- a/_sass/uikit/theme/marker.scss
+++ /dev/null
@@ -1,29 +0,0 @@
-//
-// Component: Marker
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-
-// Component
-// ========================================================================
-
-
-
-// @mixin hook-marker-hover(){}
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-marker-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-// @mixin hook-inverse-marker(){}
-// @mixin hook-inverse-marker-hover(){}
diff --git a/_sass/uikit/theme/modal.scss b/_sass/uikit/theme/modal.scss
deleted file mode 100644
index adc2135808..0000000000
--- a/_sass/uikit/theme/modal.scss
+++ /dev/null
@@ -1,84 +0,0 @@
-//
-// Component: Modal
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$modal-header-background: $modal-dialog-background !default;
-$modal-footer-background: $modal-dialog-background !default;
-
-//
-// New
-//
-
-$modal-header-border-width: $global-border-width !default;
-$modal-header-border: $global-border !default;
-
-$modal-footer-border-width: $global-border-width !default;
-$modal-footer-border: $global-border !default;
-
-$modal-close-full-padding: $global-margin !default;
-$modal-close-full-background: $modal-dialog-background !default;
-
-
-// Component
-// ========================================================================
-
-// @mixin hook-modal(){}
-
-
-// Dialog
-// ========================================================================
-
-// @mixin hook-modal-dialog(){}
-
-
-// Full
-// ========================================================================
-
-// @mixin hook-modal-full(){}
-
-
-// Sections
-// ========================================================================
-
-
-
-// @mixin hook-modal-body(){}
-
-
-
-
-// Title
-// ========================================================================
-
-// @mixin hook-modal-title(){}
-
-
-// Close
-// ========================================================================
-
-// @mixin hook-modal-close(){}
-
-// @mixin hook-modal-close-hover(){}
-
-// @mixin hook-modal-close-default(){}
-
-// @mixin hook-modal-close-default-hover(){}
-
-// @mixin hook-modal-close-outside(){}
-
-// @mixin hook-modal-close-outside-hover(){}
-
-
-
-// @mixin hook-modal-close-full-hover(){}
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-modal-misc(){}
\ No newline at end of file
diff --git a/_sass/uikit/theme/nav.scss b/_sass/uikit/theme/nav.scss
deleted file mode 100644
index 3138498273..0000000000
--- a/_sass/uikit/theme/nav.scss
+++ /dev/null
@@ -1,94 +0,0 @@
-//
-// Component: Nav
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-//
-// New
-//
-
-$nav-default-font-size: $global-small-font-size !default;
-
-
-// Sublists
-// ========================================================================
-
-// @mixin hook-nav-sub(){}
-
-
-// Parent icon modifier
-// ========================================================================
-
-// @mixin hook-nav-parent-icon(){}
-
-
-// Header
-// ========================================================================
-
-// @mixin hook-nav-header(){}
-
-
-// Divider
-// ========================================================================
-
-// @mixin hook-nav-divider(){}
-
-
-// Default style modifier
-// ========================================================================
-
-
-
-// @mixin hook-nav-default-item(){}
-
-// @mixin hook-nav-default-item-hover(){}
-
-// @mixin hook-nav-default-item-active(){}
-
-// @mixin hook-nav-default-header(){}
-
-// @mixin hook-nav-default-divider(){}
-
-
-// Primary style modifier
-// ========================================================================
-
-// @mixin hook-nav-primary(){}
-
-// @mixin hook-nav-primary-item(){}
-
-// @mixin hook-nav-primary-item-hover(){}
-
-// @mixin hook-nav-primary-item-active(){}
-
-// @mixin hook-nav-primary-header(){}
-
-// @mixin hook-nav-primary-divider(){}
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-nav-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-// @mixin hook-inverse-nav-parent-icon(){}
-
-// @mixin hook-inverse-nav-default-item(){}
-// @mixin hook-inverse-nav-default-item-hover(){}
-// @mixin hook-inverse-nav-default-item-active(){}
-// @mixin hook-inverse-nav-default-header(){}
-// @mixin hook-inverse-nav-default-divider(){}
-
-// @mixin hook-inverse-nav-primary-item(){}
-// @mixin hook-inverse-nav-primary-item-hover(){}
-// @mixin hook-inverse-nav-primary-item-active(){}
-// @mixin hook-inverse-nav-primary-header(){}
-// @mixin hook-inverse-nav-primary-divider(){}
\ No newline at end of file
diff --git a/_sass/uikit/theme/navbar.scss b/_sass/uikit/theme/navbar.scss
deleted file mode 100644
index 2a6f237f4e..0000000000
--- a/_sass/uikit/theme/navbar.scss
+++ /dev/null
@@ -1,136 +0,0 @@
-//
-// Component: Navbar
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$navbar-nav-item-font-size: $global-small-font-size !default;
-
-$navbar-dropdown-margin: 15px !default;
-$navbar-dropdown-padding: 25px !default;
-$navbar-dropdown-background: $global-background !default;
-$navbar-dropdown-grid-gutter-horizontal: ($navbar-dropdown-padding * 2) !default;
-
-//
-// New
-//
-
-$navbar-nav-item-text-transform: uppercase !default;
-
-$navbar-dropdown-nav-font-size: $global-small-font-size !default;
-
-$navbar-dropdown-box-shadow: 0 5px 12px rgba(0,0,0,0.15) !default;
-
-$navbar-dropbar-box-shadow: 0 5px 7px rgba(0, 0, 0, 0.05) !default;
-
-$navbar-dropdown-grid-divider-border-width: $global-border-width !default;
-$navbar-dropdown-grid-divider-border: $navbar-dropdown-nav-divider-border !default;
-
-
-// Component
-// ========================================================================
-
-// @mixin hook-navbar(){}
-
-
-// Container
-// ========================================================================
-
-// @mixin hook-navbar-container(){}
-
-
-// Nav
-// ========================================================================
-
-
-
-// @mixin hook-navbar-nav-item-hover(){}
-
-// @mixin hook-navbar-nav-item-onclick(){}
-
-// @mixin hook-navbar-nav-item-active(){}
-
-
-// Item
-// ========================================================================
-
-// @mixin hook-navbar-item(){}
-
-
-// Toggle
-// ========================================================================
-
-// @mixin hook-navbar-toggle(){}
-
-// @mixin hook-navbar-toggle-hover(){}
-
-// @mixin hook-navbar-toggle-icon(){}
-
-// @mixin hook-navbar-toggle-icon-hover(){}
-
-
-// Subtitle
-// ========================================================================
-
-// @mixin hook-navbar-subtitle(){}
-
-
-// Style modifiers
-// ========================================================================
-
-// @mixin hook-navbar-transparent(){}
-
-// @mixin hook-navbar-sticky(){}
-
-
-// Dropdown
-// ========================================================================
-
-
-
-
-
-
-// Dropdown nav
-// ========================================================================
-
-
-
-// @mixin hook-navbar-dropdown-nav-item(){}
-
-// @mixin hook-navbar-dropdown-nav-item-hover(){}
-
-// @mixin hook-navbar-dropdown-nav-header(){}
-
-// @mixin hook-navbar-dropdown-nav-divider(){}
-
-
-// Dropbar
-// ========================================================================
-
-// @mixin hook-navbar-dropbar(){}
-
-
-
-
-// Miscellaneous
-// ========================================================================
-
-
-
-
-// Inverse
-// ========================================================================
-
-// @mixin hook-inverse-navbar-nav-item(){}
-// @mixin hook-inverse-navbar-nav-item-hover(){}
-// @mixin hook-inverse-navbar-nav-item-onclick(){}
-// @mixin hook-inverse-navbar-nav-item-active(){}
-
-// @mixin hook-inverse-navbar-item(){}
-
-// @mixin hook-inverse-navbar-toggle(){}
-// @mixin hook-inverse-navbar-toggle-hover(){}
\ No newline at end of file
diff --git a/_sass/uikit/theme/notification.scss b/_sass/uikit/theme/notification.scss
deleted file mode 100644
index 57d5b5531b..0000000000
--- a/_sass/uikit/theme/notification.scss
+++ /dev/null
@@ -1,44 +0,0 @@
-//
-// Component: Notification
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-
-// Component
-// ========================================================================
-
-// @mixin hook-notification(){}
-
-
-// Message
-// ========================================================================
-
-// @mixin hook-notification-message(){}
-
-
-// Close
-// ========================================================================
-
-// @mixin hook-notification-close(){}
-
-
-// Style modifiers
-// ========================================================================
-
-// @mixin hook-notification-primary(){}
-
-// @mixin hook-notification-success(){}
-
-// @mixin hook-notification-warning(){}
-
-// @mixin hook-notification-danger(){}
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-notification-misc(){}
\ No newline at end of file
diff --git a/_sass/uikit/theme/offcanvas.scss b/_sass/uikit/theme/offcanvas.scss
deleted file mode 100644
index 283078ef36..0000000000
--- a/_sass/uikit/theme/offcanvas.scss
+++ /dev/null
@@ -1,32 +0,0 @@
-//
-// Component: Off-canvas
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-
-// Bar
-// ========================================================================
-
-// @mixin hook-offcanvas-bar(){}
-
-
-// Close
-// ========================================================================
-
-// @mixin hook-offcanvas-close(){}
-
-
-// Overlay
-// ========================================================================
-
-// @mixin hook-offcanvas-overlay(){}
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-offcanvas-misc(){}
\ No newline at end of file
diff --git a/_sass/uikit/theme/overlay.scss b/_sass/uikit/theme/overlay.scss
deleted file mode 100644
index 68cda45259..0000000000
--- a/_sass/uikit/theme/overlay.scss
+++ /dev/null
@@ -1,33 +0,0 @@
-//
-// Component: Overlay
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-
-// Component
-// ========================================================================
-
-// @mixin hook-overlay(){}
-
-// Icon
-// ========================================================================
-
-// @mixin hook-overlay-icon(){}
-
-
-// Style modifiers
-// ========================================================================
-
-// @mixin hook-overlay-default(){}
-
-// @mixin hook-overlay-primary(){}
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-overlay-misc(){}
\ No newline at end of file
diff --git a/_sass/uikit/theme/padding.scss b/_sass/uikit/theme/padding.scss
deleted file mode 100644
index f0737b873a..0000000000
--- a/_sass/uikit/theme/padding.scss
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-// Component: Padding
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-padding-misc(){}
\ No newline at end of file
diff --git a/_sass/uikit/theme/pagination.scss b/_sass/uikit/theme/pagination.scss
deleted file mode 100644
index a777e0c900..0000000000
--- a/_sass/uikit/theme/pagination.scss
+++ /dev/null
@@ -1,41 +0,0 @@
-//
-// Component: Pagination
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-
-// Component
-// ========================================================================
-
-// @mixin hook-pagination(){}
-
-
-// Items
-// ========================================================================
-
-
-
-// @mixin hook-pagination-item-hover(){}
-
-// @mixin hook-pagination-item-active(){}
-
-// @mixin hook-pagination-item-disabled(){}
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-pagination-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-// @mixin hook-inverse-pagination-item(){}
-// @mixin hook-inverse-pagination-item-hover(){}
-// @mixin hook-inverse-pagination-item-active(){}
-// @mixin hook-inverse-pagination-item-disabled(){}
\ No newline at end of file
diff --git a/_sass/uikit/theme/placeholder.scss b/_sass/uikit/theme/placeholder.scss
deleted file mode 100644
index 4ab662cb67..0000000000
--- a/_sass/uikit/theme/placeholder.scss
+++ /dev/null
@@ -1,29 +0,0 @@
-//
-// Component: Placeholder
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$placeholder-background: transparent !default;
-
-//
-// New
-//
-
-$placeholder-border-width: $global-border-width !default;
-$placeholder-border: $global-border !default;
-
-
-// Component
-// ========================================================================
-
-
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-placeholder-misc(){}
diff --git a/_sass/uikit/theme/position.scss b/_sass/uikit/theme/position.scss
deleted file mode 100644
index fc69520898..0000000000
--- a/_sass/uikit/theme/position.scss
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-// Component: Position
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-position-misc(){}
\ No newline at end of file
diff --git a/_sass/uikit/theme/progress.scss b/_sass/uikit/theme/progress.scss
deleted file mode 100644
index 9ca100a3e6..0000000000
--- a/_sass/uikit/theme/progress.scss
+++ /dev/null
@@ -1,24 +0,0 @@
-//
-// Component: Progress
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$progress-border-radius: 500px !default;
-
-
-// Component
-// ========================================================================
-
-
-
-// @mixin hook-progress-bar(){}
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-progress-misc(){}
diff --git a/_sass/uikit/theme/search.scss b/_sass/uikit/theme/search.scss
deleted file mode 100644
index f9e710e2d7..0000000000
--- a/_sass/uikit/theme/search.scss
+++ /dev/null
@@ -1,73 +0,0 @@
-//
-// Component: Search
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$search-default-background: transparent !default;
-
-//
-// New
-//
-
-$search-default-border-width: $global-border-width !default;
-$search-default-border: $global-border !default;
-
-
-// Component
-// ========================================================================
-
-// @mixin hook-search-input(){}
-
-
-// Default modifiers
-// ========================================================================
-
-
-
-
-// Navbar modifiers
-// ========================================================================
-
-// @mixin hook-search-navbar-input(){}
-
-// @mixin hook-search-default-input-focus(){}
-
-
-// Large modifiers
-// ========================================================================
-
-// @mixin hook-search-large-input(){}
-
-
-// Toggle
-// ========================================================================
-
-// @mixin hook-search-toggle(){}
-
-// @mixin hook-search-toggle-hover(){}
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-search-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-$inverse-search-default-background: transparent !default;
-
-
-// @mixin hook-inverse-search-default-input-focus(){}
-
-// @mixin hook-inverse-search-navbar-input(){}
-
-// @mixin hook-inverse-search-large-input(){}
-
-// @mixin hook-inverse-search-toggle(){}
-// @mixin hook-inverse-search-toggle-hover(){}
\ No newline at end of file
diff --git a/_sass/uikit/theme/section.scss b/_sass/uikit/theme/section.scss
deleted file mode 100644
index 6d7f761b6e..0000000000
--- a/_sass/uikit/theme/section.scss
+++ /dev/null
@@ -1,32 +0,0 @@
-//
-// Component: Section
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-
-// Component
-// ========================================================================
-
-// @mixin hook-section(){}
-
-
-// Style modifiers
-// ========================================================================
-
-// @mixin hook-section-default(){}
-
-// @mixin hook-section-muted(){}
-
-// @mixin hook-section-primary(){}
-
-// @mixin hook-section-secondary(){}
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-section-misc(){}
diff --git a/_sass/uikit/theme/slidenav.scss b/_sass/uikit/theme/slidenav.scss
deleted file mode 100644
index c1654e77f1..0000000000
--- a/_sass/uikit/theme/slidenav.scss
+++ /dev/null
@@ -1,52 +0,0 @@
-//
-// Component: Slidenav
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-
-// Component
-// ========================================================================
-
-
-
-// @mixin hook-slidenav-hover(){}
-
-// @mixin hook-slidenav-active(){}
-
-
-// Icon modifier
-// ========================================================================
-
-// @mixin hook-slidenav-previous(){}
-
-// @mixin hook-slidenav-next(){}
-
-
-// Size modifier
-// ========================================================================
-
-// @mixin hook-slidenav-large(){}
-
-
-// Container
-// ========================================================================
-
-// @mixin hook-slidenav-container(){}
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-icon-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-// @mixin hook-inverse-slidenav(){}
-// @mixin hook-inverse-slidenav-hover(){}
-// @mixin hook-inverse-slidenav-active(){}
\ No newline at end of file
diff --git a/_sass/uikit/theme/sortable.scss b/_sass/uikit/theme/sortable.scss
deleted file mode 100644
index 3ab18c3db1..0000000000
--- a/_sass/uikit/theme/sortable.scss
+++ /dev/null
@@ -1,38 +0,0 @@
-//
-// Component: Sortable
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-
-// Component
-// ========================================================================
-
-// @mixin hook-sortable(){}
-
-
-// Drag
-// ========================================================================
-
-// @mixin hook-sortable-drag(){}
-
-
-// Placeholder
-// ========================================================================
-
-// @mixin hook-sortable-placeholder(){}
-
-
-// Empty
-// ========================================================================
-
-// @mixin hook-sortable-empty(){}
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-sortable-misc(){}
diff --git a/_sass/uikit/theme/spinner.scss b/_sass/uikit/theme/spinner.scss
deleted file mode 100644
index d70e10fa81..0000000000
--- a/_sass/uikit/theme/spinner.scss
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-// Component: Spinner
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-spinner-misc(){}
\ No newline at end of file
diff --git a/_sass/uikit/theme/sticky.scss b/_sass/uikit/theme/sticky.scss
deleted file mode 100644
index 94e5ee69ee..0000000000
--- a/_sass/uikit/theme/sticky.scss
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-// Component: Sticky
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-sticky-misc(){}
\ No newline at end of file
diff --git a/_sass/uikit/theme/subnav.scss b/_sass/uikit/theme/subnav.scss
deleted file mode 100644
index f4d1c7fd06..0000000000
--- a/_sass/uikit/theme/subnav.scss
+++ /dev/null
@@ -1,74 +0,0 @@
-//
-// Component: Subnav
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-//
-// New
-//
-
-$subnav-item-font-size: $global-small-font-size !default;
-$subnav-item-text-transform: uppercase !default;
-
-
-// Component
-// ========================================================================
-
-// @mixin hook-subnav(){}
-
-
-
-// @mixin hook-subnav-item-hover(){}
-
-// @mixin hook-subnav-item-active(){}
-
-
-// Divider modifier
-// ========================================================================
-
-// @mixin hook-subnav-divider(){}
-
-
-// Pill modifier
-// ========================================================================
-
-// @mixin hook-subnav-pill-item(){}
-
-// @mixin hook-subnav-pill-item-hover(){}
-
-// @mixin hook-subnav-pill-item-onclick(){}
-
-// @mixin hook-subnav-pill-item-active(){}
-
-
-// Disabled
-// ========================================================================
-
-// @mixin hook-subnav-item-disabled(){}
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-subnav-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-// @mixin hook-inverse-subnav-item(){}
-// @mixin hook-inverse-subnav-item-hover(){}
-// @mixin hook-inverse-subnav-item-active(){}
-
-// @mixin hook-inverse-subnav-divider(){}
-
-// @mixin hook-inverse-subnav-pill-item(){}
-// @mixin hook-inverse-subnav-pill-item-hover(){}
-// @mixin hook-inverse-subnav-pill-item-onclick(){}
-// @mixin hook-inverse-subnav-pill-item-active(){}
-
-// @mixin hook-inverse-subnav-item-disabled(){}
diff --git a/_sass/uikit/theme/tab.scss b/_sass/uikit/theme/tab.scss
deleted file mode 100644
index 51c4ba2866..0000000000
--- a/_sass/uikit/theme/tab.scss
+++ /dev/null
@@ -1,74 +0,0 @@
-//
-// Component: Tab
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-//
-// New
-//
-
-$tab-border-width: $global-border-width !default;
-$tab-border: $global-border !default;
-
-$tab-item-border-width: $global-border-width !default;
-$tab-item-font-size: $global-small-font-size !default;
-$tab-item-text-transform: uppercase !default;
-
-$tab-item-active-border: $global-primary-background !default;
-
-
-// Component
-// ========================================================================
-
-
-
-
-// Items
-// ========================================================================
-
-
-
-// @mixin hook-tab-item-hover(){}
-
-
-
-// @mixin hook-tab-item-disabled(){}
-
-
-// Position modifiers
-// ========================================================================
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-// Miscellaneous
-// ========================================================================
-
-
-
-
-// Inverse
-// ========================================================================
-
-$inverse-tab-border: $inverse-global-border !default;
-
-
-
-// @mixin hook-inverse-tab-item(){}
-// @mixin hook-inverse-tab-item-hover(){}
-
-// @mixin hook-inverse-tab-item-disabled(){}
\ No newline at end of file
diff --git a/_sass/uikit/theme/table.scss b/_sass/uikit/theme/table.scss
deleted file mode 100644
index d6a660793b..0000000000
--- a/_sass/uikit/theme/table.scss
+++ /dev/null
@@ -1,68 +0,0 @@
-//
-// Component: Table
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-$table-header-cell-font-size: $global-small-font-size !default;
-$table-header-cell-font-weight: normal !default;
-$table-header-cell-color: $global-muted-color !default;
-
-//
-// New
-//
-
-$table-striped-border-width: $global-border-width !default;
-$table-striped-border: $global-border !default;
-
-
-// Component
-// ========================================================================
-
-
-
-// @mixin hook-table-cell(){}
-
-// @mixin hook-table-footer(){}
-
-// @mixin hook-table-caption(){}
-
-// @mixin hook-table-row-active(){}
-
-
-// Style modifiers
-// ========================================================================
-
-// @mixin hook-table-divider(){}
-
-
-
-// @mixin hook-table-hover(){}
-
-
-// Size modifier
-// ========================================================================
-
-// @mixin hook-table-small(){}
-
-// @mixin hook-table-large(){}
-
-
-// Miscellaneous
-// ========================================================================
-
-
-
-
-// Inverse
-// ========================================================================
-
-// @mixin hook-inverse-table-header-cell(){}
-// @mixin hook-inverse-table-caption(){}
-// @mixin hook-inverse-table-row-active(){}
-// @mixin hook-inverse-table-divider(){}
-
-// @mixin hook-inverse-table-hover(){}
\ No newline at end of file
diff --git a/_sass/uikit/theme/text.scss b/_sass/uikit/theme/text.scss
deleted file mode 100644
index b6e35c431f..0000000000
--- a/_sass/uikit/theme/text.scss
+++ /dev/null
@@ -1,50 +0,0 @@
-//
-// Component: Text
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-//
-// New
-//
-
-$text-meta-link-color: $text-meta-color !default;
-$text-meta-link-hover-color: $global-color !default;
-
-
-// Style modifiers
-// ========================================================================
-
-// @mixin hook-text-lead(){}
-
-
-
-
-// Size modifiers
-// ========================================================================
-
-// @mixin hook-text-small(){}
-
-// @mixin hook-text-large(){}
-
-
-// Background modifier
-// ========================================================================
-
-// @mixin hook-text-background(){}
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-text-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-// @mixin hook-inverse-text-lead(){}
-// @mixin hook-inverse-text-meta(){}
diff --git a/_sass/uikit/theme/thumbnav.scss b/_sass/uikit/theme/thumbnav.scss
deleted file mode 100644
index 7f26c38aa8..0000000000
--- a/_sass/uikit/theme/thumbnav.scss
+++ /dev/null
@@ -1,42 +0,0 @@
-//
-// Component: Thumbnav
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-//
-// New
-//
-
-$thumbnav-item-background: rgba($global-background, 0.4) !default;
-$thumbnav-item-hover-background: transparent !default;
-$thumbnav-item-active-background: transparent !default;
-
-
-// Component
-// ========================================================================
-
-// @mixin hook-thumbnav(){}
-
-
-
-
-
-
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-thumbnav-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-// @mixin hook-inverse-thumbnav-item(){}
-// @mixin hook-inverse-thumbnav-item-hover(){}
-// @mixin hook-inverse-thumbnav-item-active(){}
\ No newline at end of file
diff --git a/_sass/uikit/theme/tile.scss b/_sass/uikit/theme/tile.scss
deleted file mode 100644
index 2d043a6338..0000000000
--- a/_sass/uikit/theme/tile.scss
+++ /dev/null
@@ -1,32 +0,0 @@
-//
-// Component: Tile
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-
-// Component
-// ========================================================================
-
-// @mixin hook-tile(){}
-
-
-// Style modifiers
-// ========================================================================
-
-// @mixin hook-tile-default(){}
-
-// @mixin hook-tile-muted(){}
-
-// @mixin hook-tile-primary(){}
-
-// @mixin hook-tile-secondary(){}
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-tile-misc(){}
\ No newline at end of file
diff --git a/_sass/uikit/theme/tooltip.scss b/_sass/uikit/theme/tooltip.scss
deleted file mode 100644
index 5115139c31..0000000000
--- a/_sass/uikit/theme/tooltip.scss
+++ /dev/null
@@ -1,20 +0,0 @@
-//
-// Component: Tooltip
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-
-// Component
-// ========================================================================
-
-// @mixin hook-tooltip(){}
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-tooltip-misc(){}
\ No newline at end of file
diff --git a/_sass/uikit/theme/totop.scss b/_sass/uikit/theme/totop.scss
deleted file mode 100644
index feb7165a1d..0000000000
--- a/_sass/uikit/theme/totop.scss
+++ /dev/null
@@ -1,32 +0,0 @@
-//
-// Component: Totop
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-
-// Component
-// ========================================================================
-
-
-
-// @mixin hook-totop-hover(){}
-
-// @mixin hook-totop-active(){}
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-icon-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-// @mixin hook-inverse-totop(){}
-// @mixin hook-inverse-totop-hover(){}
-// @mixin hook-inverse-totop-active(){}
\ No newline at end of file
diff --git a/_sass/uikit/theme/transition.scss b/_sass/uikit/theme/transition.scss
deleted file mode 100644
index fd7bdede45..0000000000
--- a/_sass/uikit/theme/transition.scss
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-// Component: Transition
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-transition-misc(){}
\ No newline at end of file
diff --git a/_sass/uikit/theme/utility.scss b/_sass/uikit/theme/utility.scss
deleted file mode 100644
index ae24e15cf5..0000000000
--- a/_sass/uikit/theme/utility.scss
+++ /dev/null
@@ -1,57 +0,0 @@
-//
-// Component: Utility
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-
-// Panel
-// ========================================================================
-
-// @mixin hook-panel-scrollable(){}
-
-
-// Box-shadow bottom
-// ========================================================================
-
-// @mixin hook-box-shadow-bottom(){}
-
-
-// Drop cap
-// ========================================================================
-
-
-
-
-// Leader
-// ========================================================================
-
-// @mixin hook-leader(){}
-
-
-// Logo
-// ========================================================================
-
-// @mixin hook-logo(){}
-
-// @mixin hook-logo-hover(){}
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-utility-misc(){}
-
-
-// Inverse
-// ========================================================================
-
-// @mixin hook-inverse-dropcap(){}
-
-// @mixin hook-inverse-leader(){}
-
-// @mixin hook-inverse-logo(){}
-// @mixin hook-inverse-logo-hover(){}
\ No newline at end of file
diff --git a/_sass/uikit/theme/variables.scss b/_sass/uikit/theme/variables.scss
deleted file mode 100644
index d74b3a9971..0000000000
--- a/_sass/uikit/theme/variables.scss
+++ /dev/null
@@ -1,36 +0,0 @@
-//
-// Component: Variables
-//
-// ========================================================================
-
-
-// Global variables
-// ========================================================================
-
-//
-// Typography
-//
-
-//
-// Colors
-//
-
-//
-// Backgrounds
-//
-
-//
-// Borders
-//
-
-//
-// Spacings
-//
-
-//
-// Controls
-//
-
-//
-// Z-index
-//
\ No newline at end of file
diff --git a/_sass/uikit/theme/width.scss b/_sass/uikit/theme/width.scss
deleted file mode 100644
index b67a7954ed..0000000000
--- a/_sass/uikit/theme/width.scss
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-// Component: Width
-//
-// ========================================================================
-
-
-// Variables
-// ========================================================================
-
-
-// Miscellaneous
-// ========================================================================
-
-// @mixin hook-width-misc(){}
\ No newline at end of file
diff --git a/_sass/uikit/uikit-theme.scss b/_sass/uikit/uikit-theme.scss
deleted file mode 100644
index 13dbd02217..0000000000
--- a/_sass/uikit/uikit-theme.scss
+++ /dev/null
@@ -1,9 +0,0 @@
-//
-// Theme
-//
-
-@import "theme/_import.scss";
-
-@import "components/_import.scss";
-
-
diff --git a/_sass/uikit/uikit.scss b/_sass/uikit/uikit.scss
deleted file mode 100644
index 662482314f..0000000000
--- a/_sass/uikit/uikit.scss
+++ /dev/null
@@ -1,5 +0,0 @@
-//
-// Core
-//
-
-@import "components/_import.scss";
\ No newline at end of file
diff --git a/_sass/uikit/variables-theme.scss b/_sass/uikit/variables-theme.scss
deleted file mode 100644
index 8aa5a9c40b..0000000000
--- a/_sass/uikit/variables-theme.scss
+++ /dev/null
@@ -1,1093 +0,0 @@
-$global-margin: 20px !default;
-$accordion-item-margin-top: $global-margin !default;
-$global-medium-font-size: 1.25rem !default;
-$accordion-title-font-size: $global-medium-font-size !default;
-$accordion-title-line-height: 1.4 !default;
-$global-emphasis-color: #333 !default;
-$accordion-title-color: $global-emphasis-color !default;
-$global-color: #666 !default;
-$accordion-title-hover-color: $global-color !default;
-$accordion-content-margin-top: $global-margin !default;
-$global-inverse-color: #fff !default;
-$inverse-global-emphasis-color: $global-inverse-color !default;
-$inverse-accordion-title-color: $inverse-global-emphasis-color !default;
-$inverse-global-inverse-color: $global-color !default;
-$inverse-accordion-title-hover-color: $inverse-global-inverse-color !default;
-$global-gutter: 30px !default;
-$align-margin-horizontal: $global-gutter !default;
-$align-margin-vertical: $global-gutter !default;
-$global-medium-gutter: 40px !default;
-$align-margin-horizontal-l: $global-medium-gutter !default;
-$alert-margin-vertical: $global-margin !default;
-$global-small-gutter: 15px !default;
-$alert-padding: $global-small-gutter !default;
-$alert-padding-right: $alert-padding + 14px !default;
-$global-muted-background: #f8f8f8 !default;
-$alert-background: $global-muted-background !default;
-$alert-color: $global-color !default;
-$alert-close-top: $alert-padding + 5px !default;
-$alert-close-right: $alert-padding !default;
-$global-primary-background: #1e87f0 !default;
-$alert-primary-background: lighten(mix(white, $global-primary-background, 40%), 20%) !default;
-$alert-primary-color: $global-primary-background !default;
-$global-success-background: #32d296 !default;
-$alert-success-background: lighten(mix(white, $global-success-background, 40%), 25%) !default;
-$alert-success-color: $global-success-background !default;
-$global-warning-background: #faa05a !default;
-$alert-warning-background: lighten(mix(white, $global-warning-background, 45%), 15%) !default;
-$alert-warning-color: $global-warning-background !default;
-$global-danger-background: #f0506e !default;
-$alert-danger-background: lighten(mix(white, $global-danger-background, 40%), 20%) !default;
-$alert-danger-color: $global-danger-background !default;
-$global-large-margin: 70px !default;
-$article-margin-top: $global-large-margin !default;
-$global-xxlarge-font-size: 2.625rem !default;
-$article-title-font-size: $global-xxlarge-font-size !default;
-$article-title-line-height: 1.2 !default;
-$global-small-font-size: 0.875rem !default;
-$article-meta-font-size: $global-small-font-size !default;
-$article-meta-line-height: 1.4 !default;
-$global-muted-color: #999 !default;
-$article-meta-color: $global-muted-color !default;
-$inverse-global-muted-color: rgba($global-inverse-color, 0.5) !default;
-$inverse-article-meta-color: $inverse-global-muted-color !default;
-$animation-duration: 0.5s !default;
-$animation-fade-duration: 0.8s !default;
-$animation-kenburns-duration: 15s !default;
-$animation-fast-duration: 0.1s !default;
-$animation-slide-small-translate: 10px !default;
-$animation-slide-medium-translate: 50px !default;
-$global-background: #fff !default;
-$background-default-background: $global-background !default;
-$background-muted-background: $global-muted-background !default;
-$background-primary-background: $global-primary-background !default;
-$global-secondary-background: #222 !default;
-$background-secondary-background: $global-secondary-background !default;
-$badge-size: 22px !default;
-$badge-padding-vertical: 0 !default;
-$badge-padding-horizontal: 5px !default;
-$badge-border-radius: 500px !default;
-$badge-background: $global-primary-background !default;
-$badge-color: $global-inverse-color !default;
-$badge-font-size: $global-small-font-size !default;
-$badge-hover-color: $global-inverse-color !default;
-$inverse-global-primary-background: $global-inverse-color !default;
-$inverse-badge-background: $inverse-global-primary-background !default;
-$inverse-badge-color: $inverse-global-inverse-color !default;
-$inverse-badge-hover-color: $inverse-global-inverse-color !default;
-$base-body-background: $global-background !default;
-$global-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif !default;
-$base-body-font-family: $global-font-family !default;
-$base-body-font-weight: normal !default;
-$global-font-size: 16px !default;
-$base-body-font-size: $global-font-size !default;
-$global-line-height: 1.5 !default;
-$base-body-line-height: $global-line-height !default;
-$base-body-color: $global-color !default;
-$global-link-color: #1e87f0 !default;
-$base-link-color: $global-link-color !default;
-$base-link-text-decoration: none !default;
-$global-link-hover-color: #0f6ecd !default;
-$base-link-hover-color: $global-link-hover-color !default;
-$base-link-hover-text-decoration: underline !default;
-$base-strong-font-weight: bolder !default;
-$base-code-font-size: $global-small-font-size !default;
-$base-code-font-family: Consolas, monaco, monospace !default;
-$base-code-color: $global-danger-background !default;
-$base-em-color: $global-danger-background !default;
-$base-ins-background: #ffd !default;
-$base-ins-color: $global-color !default;
-$base-mark-background: #ffd !default;
-$base-mark-color: $global-color !default;
-$base-quote-font-style: italic !default;
-$base-small-font-size: 80% !default;
-$base-margin-vertical: $global-margin !default;
-$base-heading-font-family: $global-font-family !default;
-$base-heading-font-weight: normal !default;
-$base-heading-color: $global-emphasis-color !default;
-$base-heading-text-transform: none !default;
-$global-medium-margin: 40px !default;
-$base-heading-margin-top: $global-medium-margin !default;
-$base-h1-font-size: $global-xxlarge-font-size !default;
-$base-h1-line-height: 1.2 !default;
-$global-xlarge-font-size: 2rem !default;
-$base-h2-font-size: $global-xlarge-font-size !default;
-$base-h2-line-height: 1.3 !default;
-$global-large-font-size: 1.5rem !default;
-$base-h3-font-size: $global-large-font-size !default;
-$base-h3-line-height: 1.4 !default;
-$base-h4-font-size: $global-medium-font-size !default;
-$base-h4-line-height: 1.4 !default;
-$base-h5-font-size: $global-font-size !default;
-$base-h5-line-height: 1.4 !default;
-$base-h6-font-size: $global-small-font-size !default;
-$base-h6-line-height: 1.4 !default;
-$base-list-padding-left: 30px !default;
-$base-hr-margin-vertical: $global-margin !default;
-$global-border-width: 1px !default;
-$base-hr-border-width: $global-border-width !default;
-$global-border: #e5e5e5 !default;
-$base-hr-border: $global-border !default;
-$base-blockquote-font-size: $global-medium-font-size !default;
-$base-blockquote-line-height: 1.5 !default;
-$base-blockquote-font-style: italic !default;
-$base-blockquote-margin-vertical: $global-margin !default;
-$global-small-margin: 10px !default;
-$base-blockquote-footer-margin-top: $global-small-margin !default;
-$base-blockquote-footer-font-size: $global-small-font-size !default;
-$base-blockquote-footer-line-height: 1.5 !default;
-$base-pre-font-size: $global-small-font-size !default;
-$base-pre-line-height: 1.5 !default;
-$base-pre-font-family: $base-code-font-family !default;
-$base-pre-color: $global-color !default;
-$base-selection-background: #39f !default;
-$base-selection-color: $global-inverse-color !default;
-$inverse-global-color: rgba($global-inverse-color, 0.7) !default;
-$inverse-base-color: $inverse-global-color !default;
-$inverse-base-link-color: $inverse-global-emphasis-color !default;
-$inverse-base-link-hover-color: $inverse-global-emphasis-color !default;
-$inverse-base-code-color: $inverse-global-color !default;
-$inverse-base-em-color: $inverse-global-emphasis-color !default;
-$inverse-base-heading-color: $inverse-global-emphasis-color !default;
-$inverse-global-border: rgba($global-inverse-color, 0.2) !default;
-$inverse-base-hr-border: $inverse-global-border !default;
-$breadcrumb-item-font-size: $global-small-font-size !default;
-$breadcrumb-item-color: $global-muted-color !default;
-$breadcrumb-item-hover-color: $global-color !default;
-$breadcrumb-item-hover-text-decoration: none !default;
-$breadcrumb-item-active-color: $global-color !default;
-$breadcrumb-divider: "/" !default;
-$breadcrumb-divider-margin-horizontal: 20px !default;
-$breadcrumb-divider-color: $global-muted-color !default;
-$inverse-breadcrumb-item-color: $inverse-global-muted-color !default;
-$inverse-breadcrumb-item-hover-color: $inverse-global-color !default;
-$inverse-breadcrumb-item-active-color: $inverse-global-color !default;
-$inverse-breadcrumb-divider-color: $inverse-global-muted-color !default;
-$global-control-height: 40px !default;
-$button-border-width: $global-border-width !default;
-$button-line-height: $global-control-height - ($button-border-width * 2) !default;
-$global-control-small-height: 30px !default;
-$button-small-line-height: $global-control-small-height - ($button-border-width * 2) !default;
-$global-control-large-height: 55px !default;
-$button-large-line-height: $global-control-large-height - ($button-border-width * 2) !default;
-$button-font-size: $global-small-font-size !default;
-$button-small-font-size: $global-small-font-size !default;
-$button-large-font-size: $global-small-font-size !default;
-$button-padding-horizontal: $global-gutter !default;
-$button-small-padding-horizontal: $global-small-gutter !default;
-$button-large-padding-horizontal: $global-medium-gutter !default;
-$button-default-background: transparent !default;
-$button-default-color: $global-emphasis-color !default;
-$button-default-hover-background: transparent !default;
-$button-default-hover-color: $global-emphasis-color !default;
-$button-default-active-background: transparent !default;
-$button-default-active-color: $global-emphasis-color !default;
-$button-primary-background: $global-primary-background !default;
-$button-primary-color: $global-inverse-color !default;
-$button-primary-hover-background: darken($button-primary-background, 5%) !default;
-$button-primary-hover-color: $global-inverse-color !default;
-$button-primary-active-background: darken($button-primary-background, 10%) !default;
-$button-primary-active-color: $global-inverse-color !default;
-$button-secondary-background: $global-secondary-background !default;
-$button-secondary-color: $global-inverse-color !default;
-$button-secondary-hover-background: darken($button-secondary-background, 5%) !default;
-$button-secondary-hover-color: $global-inverse-color !default;
-$button-secondary-active-background: darken($button-secondary-background, 10%) !default;
-$button-secondary-active-color: $global-inverse-color !default;
-$button-danger-background: $global-danger-background !default;
-$button-danger-color: $global-inverse-color !default;
-$button-danger-hover-background: darken($button-danger-background, 5%) !default;
-$button-danger-hover-color: $global-inverse-color !default;
-$button-danger-active-background: darken($button-danger-background, 10%) !default;
-$button-danger-active-color: $global-inverse-color !default;
-$button-disabled-background: transparent !default;
-$button-disabled-color: $global-muted-color !default;
-$button-text-line-height: $global-line-height !default;
-$button-text-color: $global-emphasis-color !default;
-$button-text-hover-color: $global-emphasis-color !default;
-$button-text-disabled-color: $global-muted-color !default;
-$button-link-line-height: $global-line-height !default;
-$button-link-color: $global-link-color !default;
-$button-link-hover-color: $global-link-hover-color !default;
-$button-link-hover-text-decoration: underline !default;
-$button-link-disabled-color: $global-muted-color !default;
-$inverse-button-default-background: transparent !default;
-$inverse-button-default-color: $inverse-global-emphasis-color !default;
-$inverse-button-default-hover-background: transparent !default;
-$inverse-button-default-hover-color: $inverse-global-emphasis-color !default;
-$inverse-button-default-active-background: transparent !default;
-$inverse-button-default-active-color: $inverse-global-emphasis-color !default;
-$inverse-button-primary-background: $inverse-global-primary-background !default;
-$inverse-button-primary-color: $inverse-global-inverse-color !default;
-$inverse-button-primary-hover-background: darken($inverse-button-primary-background, 5%) !default;
-$inverse-button-primary-hover-color: $inverse-global-inverse-color !default;
-$inverse-button-primary-active-background: darken($inverse-button-primary-background, 10%) !default;
-$inverse-button-primary-active-color: $inverse-global-inverse-color !default;
-$inverse-button-secondary-background: $inverse-global-primary-background !default;
-$inverse-button-secondary-color: $inverse-global-inverse-color !default;
-$inverse-button-secondary-hover-background: darken($inverse-button-secondary-background, 5%) !default;
-$inverse-button-secondary-hover-color: $inverse-global-inverse-color !default;
-$inverse-button-secondary-active-background: darken($inverse-button-secondary-background, 10%) !default;
-$inverse-button-secondary-active-color: $inverse-global-inverse-color !default;
-$inverse-button-text-color: $inverse-global-emphasis-color !default;
-$inverse-button-text-hover-color: $inverse-global-emphasis-color !default;
-$inverse-button-text-disabled-color: $inverse-global-muted-color !default;
-$inverse-button-link-color: $inverse-global-muted-color !default;
-$inverse-button-link-hover-color: $inverse-global-color !default;
-$card-body-padding-horizontal: $global-gutter !default;
-$card-body-padding-vertical: $global-gutter !default;
-$card-body-padding-horizontal-l: $global-medium-gutter !default;
-$card-body-padding-vertical-l: $global-medium-gutter !default;
-$card-header-padding-horizontal: $global-gutter !default;
-$card-header-padding-vertical: round($global-gutter / 2) !default;
-$card-header-padding-horizontal-l: $global-medium-gutter !default;
-$card-header-padding-vertical-l: round($global-medium-gutter / 2) !default;
-$card-footer-padding-horizontal: $global-gutter !default;
-$card-footer-padding-vertical: ($global-gutter / 2) !default;
-$card-footer-padding-horizontal-l: $global-medium-gutter !default;
-$card-footer-padding-vertical-l: round($global-medium-gutter / 2) !default;
-$card-title-font-size: $global-large-font-size !default;
-$card-title-line-height: 1.4 !default;
-$card-badge-top: $global-gutter !default;
-$card-badge-right: $card-badge-top !default;
-$card-hover-background: $global-background !default;
-$card-default-background: $global-background !default;
-$card-default-color: $global-color !default;
-$card-default-title-color: $global-emphasis-color !default;
-$card-default-hover-background: $card-default-background !default;
-$card-primary-background: $global-primary-background !default;
-$card-primary-color: $global-inverse-color !default;
-$card-primary-title-color: $card-primary-color !default;
-$card-primary-hover-background: $card-primary-background !default;
-$card-primary-color-mode: light !default;
-$card-secondary-background: $global-secondary-background !default;
-$card-secondary-color: $global-inverse-color !default;
-$card-secondary-title-color: $card-secondary-color !default;
-$card-secondary-hover-background: $card-secondary-background !default;
-$card-secondary-color-mode: light !default;
-$card-small-body-padding-horizontal: $global-margin !default;
-$card-small-body-padding-vertical: $global-margin !default;
-$card-small-header-padding-horizontal: $global-margin !default;
-$card-small-header-padding-vertical: round($global-margin / 1.5) !default;
-$card-small-footer-padding-horizontal: $global-margin !default;
-$card-small-footer-padding-vertical: round($global-margin / 1.5) !default;
-$global-large-gutter: 70px !default;
-$card-large-body-padding-horizontal-l: $global-large-gutter !default;
-$card-large-body-padding-vertical-l: $global-large-gutter !default;
-$card-large-header-padding-horizontal-l: $global-large-gutter !default;
-$card-large-header-padding-vertical-l: round($global-large-gutter / 2) !default;
-$card-large-footer-padding-horizontal-l: $global-large-gutter !default;
-$card-large-footer-padding-vertical-l: round($global-large-gutter / 2) !default;
-$close-color: $global-muted-color !default;
-$close-hover-color: $global-color !default;
-$inverse-close-color: $inverse-global-muted-color !default;
-$inverse-close-hover-color: $inverse-global-color !default;
-$column-gutter: $global-gutter !default;
-$column-gutter-l: $global-medium-gutter !default;
-$column-divider-rule-color: $global-border !default;
-$column-divider-rule-width: 1px !default;
-$inverse-column-divider-rule-color: $inverse-global-border !default;
-$comment-header-margin-bottom: $global-margin !default;
-$comment-title-font-size: $global-medium-font-size !default;
-$comment-title-line-height: 1.4 !default;
-$comment-meta-font-size: $global-small-font-size !default;
-$comment-meta-line-height: 1.4 !default;
-$comment-meta-color: $global-muted-color !default;
-$comment-list-margin-top: $global-large-margin !default;
-$comment-list-padding-left: 30px !default;
-$comment-list-padding-left-m: 100px !default;
-$container-max-width: 1200px !default;
-$container-small-max-width: 900px !default;
-$container-large-max-width: 1600px !default;
-$container-padding-horizontal: 15px !default;
-$container-padding-horizontal-s: $global-gutter !default;
-$container-padding-horizontal-m: $global-medium-gutter !default;
-$countdown-item-line-height: 70px !default;
-$countdown-number-font-size: 2rem !default;
-$countdown-number-font-size-s: 4rem !default;
-$countdown-number-font-size-m: 6rem !default;
-$countdown-separator-font-size: 1rem !default;
-$countdown-separator-font-size-s: 2rem !default;
-$countdown-separator-font-size-m: 3rem !default;
-$description-list-term-color: $global-emphasis-color !default;
-$description-list-term-margin-top: $global-margin !default;
-$description-list-divider-term-margin-top: $global-margin !default;
-$description-list-divider-term-border-width: $global-border-width !default;
-$description-list-divider-term-border: $global-border !default;
-$divider-margin-vertical: $global-margin !default;
-$divider-icon-width: 50px !default;
-$divider-icon-height: 20px !default;
-$divider-icon-color: $global-border !default;
-$divider-icon-line-top: 50% !default;
-$divider-icon-line-width: 100% !default;
-$divider-icon-line-border-width: $global-border-width !default;
-$divider-icon-line-border: $global-border !default;
-$internal-divider-icon-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2220%22%20height%3D%2220%22%20viewBox%3D%220%200%2020%2020%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Ccircle%20fill%3D%22none%22%20stroke%3D%22#000%22%20stroke-width%3D%222%22%20cx%3D%2210%22%20cy%3D%2210%22%20r%3D%227%22%20%2F%3E%0A%3C%2Fsvg%3E%0A" !default;
-$divider-small-width: 100px !default;
-$divider-small-border-width: $global-border-width !default;
-$divider-small-border: $global-border !default;
-$inverse-divider-icon-color: $inverse-global-border !default;
-$inverse-divider-icon-line-border: $inverse-global-border !default;
-$inverse-divider-small-border: $inverse-global-border !default;
-$dotnav-margin-horizontal: 12px !default;
-$dotnav-margin-vertical: $dotnav-margin-horizontal !default;
-$dotnav-item-width: 10px !default;
-$dotnav-item-height: $dotnav-item-width !default;
-$dotnav-item-border-radius: 50% !default;
-$dotnav-item-background: transparent !default;
-$dotnav-item-hover-background: rgba($global-color, 0.6) !default;
-$dotnav-item-onclick-background: rgba($global-color, 0.2) !default;
-$dotnav-item-active-background: rgba($global-color, 0.6) !default;
-$inverse-dotnav-item-background: transparent !default;
-$inverse-dotnav-item-hover-background: rgba($inverse-global-color, 0.9) !default;
-$inverse-dotnav-item-onclick-background: rgba($inverse-global-color, 0.5) !default;
-$inverse-dotnav-item-active-background: rgba($inverse-global-color, 0.9) !default;
-$global-z-index: 1000 !default;
-$drop-z-index: $global-z-index + 20 !default;
-$drop-width: 300px !default;
-$drop-margin: $global-margin !default;
-$dropdown-z-index: $global-z-index + 20 !default;
-$dropdown-min-width: 200px !default;
-$dropdown-padding: 25px !default;
-$dropdown-background: $global-background !default;
-$dropdown-color: $global-color !default;
-$dropdown-margin: $global-small-margin !default;
-$dropdown-nav-item-color: $global-muted-color !default;
-$dropdown-nav-item-hover-color: $global-color !default;
-$dropdown-nav-header-color: $global-emphasis-color !default;
-$dropdown-nav-divider-border-width: $global-border-width !default;
-$dropdown-nav-divider-border: $global-border !default;
-$dropdown-nav-sublist-item-color: $global-muted-color !default;
-$dropdown-nav-sublist-item-hover-color: $global-color !default;
-$form-range-thumb-height: 15px !default;
-$form-range-thumb-border-radius: 500px !default;
-$form-range-thumb-background: $global-background !default;
-$form-range-track-height: 3px !default;
-$form-range-track-background: darken($global-muted-background, 5%) !default;
-$form-range-track-focus-background: darken($global-muted-background, 15%) !default;
-$form-height: $global-control-height !default;
-$form-border-width: $global-border-width !default;
-$form-line-height: $form-height - (2* $form-border-width) !default;
-$form-padding-horizontal: 10px !default;
-$form-padding-vertical: 4px !default;
-$form-background: $global-background !default;
-$form-color: $global-color !default;
-$form-focus-background: $global-background !default;
-$form-focus-color: $global-color !default;
-$form-disabled-background: $global-muted-background !default;
-$form-disabled-color: $global-muted-color !default;
-$form-placeholder-color: $global-muted-color !default;
-$form-small-height: $global-control-small-height !default;
-$form-small-padding-horizontal: 8px !default;
-$form-small-line-height: $form-small-height - (2* $form-border-width) !default;
-$form-small-font-size: $global-small-font-size !default;
-$form-large-height: $global-control-large-height !default;
-$form-large-padding-horizontal: 12px !default;
-$form-large-line-height: $form-large-height - (2* $form-border-width) !default;
-$form-large-font-size: $global-medium-font-size !default;
-$form-danger-color: $global-danger-background !default;
-$form-success-color: $global-success-background !default;
-$form-width-xsmall: 50px !default;
-$form-width-small: 130px !default;
-$form-width-medium: 200px !default;
-$form-width-large: 500px !default;
-$form-select-padding-right: 20px !default;
-$form-select-icon-color: $global-color !default;
-$form-select-disabled-icon-color: $global-muted-color !default;
-$form-radio-size: 16px !default;
-$form-radio-margin-top: -4px !default;
-$form-radio-background: transparent !default;
-$form-radio-checked-background: $global-primary-background !default;
-$form-radio-checked-icon-color: $global-inverse-color !default;
-$form-radio-checked-focus-background: darken($global-primary-background, 10%) !default;
-$form-radio-disabled-background: $global-muted-background !default;
-$form-radio-disabled-icon-color: $global-muted-color !default;
-$form-legend-font-size: $global-large-font-size !default;
-$form-legend-line-height: 1.4 !default;
-$form-stacked-margin-bottom: 5px !default;
-$form-horizontal-label-width: 200px !default;
-$form-horizontal-label-margin-top: 7px !default;
-$form-horizontal-controls-margin-left: 215px !default;
-$form-horizontal-controls-text-padding-top: 7px !default;
-$form-icon-width: $form-height !default;
-$form-icon-font-size: $global-font-size !default;
-$form-icon-color: $global-muted-color !default;
-$form-icon-hover-color: $global-color !default;
-$internal-form-select-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2224%22%20height%3D%2216%22%20viewBox%3D%220%200%2024%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22#000%22%20points%3D%2212%201%209%206%2015%206%22%20%2F%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22#000%22%20points%3D%2212%2013%209%208%2015%208%22%20%2F%3E%0A%3C%2Fsvg%3E%0A" !default;
-$internal-form-radio-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Ccircle%20fill%3D%22#000%22%20cx%3D%228%22%20cy%3D%228%22%20r%3D%222%22%20%2F%3E%0A%3C%2Fsvg%3E" !default;
-$internal-form-checkbox-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2214%22%20height%3D%2211%22%20viewBox%3D%220%200%2014%2011%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22#000%22%20points%3D%2212%201%205%207.5%202%205%201%205.5%205%2010%2013%201.5%22%20%2F%3E%0A%3C%2Fsvg%3E%0A" !default;
-$internal-form-checkbox-indeterminate-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Crect%20fill%3D%22#000%22%20x%3D%223%22%20y%3D%228%22%20width%3D%2210%22%20height%3D%221%22%20%2F%3E%0A%3C%2Fsvg%3E" !default;
-$inverse-global-muted-background: rgba($global-inverse-color, 0.1) !default;
-$inverse-form-background: $inverse-global-muted-background !default;
-$inverse-form-color: $inverse-global-color !default;
-$inverse-form-focus-background: $inverse-global-muted-background !default;
-$inverse-form-focus-color: $inverse-global-color !default;
-$inverse-form-placeholder-color: $inverse-global-muted-color !default;
-$inverse-form-select-icon-color: $inverse-global-color !default;
-$inverse-form-radio-background: darken($inverse-global-muted-background, 5%) !default;
-$inverse-form-radio-checked-background: $inverse-global-primary-background !default;
-$inverse-form-radio-checked-icon-color: $inverse-global-inverse-color !default;
-$inverse-form-radio-checked-focus-background: darken($inverse-global-primary-background, 10%) !default;
-$grid-gutter-horizontal: $global-gutter !default;
-$grid-gutter-vertical: $grid-gutter-horizontal !default;
-$grid-gutter-horizontal-l: $global-medium-gutter !default;
-$grid-gutter-vertical-l: $grid-gutter-horizontal-l !default;
-$grid-small-gutter-horizontal: $global-small-gutter !default;
-$grid-small-gutter-vertical: $grid-small-gutter-horizontal !default;
-$grid-medium-gutter-horizontal: $global-gutter !default;
-$grid-medium-gutter-vertical: $grid-medium-gutter-horizontal !default;
-$grid-large-gutter-horizontal: $global-medium-gutter !default;
-$grid-large-gutter-vertical: $grid-large-gutter-horizontal !default;
-$grid-large-gutter-horizontal-l: $global-large-gutter !default;
-$grid-large-gutter-vertical-l: $grid-large-gutter-horizontal-l !default;
-$grid-divider-border-width: $global-border-width !default;
-$grid-divider-border: $global-border !default;
-$inverse-grid-divider-border: $inverse-global-border !default;
-$heading-primary-font-size: $global-xxlarge-font-size !default;
-$heading-primary-line-height: 1.2 !default;
-$heading-primary-font-size-m: 3.75rem !default;
-$heading-primary-line-height-m: 1.1 !default;
-$heading-hero-font-size: 4rem !default;
-$heading-hero-line-height: 1.1 !default;
-$heading-hero-font-size-s: 6rem !default;
-$heading-hero-line-height-s: 1 !default;
-$heading-hero-font-size-m: 8rem !default;
-$heading-hero-line-height-m: 1 !default;
-$heading-divider-padding-bottom: 10px !default;
-$heading-divider-border-width: $global-border-width !default;
-$heading-divider-border: $global-border !default;
-$heading-bullet-top: unquote('calc(-0.1 * 1em)') !default;
-$heading-bullet-height: 0.9em !default;
-$heading-bullet-margin-right: 10px !default;
-$heading-bullet-border-width: 5px !default;
-$heading-bullet-border: $global-border !default;
-$heading-line-top: 50% !default;
-$heading-line-border-width: $global-border-width !default;
-$heading-line-height: $heading-line-border-width !default;
-$heading-line-width: 2000px !default;
-$heading-line-border: $global-border !default;
-$heading-line-margin-horizontal: 0.6em !default;
-$inverse-heading-divider-border: $inverse-global-border !default;
-$inverse-heading-bullet-border: $inverse-global-border !default;
-$inverse-heading-line-border: $inverse-global-border !default;
-$icon-image-size: 20px !default;
-$icon-link-color: $global-muted-color !default;
-$icon-link-hover-color: $global-color !default;
-$icon-link-active-color: darken($global-color, 5%) !default;
-$icon-button-size: 36px !default;
-$icon-button-border-radius: 500px !default;
-$icon-button-background: $global-muted-background !default;
-$icon-button-color: $global-muted-color !default;
-$icon-button-hover-background: darken($icon-button-background, 5%) !default;
-$icon-button-hover-color: $global-color !default;
-$icon-button-active-background: darken($icon-button-background, 10%) !default;
-$icon-button-active-color: $global-color !default;
-$inverse-icon-link-color: $inverse-global-muted-color !default;
-$inverse-icon-link-hover-color: $inverse-global-color !default;
-$inverse-icon-link-active-color: $inverse-global-color !default;
-$inverse-icon-button-background: $inverse-global-muted-background !default;
-$inverse-icon-button-color: $inverse-global-muted-color !default;
-$inverse-icon-button-hover-background: darken($inverse-icon-button-background, 5%) !default;
-$inverse-icon-button-hover-color: $inverse-global-color !default;
-$inverse-icon-button-active-background: darken($inverse-icon-button-background, 10%) !default;
-$inverse-icon-button-active-color: $inverse-global-color !default;
-$iconnav-margin-horizontal: $global-small-margin !default;
-$iconnav-margin-vertical: $iconnav-margin-horizontal !default;
-$iconnav-item-color: $global-muted-color !default;
-$iconnav-item-hover-color: $global-color !default;
-$iconnav-item-active-color: $global-color !default;
-$inverse-iconnav-item-color: $inverse-global-muted-color !default;
-$inverse-iconnav-item-hover-color: $inverse-global-color !default;
-$inverse-iconnav-item-active-color: $inverse-global-color !default;
-$inverse-global-color-mode: light !default;
-$label-padding-vertical: 0 !default;
-$label-padding-horizontal: $global-small-margin !default;
-$label-background: $global-primary-background !default;
-$label-line-height: $global-line-height !default;
-$label-font-size: $global-small-font-size !default;
-$label-color: $global-inverse-color !default;
-$label-success-background: $global-success-background !default;
-$label-success-color: $global-inverse-color !default;
-$label-warning-background: $global-warning-background !default;
-$label-warning-color: $global-inverse-color !default;
-$label-danger-background: $global-danger-background !default;
-$label-danger-color: $global-inverse-color !default;
-$inverse-label-background: $inverse-global-primary-background !default;
-$inverse-label-color: $inverse-global-inverse-color !default;
-$lightbox-z-index: $global-z-index + 10 !default;
-$lightbox-background: #000 !default;
-$lightbox-item-color: rgba(255,255,255,0.7) !default;
-$lightbox-toolbar-padding-vertical: 10px !default;
-$lightbox-toolbar-padding-horizontal: 10px !default;
-$lightbox-toolbar-background: rgba(0,0,0,0.3) !default;
-$lightbox-toolbar-color: rgba(255,255,255,0.7) !default;
-$lightbox-toolbar-icon-padding: 5px !default;
-$lightbox-toolbar-icon-color: rgba(255,255,255,0.7) !default;
-$lightbox-toolbar-icon-hover-color: #fff !default;
-$lightbox-button-size: 50px !default;
-$lightbox-button-background: $lightbox-toolbar-background !default;
-$lightbox-button-color: rgba(255,255,255,0.7) !default;
-$lightbox-button-hover-color: #fff !default;
-$link-muted-color: $global-muted-color !default;
-$link-muted-hover-color: $global-color !default;
-$link-text-hover-color: $global-muted-color !default;
-$link-heading-hover-color: $global-primary-background !default;
-$link-heading-hover-text-decoration: none !default;
-$inverse-link-muted-color: $inverse-global-muted-color !default;
-$inverse-link-muted-hover-color: $inverse-global-color !default;
-$inverse-link-text-hover-color: $inverse-global-muted-color !default;
-$inverse-link-heading-hover-color: $inverse-global-primary-background !default;
-$list-margin-top: $global-small-margin !default;
-$list-nested-padding-left: $global-gutter !default;
-$list-divider-margin-top: $global-small-margin !default;
-$list-divider-border-width: $global-border-width !default;
-$list-divider-border: $global-border !default;
-$list-striped-padding-vertical: $global-small-margin !default;
-$list-striped-padding-horizontal: $global-small-margin !default;
-$list-striped-background: $global-muted-background !default;
-$list-bullet-width: ($global-line-height * 1em) !default;
-$list-bullet-height: $list-bullet-width !default;
-$list-bullet-margin-right: $global-small-margin !default;
-$list-bullet-icon-color: $global-color !default;
-$list-large-margin-top: $global-margin !default;
-$list-large-divider-margin-top: $global-margin !default;
-$list-large-striped-padding-vertical: $global-margin !default;
-$list-large-striped-padding-horizontal: $global-small-margin !default;
-$internal-list-bullet-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%226%22%20height%3D%226%22%20viewBox%3D%220%200%206%206%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Ccircle%20fill%3D%22#000%22%20cx%3D%223%22%20cy%3D%223%22%20r%3D%223%22%20%2F%3E%0A%3C%2Fsvg%3E" !default;
-$inverse-list-divider-border: $inverse-global-border !default;
-$inverse-list-striped-background: $inverse-global-muted-background !default;
-$inverse-list-bullet-icon-color: $inverse-global-color !default;
-$margin-margin: $global-margin !default;
-$margin-small-margin: $global-small-margin !default;
-$margin-medium-margin: $global-medium-margin !default;
-$margin-large-margin: $global-medium-margin !default;
-$margin-large-margin-l: $global-large-margin !default;
-$margin-xlarge-margin: $global-large-margin !default;
-$global-xlarge-margin: 140px !default;
-$margin-xlarge-margin-l: $global-xlarge-margin !default;
-$marker-padding: 5px !default;
-$marker-background: $global-secondary-background !default;
-$marker-color: $global-inverse-color !default;
-$marker-hover-color: $global-inverse-color !default;
-$inverse-marker-background: $global-muted-background !default;
-$inverse-marker-color: $global-color !default;
-$inverse-marker-hover-color: $global-color !default;
-$modal-z-index: $global-z-index + 10 !default;
-$modal-background: rgba(0,0,0,0.6) !default;
-$modal-padding-horizontal: 15px !default;
-$modal-padding-horizontal-s: $global-gutter !default;
-$modal-padding-horizontal-m: $global-medium-gutter !default;
-$modal-padding-vertical: $modal-padding-horizontal !default;
-$modal-padding-vertical-s: 50px !default;
-$modal-dialog-width: 600px !default;
-$modal-dialog-background: $global-background !default;
-$modal-container-width: 1200px !default;
-$modal-body-padding-horizontal: $global-gutter !default;
-$modal-body-padding-vertical: $global-gutter !default;
-$modal-header-padding-horizontal: $global-gutter !default;
-$modal-header-padding-vertical: ($modal-header-padding-horizontal / 2) !default;
-$modal-header-background: $modal-dialog-background !default;
-$modal-footer-padding-horizontal: $global-gutter !default;
-$modal-footer-padding-vertical: ($modal-footer-padding-horizontal / 2) !default;
-$modal-footer-background: $modal-dialog-background !default;
-$modal-title-font-size: $global-xlarge-font-size !default;
-$modal-title-line-height: 1.3 !default;
-$modal-close-position: $global-small-margin !default;
-$modal-close-padding: 5px !default;
-$modal-close-outside-position: 0 !default;
-$modal-close-outside-translate: 100% !default;
-$modal-close-outside-color: lighten($global-inverse-color, 20%) !default;
-$modal-close-outside-hover-color: $global-inverse-color !default;
-$nav-item-padding-vertical: 5px !default;
-$nav-item-padding-horizontal: 0 !default;
-$nav-sublist-padding-vertical: 5px !default;
-$nav-sublist-padding-left: 15px !default;
-$nav-sublist-deeper-padding-left: 15px !default;
-$nav-sublist-item-padding-vertical: 2px !default;
-$nav-parent-icon-width: ($global-line-height * 1em) !default;
-$nav-parent-icon-height: $nav-parent-icon-width !default;
-$nav-parent-icon-color: $global-color !default;
-$nav-header-padding-vertical: $nav-item-padding-vertical !default;
-$nav-header-padding-horizontal: $nav-item-padding-horizontal !default;
-$nav-header-font-size: $global-small-font-size !default;
-$nav-header-text-transform: uppercase !default;
-$nav-header-margin-top: $global-margin !default;
-$nav-divider-margin-vertical: 5px !default;
-$nav-divider-margin-horizontal: 0 !default;
-$nav-default-item-color: $global-muted-color !default;
-$nav-default-item-hover-color: $global-color !default;
-$nav-default-item-active-color: $global-emphasis-color !default;
-$nav-default-header-color: $global-emphasis-color !default;
-$nav-default-divider-border-width: $global-border-width !default;
-$nav-default-divider-border: $global-border !default;
-$nav-default-sublist-item-color: $global-muted-color !default;
-$nav-default-sublist-item-hover-color: $global-color !default;
-$nav-primary-item-font-size: $global-large-font-size !default;
-$nav-primary-item-line-height: $global-line-height !default;
-$nav-primary-item-color: $global-muted-color !default;
-$nav-primary-item-hover-color: $global-color !default;
-$nav-primary-item-active-color: $global-emphasis-color !default;
-$nav-primary-header-color: $global-emphasis-color !default;
-$nav-primary-divider-border-width: $global-border-width !default;
-$nav-primary-divider-border: $global-border !default;
-$nav-primary-sublist-item-color: $global-muted-color !default;
-$nav-primary-sublist-item-hover-color: $global-color !default;
-$internal-nav-parent-close-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2214%22%20height%3D%2214%22%20viewBox%3D%220%200%2014%2014%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolyline%20fill%3D%22none%22%20stroke%3D%22#000%22%20stroke-width%3D%221.1%22%20points%3D%2210%201%204%207%2010%2013%22%20%2F%3E%0A%3C%2Fsvg%3E" !default;
-$internal-nav-parent-open-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2214%22%20height%3D%2214%22%20viewBox%3D%220%200%2014%2014%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolyline%20fill%3D%22none%22%20stroke%3D%22#000%22%20stroke-width%3D%221.1%22%20points%3D%221%204%207%2010%2013%204%22%20%2F%3E%0A%3C%2Fsvg%3E" !default;
-$inverse-nav-parent-icon-color: $inverse-global-color !default;
-$inverse-nav-default-item-color: $inverse-global-muted-color !default;
-$inverse-nav-default-item-hover-color: $inverse-global-color !default;
-$inverse-nav-default-item-active-color: $inverse-global-emphasis-color !default;
-$inverse-nav-default-header-color: $inverse-global-emphasis-color !default;
-$inverse-nav-default-divider-border: $inverse-global-border !default;
-$inverse-nav-default-sublist-item-color: $inverse-global-muted-color !default;
-$inverse-nav-default-sublist-item-hover-color: $inverse-global-color !default;
-$inverse-nav-primary-item-color: $inverse-global-muted-color !default;
-$inverse-nav-primary-item-hover-color: $inverse-global-color !default;
-$inverse-nav-primary-item-active-color: $inverse-global-emphasis-color !default;
-$inverse-nav-primary-header-color: $inverse-global-emphasis-color !default;
-$inverse-nav-primary-divider-border: $inverse-global-border !default;
-$inverse-nav-primary-sublist-item-color: $inverse-global-muted-color !default;
-$inverse-nav-primary-sublist-item-hover-color: $inverse-global-color !default;
-$navbar-background: $global-muted-background !default;
-$navbar-color-mode: none !default;
-$navbar-nav-item-height: 80px !default;
-$navbar-nav-item-padding-horizontal: 15px !default;
-$navbar-nav-item-color: $global-muted-color !default;
-$navbar-nav-item-font-size: $global-small-font-size !default;
-$navbar-nav-item-font-family: $global-font-family !default;
-$navbar-nav-item-hover-color: $global-color !default;
-$navbar-nav-item-onclick-color: $global-emphasis-color !default;
-$navbar-nav-item-active-color: $global-emphasis-color !default;
-$navbar-item-color: $global-color !default;
-$navbar-toggle-color: $global-muted-color !default;
-$navbar-toggle-hover-color: $global-color !default;
-$navbar-subtitle-font-size: $global-small-font-size !default;
-$navbar-dropdown-z-index: $global-z-index + 20 !default;
-$navbar-dropdown-width: 200px !default;
-$navbar-dropdown-margin: 15px !default;
-$navbar-dropdown-padding: 25px !default;
-$navbar-dropdown-background: $global-background !default;
-$navbar-dropdown-color: $global-color !default;
-$navbar-dropdown-grid-gutter-horizontal: ($navbar-dropdown-padding * 2) !default;
-$navbar-dropdown-grid-gutter-vertical: $navbar-dropdown-grid-gutter-horizontal !default;
-$navbar-dropdown-dropbar-margin-top: 0 !default;
-$navbar-dropdown-dropbar-margin-bottom: $navbar-dropdown-dropbar-margin-top !default;
-$navbar-dropdown-nav-item-color: $global-muted-color !default;
-$navbar-dropdown-nav-item-hover-color: $global-color !default;
-$navbar-dropdown-nav-item-active-color: $global-emphasis-color !default;
-$navbar-dropdown-nav-header-color: $global-emphasis-color !default;
-$navbar-dropdown-nav-divider-border-width: $global-border-width !default;
-$navbar-dropdown-nav-divider-border: $global-border !default;
-$navbar-dropdown-nav-sublist-item-color: $global-muted-color !default;
-$navbar-dropdown-nav-sublist-item-hover-color: $global-color !default;
-$navbar-dropbar-background: $navbar-dropdown-background !default;
-$navbar-dropbar-z-index: $global-z-index - 20 !default;
-$inverse-navbar-nav-item-color: $inverse-global-muted-color !default;
-$inverse-navbar-nav-item-hover-color: $inverse-global-color !default;
-$inverse-navbar-nav-item-onclick-color: $inverse-global-emphasis-color !default;
-$inverse-navbar-nav-item-active-color: $inverse-global-emphasis-color !default;
-$inverse-navbar-item-color: $inverse-global-color !default;
-$inverse-navbar-toggle-color: $inverse-global-muted-color !default;
-$inverse-navbar-toggle-hover-color: $inverse-global-color !default;
-$notification-position: 10px !default;
-$notification-z-index: $global-z-index + 40 !default;
-$notification-width: 350px !default;
-$notification-message-margin-bottom: 10px !default;
-$notification-message-padding: $global-small-gutter !default;
-$notification-message-background: $global-muted-background !default;
-$notification-message-color: $global-color !default;
-$notification-message-font-size: $global-medium-font-size !default;
-$notification-message-line-height: 1.4 !default;
-$notification-close-top: $notification-message-padding + 5px !default;
-$notification-close-right: $notification-message-padding !default;
-$notification-message-primary-color: $global-primary-background !default;
-$notification-message-success-color: $global-success-background !default;
-$notification-message-warning-color: $global-warning-background !default;
-$notification-message-danger-color: $global-danger-background !default;
-$offcanvas-z-index: $global-z-index !default;
-$offcanvas-bar-width: 270px !default;
-$offcanvas-bar-padding-vertical: $global-margin !default;
-$offcanvas-bar-padding-horizontal: $global-margin !default;
-$offcanvas-bar-background: $global-secondary-background !default;
-$offcanvas-bar-color-mode: light !default;
-$offcanvas-bar-width-m: 350px !default;
-$offcanvas-bar-padding-vertical-m: $global-medium-gutter !default;
-$offcanvas-bar-padding-horizontal-m: $global-medium-gutter !default;
-$offcanvas-close-position: 20px !default;
-$offcanvas-close-padding: 5px !default;
-$offcanvas-overlay-background: rgba(0,0,0,0.1) !default;
-$overlay-padding-horizontal: $global-gutter !default;
-$overlay-padding-vertical: $global-gutter !default;
-$overlay-default-background: rgba($global-background, 0.8) !default;
-$overlay-primary-background: rgba($global-secondary-background, 0.8) !default;
-$overlay-primary-color-mode: light !default;
-$padding-padding: $global-gutter !default;
-$padding-padding-l: $global-medium-gutter !default;
-$padding-small-padding: $global-small-gutter !default;
-$padding-large-padding: $global-gutter !default;
-$padding-large-padding-l: $global-large-gutter !default;
-$pagination-margin-horizontal: 20px !default;
-$pagination-item-color: $global-muted-color !default;
-$pagination-item-hover-color: $global-color !default;
-$pagination-item-hover-text-decoration: none !default;
-$pagination-item-active-color: $global-color !default;
-$pagination-item-disabled-color: $global-muted-color !default;
-$inverse-pagination-item-color: $inverse-global-muted-color !default;
-$inverse-pagination-item-hover-color: $inverse-global-color !default;
-$inverse-pagination-item-active-color: $inverse-global-color !default;
-$inverse-pagination-item-disabled-color: $inverse-global-muted-color !default;
-$placeholder-margin-vertical: $global-margin !default;
-$placeholder-padding-vertical: $global-gutter !default;
-$placeholder-padding-horizontal: $global-gutter !default;
-$placeholder-background: transparent !default;
-$position-small-margin: $global-small-gutter !default;
-$position-medium-margin: $global-gutter !default;
-$position-large-margin: $global-gutter !default;
-$position-large-margin-l: 50px !default;
-$progress-height: 15px !default;
-$progress-margin-vertical: $global-margin !default;
-$progress-background: $global-muted-background !default;
-$progress-bar-background: $global-primary-background !default;
-$search-color: $global-color !default;
-$search-placeholder-color: $global-muted-color !default;
-$search-icon-color: $global-muted-color !default;
-$search-default-width: 180px !default;
-$search-default-height: $global-control-height !default;
-$search-default-padding-horizontal: 6px !default;
-$search-default-background: transparent !default;
-$search-default-focus-background: $search-default-background !default;
-$search-default-icon-width: $global-control-height !default;
-$search-navbar-width: 400px !default;
-$search-navbar-height: 40px !default;
-$search-navbar-background: transparent !default;
-$search-navbar-font-size: $global-large-font-size !default;
-$search-navbar-icon-width: 40px !default;
-$search-large-width: 500px !default;
-$search-large-height: 80px !default;
-$search-large-background: transparent !default;
-$search-large-font-size: $global-xxlarge-font-size !default;
-$search-large-icon-width: 80px !default;
-$search-toggle-color: $global-muted-color !default;
-$search-toggle-hover-color: $global-color !default;
-$inverse-search-color: $inverse-global-color !default;
-$inverse-search-placeholder-color: $inverse-global-muted-color !default;
-$inverse-search-icon-color: $inverse-global-muted-color !default;
-$inverse-search-default-background: transparent !default;
-$inverse-search-default-focus-background: $inverse-search-default-background !default;
-$inverse-search-navbar-background: transparent !default;
-$inverse-search-large-background: transparent !default;
-$inverse-search-toggle-color: $inverse-global-muted-color !default;
-$inverse-search-toggle-hover-color: $inverse-global-color !default;
-$section-padding-vertical: $global-medium-margin !default;
-$section-padding-vertical-m: $global-large-margin !default;
-$section-xsmall-padding-vertical: $global-margin !default;
-$section-small-padding-vertical: $global-medium-margin !default;
-$section-large-padding-vertical: $global-large-margin !default;
-$section-large-padding-vertical-m: $global-xlarge-margin !default;
-$section-xlarge-padding-vertical: $global-xlarge-margin !default;
-$section-xlarge-padding-vertical-m: ($global-large-margin + $global-xlarge-margin) !default;
-$section-default-background: $global-background !default;
-$section-muted-background: $global-muted-background !default;
-$section-primary-background: $global-primary-background !default;
-$section-primary-color-mode: light !default;
-$section-secondary-background: $global-secondary-background !default;
-$section-secondary-color-mode: light !default;
-$slidenav-padding-vertical: 5px !default;
-$slidenav-padding-horizontal: 10px !default;
-$slidenav-color: rgba($global-color, 0.5) !default;
-$slidenav-hover-color: rgba($global-color, 0.9) !default;
-$slidenav-active-color: rgba($global-color, 0.5) !default;
-$slidenav-large-padding-vertical: 10px !default;
-$slidenav-large-padding-horizontal: $slidenav-large-padding-vertical !default;
-$inverse-slidenav-color: rgba($inverse-global-color, 0.7) !default;
-$inverse-slidenav-hover-color: rgba($inverse-global-color, 0.95) !default;
-$inverse-slidenav-active-color: rgba($inverse-global-color, 0.7) !default;
-$sortable-dragged-z-index: $global-z-index + 50 !default;
-$sortable-placeholder-opacity: 0 !default;
-$sortable-empty-height: 50px !default;
-$spinner-size: 30px !default;
-$spinner-stroke-width: 1 !default;
-$spinner-radius: floor(($spinner-size - $spinner-stroke-width) / 2) !default;
-$spinner-circumference: round(2 * 3.141 * $spinner-radius) !default;
-$spinner-duration: 1.4s !default;
-$sticky-z-index: $global-z-index - 20 !default;
-$sticky-animation-duration: 0.2s !default;
-$sticky-reverse-animation-duration: 0.2s !default;
-$subnav-margin-horizontal: 20px !default;
-$subnav-item-color: $global-muted-color !default;
-$subnav-item-hover-color: $global-color !default;
-$subnav-item-hover-text-decoration: none !default;
-$subnav-item-active-color: $global-emphasis-color !default;
-$subnav-divider-margin-horizontal: $subnav-margin-horizontal !default;
-$subnav-divider-border-height: 1.5em !default;
-$subnav-divider-border-width: $global-border-width !default;
-$subnav-divider-border: $global-border !default;
-$subnav-pill-item-padding-vertical: 5px !default;
-$subnav-pill-item-padding-horizontal: 10px !default;
-$subnav-pill-item-background: transparent !default;
-$subnav-pill-item-color: $subnav-item-color !default;
-$subnav-pill-item-hover-background: $global-muted-background !default;
-$subnav-pill-item-hover-color: $global-color !default;
-$subnav-pill-item-onclick-background: $subnav-pill-item-hover-background !default;
-$subnav-pill-item-onclick-color: $subnav-pill-item-hover-color !default;
-$subnav-pill-item-active-background: $global-primary-background !default;
-$subnav-pill-item-active-color: $global-inverse-color !default;
-$subnav-item-disabled-color: $global-muted-color !default;
-$inverse-subnav-item-color: $inverse-global-muted-color !default;
-$inverse-subnav-item-hover-color: $inverse-global-color !default;
-$inverse-subnav-item-active-color: $inverse-global-emphasis-color !default;
-$inverse-subnav-divider-border: $inverse-global-border !default;
-$inverse-subnav-pill-item-background: transparent !default;
-$inverse-subnav-pill-item-color: $inverse-global-muted-color !default;
-$inverse-subnav-pill-item-hover-background: $inverse-global-muted-background !default;
-$inverse-subnav-pill-item-hover-color: $inverse-global-color !default;
-$inverse-subnav-pill-item-onclick-background: $inverse-subnav-pill-item-hover-background !default;
-$inverse-subnav-pill-item-onclick-color: $inverse-subnav-pill-item-hover-color !default;
-$inverse-subnav-pill-item-active-background: $inverse-global-primary-background !default;
-$inverse-subnav-pill-item-active-color: $inverse-global-inverse-color !default;
-$inverse-subnav-item-disabled-color: $inverse-global-muted-color !default;
-$tab-margin-horizontal: 20px !default;
-$tab-item-padding-horizontal: 10px !default;
-$tab-item-padding-vertical: 5px !default;
-$tab-item-color: $global-muted-color !default;
-$tab-item-hover-color: $global-color !default;
-$tab-item-hover-text-decoration: none !default;
-$tab-item-active-color: $global-emphasis-color !default;
-$tab-item-disabled-color: $global-muted-color !default;
-$inverse-tab-item-color: $inverse-global-muted-color !default;
-$inverse-tab-item-hover-color: $inverse-global-color !default;
-$inverse-tab-item-active-color: $inverse-global-emphasis-color !default;
-$inverse-tab-item-disabled-color: $inverse-global-muted-color !default;
-$table-margin-vertical: $global-margin !default;
-$table-cell-padding-vertical: 16px !default;
-$table-cell-padding-horizontal: 12px !default;
-$table-header-cell-font-size: $global-small-font-size !default;
-$table-header-cell-font-weight: normal !default;
-$table-header-cell-color: $global-muted-color !default;
-$table-footer-font-size: $global-small-font-size !default;
-$table-caption-font-size: $global-small-font-size !default;
-$table-caption-color: $global-muted-color !default;
-$table-row-active-background: #ffd !default;
-$table-divider-border-width: $global-border-width !default;
-$table-divider-border: $global-border !default;
-$table-striped-row-background: $global-muted-background !default;
-$table-hover-row-background: $table-row-active-background !default;
-$table-small-cell-padding-vertical: 10px !default;
-$table-small-cell-padding-horizontal: 12px !default;
-$table-large-cell-padding-vertical: 22px !default;
-$table-large-cell-padding-horizontal: 12px !default;
-$table-expand-min-width: 150px !default;
-$inverse-table-header-cell-color: $inverse-global-color !default;
-$inverse-table-caption-color: $inverse-global-muted-color !default;
-$inverse-table-row-active-background: fade-out($inverse-global-muted-background, 0.02) !default;
-$inverse-table-divider-border: $inverse-global-border !default;
-$inverse-table-striped-row-background: $inverse-global-muted-background !default;
-$inverse-table-hover-row-background: $inverse-table-row-active-background !default;
-$text-lead-font-size: $global-large-font-size !default;
-$text-lead-line-height: 1.5 !default;
-$text-lead-color: $global-emphasis-color !default;
-$text-meta-font-size: $global-small-font-size !default;
-$text-meta-line-height: 1.4 !default;
-$text-meta-color: $global-muted-color !default;
-$text-small-font-size: $global-small-font-size !default;
-$text-small-line-height: 1.5 !default;
-$text-large-font-size: $global-large-font-size !default;
-$text-large-line-height: 1.5 !default;
-$text-bold-font-weight: bolder !default;
-$text-muted-color: $global-muted-color !default;
-$text-primary-color: $global-primary-background !default;
-$text-success-color: $global-success-background !default;
-$text-warning-color: $global-warning-background !default;
-$text-danger-color: $global-danger-background !default;
-$text-background-color: $global-primary-background !default;
-$inverse-text-lead-color: $inverse-global-color !default;
-$inverse-text-meta-color: $inverse-global-muted-color !default;
-$inverse-text-muted-color: $inverse-global-muted-color !default;
-$inverse-text-primary-color: $inverse-global-color !default;
-$thumbnav-margin-horizontal: 15px !default;
-$thumbnav-margin-vertical: $thumbnav-margin-horizontal !default;
-$tile-padding-horizontal: 15px !default;
-$tile-padding-horizontal-s: $global-gutter !default;
-$tile-padding-horizontal-m: $global-medium-gutter !default;
-$tile-padding-vertical: $global-medium-margin !default;
-$tile-padding-vertical-m: $global-large-margin !default;
-$tile-xsmall-padding-vertical: $global-margin !default;
-$tile-small-padding-vertical: $global-medium-margin !default;
-$tile-large-padding-vertical: $global-large-margin !default;
-$tile-large-padding-vertical-m: $global-xlarge-margin !default;
-$tile-xlarge-padding-vertical: $global-xlarge-margin !default;
-$tile-xlarge-padding-vertical-m: ($global-large-margin + $global-xlarge-margin) !default;
-$tile-default-background: $global-background !default;
-$tile-muted-background: $global-muted-background !default;
-$tile-primary-background: $global-primary-background !default;
-$tile-primary-color-mode: light !default;
-$tile-secondary-background: $global-secondary-background !default;
-$tile-secondary-color-mode: light !default;
-$tooltip-z-index: $global-z-index + 30 !default;
-$tooltip-max-width: 200px !default;
-$tooltip-padding-vertical: 3px !default;
-$tooltip-padding-horizontal: 6px !default;
-$tooltip-background: #666 !default;
-$tooltip-border-radius: 2px !default;
-$tooltip-color: $global-inverse-color !default;
-$tooltip-font-size: 12px !default;
-$tooltip-margin: 10px !default;
-$totop-padding: 5px !default;
-$totop-color: $global-muted-color !default;
-$totop-hover-color: $global-color !default;
-$totop-active-color: $global-emphasis-color !default;
-$inverse-totop-color: $inverse-global-muted-color !default;
-$inverse-totop-hover-color: $inverse-global-color !default;
-$inverse-totop-active-color: $inverse-global-emphasis-color !default;
-$transition-duration: 0.3s !default;
-$transition-scale: 1.1 !default;
-$transition-slide-small-translate: 10px !default;
-$transition-slide-medium-translate: 50px !default;
-$transition-slow-duration: 0.7s !default;
-$panel-scrollable-height: 170px !default;
-$panel-scrollable-padding: 10px !default;
-$panel-scrollable-border-width: $global-border-width !default;
-$panel-scrollable-border: $global-border !default;
-$height-small-height: 150px !default;
-$height-medium-height: 300px !default;
-$height-large-height: 450px !default;
-$border-rounded-border-radius: 5px !default;
-$box-shadow-duration: 0.1s !default;
-$box-shadow-bottom-height: 30px !default;
-$box-shadow-bottom-border-radius: 100% !default;
-$box-shadow-bottom-background: #444 !default;
-$box-shadow-bottom-blur: 20px !default;
-$dropcap-margin-right: 10px !default;
-$dropcap-font-size: (($global-line-height * 3) * 1em) !default;
-$leader-fill-content: '.' !default;
-$leader-fill-margin-left: $global-small-gutter !default;
-$logo-font-size: $global-large-font-size !default;
-$logo-font-family: $global-font-family !default;
-$logo-color: $global-color !default;
-$logo-hover-color: $global-color !default;
-$dragover-box-shadow: 0 0 20px rgba(100,100,100,0.3) !default;
-$inverse-logo-color: $inverse-global-color !default;
-$inverse-logo-hover-color: $inverse-global-color !default;
-$breakpoint-small: 640px !default;
-$breakpoint-medium: 960px !default;
-$breakpoint-large: 1200px !default;
-$breakpoint-xlarge: 1600px !default;
-$breakpoint-xsmall-max: ($breakpoint-small - 1) !default;
-$breakpoint-small-max: ($breakpoint-medium - 1) !default;
-$breakpoint-medium-max: ($breakpoint-large - 1) !default;
-$breakpoint-large-max: ($breakpoint-xlarge - 1) !default;
-$global-small-box-shadow: 0 2px 8px rgba(0,0,0,0.08) !default;
-$global-medium-box-shadow: 0 5px 15px rgba(0,0,0,0.08) !default;
-$global-large-box-shadow: 0 14px 25px rgba(0,0,0,0.16) !default;
-$global-xlarge-box-shadow: 0 28px 50px rgba(0,0,0,0.16) !default;
-$width-small-width: 150px !default;
-$width-medium-width: 300px !default;
-$width-large-width: 450px !default;
-$width-xlarge-width: 600px !default;
-$width-xxlarge-width: 750px !default;
-$accordion-icon-color: $global-color !default;
-$internal-accordion-open-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2213%22%20height%3D%2213%22%20viewBox%3D%220%200%2013%2013%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Crect%20fill%3D%22#000%22%20width%3D%2213%22%20height%3D%221%22%20x%3D%220%22%20y%3D%226%22%20%2F%3E%0A%3C%2Fsvg%3E" !default;
-$internal-accordion-close-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2213%22%20height%3D%2213%22%20viewBox%3D%220%200%2013%2013%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Crect%20fill%3D%22#000%22%20width%3D%2213%22%20height%3D%221%22%20x%3D%220%22%20y%3D%226%22%20%2F%3E%0A%20%20%20%20%3Crect%20fill%3D%22#000%22%20width%3D%221%22%20height%3D%2213%22%20x%3D%226%22%20y%3D%220%22%20%2F%3E%0A%3C%2Fsvg%3E" !default;
-$alert-close-opacity: 0.4 !default;
-$alert-close-hover-opacity: 0.8 !default;
-$article-meta-link-color: $article-meta-color !default;
-$article-meta-link-hover-color: $global-color !default;
-$base-code-padding-horizontal: 6px !default;
-$base-code-padding-vertical: 2px !default;
-$base-code-background: $global-muted-background !default;
-$base-blockquote-color: $global-emphasis-color !default;
-$base-blockquote-footer-color: $global-color !default;
-$base-pre-padding: 10px !default;
-$base-pre-background: $global-background !default;
-$base-pre-border-width: $global-border-width !default;
-$base-pre-border: $global-border !default;
-$base-pre-border-radius: 3px !default;
-$inverse-base-blockquote-color: $inverse-global-emphasis-color !default;
-$inverse-base-blockquote-footer-color: $inverse-global-color !default;
-$button-text-transform: uppercase !default;
-$button-default-border: $global-border !default;
-$button-default-hover-border: darken($global-border, 20%) !default;
-$button-default-active-border: darken($global-border, 30%) !default;
-$button-disabled-border: $global-border !default;
-$button-text-border-width: $global-border-width !default;
-$button-text-border: $button-text-hover-color !default;
-$card-hover-box-shadow: $global-large-box-shadow !default;
-$card-default-box-shadow: $global-medium-box-shadow !default;
-$card-default-hover-box-shadow: $global-large-box-shadow !default;
-$card-default-header-border-width: $global-border-width !default;
-$card-default-header-border: $global-border !default;
-$card-default-footer-border-width: $global-border-width !default;
-$card-default-footer-border: $global-border !default;
-$card-primary-box-shadow: $global-medium-box-shadow !default;
-$card-primary-hover-box-shadow: $global-large-box-shadow !default;
-$card-secondary-box-shadow: $global-medium-box-shadow !default;
-$card-secondary-hover-box-shadow: $global-large-box-shadow !default;
-$comment-primary-padding: $global-gutter !default;
-$comment-primary-background: $global-muted-background !default;
-$description-list-term-font-size: $global-small-font-size !default;
-$description-list-term-font-weight: normal !default;
-$description-list-term-text-transform: uppercase !default;
-$dotnav-item-border-width: 1px !default;
-$dotnav-item-border: rgba($global-color, 0.4) !default;
-$dotnav-item-hover-border: transparent !default;
-$dotnav-item-onclick-border: transparent !default;
-$dotnav-item-active-border: transparent !default;
-$dropdown-nav-font-size: $global-small-font-size !default;
-$dropdown-box-shadow: 0 5px 12px rgba(0,0,0,0.15) !default;
-$form-range-thumb-border-width: $global-border-width !default;
-$form-range-thumb-border: darken($global-border, 10%) !default;
-$form-range-track-border-radius: 500px !default;
-$form-border: $global-border !default;
-$form-focus-border: $global-primary-background !default;
-$form-disabled-border: $global-border !default;
-$form-danger-border: $global-danger-background !default;
-$form-success-border: $global-success-background !default;
-$form-blank-focus-border: $global-border !default;
-$form-blank-focus-border-style: dashed !default;
-$form-radio-border-width: $global-border-width !default;
-$form-radio-border: darken($global-border, 10%) !default;
-$form-radio-focus-border: $global-primary-background !default;
-$form-radio-checked-border: transparent !default;
-$form-radio-disabled-border: $global-border !default;
-$form-label-color: $global-emphasis-color !default;
-$form-label-font-size: $global-small-font-size !default;
-$inverse-form-label-color: $inverse-global-emphasis-color !default;
-$label-border-radius: 2px !default;
-$label-text-transform: uppercase !default;
-$list-striped-border-width: $global-border-width !default;
-$list-striped-border: $global-border !default;
-$modal-header-border-width: $global-border-width !default;
-$modal-header-border: $global-border !default;
-$modal-footer-border-width: $global-border-width !default;
-$modal-footer-border: $global-border !default;
-$modal-close-full-padding: $global-margin !default;
-$modal-close-full-background: $modal-dialog-background !default;
-$nav-default-font-size: $global-small-font-size !default;
-$navbar-nav-item-text-transform: uppercase !default;
-$navbar-dropdown-nav-font-size: $global-small-font-size !default;
-$navbar-dropdown-box-shadow: 0 5px 12px rgba(0,0,0,0.15) !default;
-$navbar-dropbar-box-shadow: 0 5px 7px rgba(0, 0, 0, 0.05) !default;
-$navbar-dropdown-grid-divider-border-width: $global-border-width !default;
-$navbar-dropdown-grid-divider-border: $navbar-dropdown-nav-divider-border !default;
-$placeholder-border-width: $global-border-width !default;
-$placeholder-border: $global-border !default;
-$progress-border-radius: 500px !default;
-$search-default-border-width: $global-border-width !default;
-$search-default-border: $global-border !default;
-$subnav-item-font-size: $global-small-font-size !default;
-$subnav-item-text-transform: uppercase !default;
-$tab-border-width: $global-border-width !default;
-$tab-border: $global-border !default;
-$tab-item-border-width: $global-border-width !default;
-$tab-item-font-size: $global-small-font-size !default;
-$tab-item-text-transform: uppercase !default;
-$tab-item-active-border: $global-primary-background !default;
-$inverse-tab-border: $inverse-global-border !default;
-$table-striped-border-width: $global-border-width !default;
-$table-striped-border: $global-border !default;
-$text-meta-link-color: $text-meta-color !default;
-$text-meta-link-hover-color: $global-color !default;
-$thumbnav-item-background: rgba($global-background, 0.4) !default;
-$thumbnav-item-hover-background: transparent !default;
-$thumbnav-item-active-background: transparent !default;
\ No newline at end of file
diff --git a/_sass/uikit/variables.scss b/_sass/uikit/variables.scss
deleted file mode 100644
index 90b5afbb8a..0000000000
--- a/_sass/uikit/variables.scss
+++ /dev/null
@@ -1,986 +0,0 @@
-$global-margin: 20px !default;
-$accordion-item-margin-top: $global-margin !default;
-$global-medium-font-size: 1.25rem !default;
-$accordion-title-font-size: $global-medium-font-size !default;
-$accordion-title-line-height: 1.4 !default;
-$global-emphasis-color: #333 !default;
-$accordion-title-color: $global-emphasis-color !default;
-$global-color: #666 !default;
-$accordion-title-hover-color: $global-color !default;
-$accordion-content-margin-top: $global-margin !default;
-$global-inverse-color: #fff !default;
-$inverse-global-emphasis-color: $global-inverse-color !default;
-$inverse-accordion-title-color: $inverse-global-emphasis-color !default;
-$inverse-global-inverse-color: $global-color !default;
-$inverse-accordion-title-hover-color: $inverse-global-inverse-color !default;
-$global-gutter: 30px !default;
-$align-margin-horizontal: $global-gutter !default;
-$align-margin-vertical: $global-gutter !default;
-$global-medium-gutter: 40px !default;
-$align-margin-horizontal-l: $global-medium-gutter !default;
-$alert-margin-vertical: $global-margin !default;
-$global-small-gutter: 15px !default;
-$alert-padding: $global-small-gutter !default;
-$alert-padding-right: $alert-padding + 14px !default;
-$global-muted-background: #f8f8f8 !default;
-$alert-background: $global-muted-background !default;
-$alert-color: $global-color !default;
-$alert-close-top: $alert-padding + 5px !default;
-$alert-close-right: $alert-padding !default;
-$global-primary-background: #1e87f0 !default;
-$alert-primary-background: lighten(mix(white, $global-primary-background, 40%), 20%) !default;
-$alert-primary-color: $global-primary-background !default;
-$global-success-background: #32d296 !default;
-$alert-success-background: lighten(mix(white, $global-success-background, 40%), 25%) !default;
-$alert-success-color: $global-success-background !default;
-$global-warning-background: #faa05a !default;
-$alert-warning-background: lighten(mix(white, $global-warning-background, 45%), 15%) !default;
-$alert-warning-color: $global-warning-background !default;
-$global-danger-background: #f0506e !default;
-$alert-danger-background: lighten(mix(white, $global-danger-background, 40%), 20%) !default;
-$alert-danger-color: $global-danger-background !default;
-$global-large-margin: 70px !default;
-$article-margin-top: $global-large-margin !default;
-$global-xxlarge-font-size: 2.625rem !default;
-$article-title-font-size: $global-xxlarge-font-size !default;
-$article-title-line-height: 1.2 !default;
-$global-small-font-size: 0.875rem !default;
-$article-meta-font-size: $global-small-font-size !default;
-$article-meta-line-height: 1.4 !default;
-$global-muted-color: #999 !default;
-$article-meta-color: $global-muted-color !default;
-$inverse-global-muted-color: rgba($global-inverse-color, 0.5) !default;
-$inverse-article-meta-color: $inverse-global-muted-color !default;
-$animation-duration: 0.5s !default;
-$animation-fade-duration: 0.8s !default;
-$animation-kenburns-duration: 15s !default;
-$animation-fast-duration: 0.1s !default;
-$animation-slide-small-translate: 10px !default;
-$animation-slide-medium-translate: 50px !default;
-$global-background: #fff !default;
-$background-default-background: $global-background !default;
-$background-muted-background: $global-muted-background !default;
-$background-primary-background: $global-primary-background !default;
-$global-secondary-background: #222 !default;
-$background-secondary-background: $global-secondary-background !default;
-$badge-size: 22px !default;
-$badge-padding-vertical: 0 !default;
-$badge-padding-horizontal: 5px !default;
-$badge-border-radius: 500px !default;
-$badge-background: $global-primary-background !default;
-$badge-color: $global-inverse-color !default;
-$badge-font-size: $global-small-font-size !default;
-$badge-hover-color: $global-inverse-color !default;
-$inverse-global-primary-background: $global-inverse-color !default;
-$inverse-badge-background: $inverse-global-primary-background !default;
-$inverse-badge-color: $inverse-global-inverse-color !default;
-$inverse-badge-hover-color: $inverse-global-inverse-color !default;
-$base-body-background: $global-background !default;
-$global-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif !default;
-$base-body-font-family: $global-font-family !default;
-$base-body-font-weight: normal !default;
-$global-font-size: 16px !default;
-$base-body-font-size: $global-font-size !default;
-$global-line-height: 1.5 !default;
-$base-body-line-height: $global-line-height !default;
-$base-body-color: $global-color !default;
-$global-link-color: #1e87f0 !default;
-$base-link-color: $global-link-color !default;
-$base-link-text-decoration: none !default;
-$global-link-hover-color: #0f6ecd !default;
-$base-link-hover-color: $global-link-hover-color !default;
-$base-link-hover-text-decoration: underline !default;
-$base-strong-font-weight: bolder !default;
-$base-code-font-size: $global-small-font-size !default;
-$base-code-font-family: Consolas, monaco, monospace !default;
-$base-code-color: $global-danger-background !default;
-$base-em-color: $global-danger-background !default;
-$base-ins-background: #ffd !default;
-$base-ins-color: $global-color !default;
-$base-mark-background: #ffd !default;
-$base-mark-color: $global-color !default;
-$base-quote-font-style: italic !default;
-$base-small-font-size: 80% !default;
-$base-margin-vertical: $global-margin !default;
-$base-heading-font-family: $global-font-family !default;
-$base-heading-font-weight: normal !default;
-$base-heading-color: $global-emphasis-color !default;
-$base-heading-text-transform: none !default;
-$global-medium-margin: 40px !default;
-$base-heading-margin-top: $global-medium-margin !default;
-$base-h1-font-size: $global-xxlarge-font-size !default;
-$base-h1-line-height: 1.2 !default;
-$global-xlarge-font-size: 2rem !default;
-$base-h2-font-size: $global-xlarge-font-size !default;
-$base-h2-line-height: 1.3 !default;
-$global-large-font-size: 1.5rem !default;
-$base-h3-font-size: $global-large-font-size !default;
-$base-h3-line-height: 1.4 !default;
-$base-h4-font-size: $global-medium-font-size !default;
-$base-h4-line-height: 1.4 !default;
-$base-h5-font-size: $global-font-size !default;
-$base-h5-line-height: 1.4 !default;
-$base-h6-font-size: $global-small-font-size !default;
-$base-h6-line-height: 1.4 !default;
-$base-list-padding-left: 30px !default;
-$base-hr-margin-vertical: $global-margin !default;
-$global-border-width: 1px !default;
-$base-hr-border-width: $global-border-width !default;
-$global-border: #e5e5e5 !default;
-$base-hr-border: $global-border !default;
-$base-blockquote-font-size: $global-medium-font-size !default;
-$base-blockquote-line-height: 1.5 !default;
-$base-blockquote-font-style: italic !default;
-$base-blockquote-margin-vertical: $global-margin !default;
-$global-small-margin: 10px !default;
-$base-blockquote-footer-margin-top: $global-small-margin !default;
-$base-blockquote-footer-font-size: $global-small-font-size !default;
-$base-blockquote-footer-line-height: 1.5 !default;
-$base-pre-font-size: $global-small-font-size !default;
-$base-pre-line-height: 1.5 !default;
-$base-pre-font-family: $base-code-font-family !default;
-$base-pre-color: $global-color !default;
-$base-selection-background: #39f !default;
-$base-selection-color: $global-inverse-color !default;
-$inverse-global-color: rgba($global-inverse-color, 0.7) !default;
-$inverse-base-color: $inverse-global-color !default;
-$inverse-base-link-color: $inverse-global-emphasis-color !default;
-$inverse-base-link-hover-color: $inverse-global-emphasis-color !default;
-$inverse-base-code-color: $inverse-global-color !default;
-$inverse-base-em-color: $inverse-global-emphasis-color !default;
-$inverse-base-heading-color: $inverse-global-emphasis-color !default;
-$inverse-global-border: rgba($global-inverse-color, 0.2) !default;
-$inverse-base-hr-border: $inverse-global-border !default;
-$breadcrumb-item-font-size: $global-small-font-size !default;
-$breadcrumb-item-color: $global-muted-color !default;
-$breadcrumb-item-hover-color: $global-color !default;
-$breadcrumb-item-hover-text-decoration: none !default;
-$breadcrumb-item-active-color: $global-color !default;
-$breadcrumb-divider: "/" !default;
-$breadcrumb-divider-margin-horizontal: 20px !default;
-$breadcrumb-divider-color: $global-muted-color !default;
-$inverse-breadcrumb-item-color: $inverse-global-muted-color !default;
-$inverse-breadcrumb-item-hover-color: $inverse-global-color !default;
-$inverse-breadcrumb-item-active-color: $inverse-global-color !default;
-$inverse-breadcrumb-divider-color: $inverse-global-muted-color !default;
-$global-control-height: 40px !default;
-$button-line-height: $global-control-height !default;
-$global-control-small-height: 30px !default;
-$button-small-line-height: $global-control-small-height !default;
-$global-control-large-height: 55px !default;
-$button-large-line-height: $global-control-large-height !default;
-$button-font-size: $global-font-size !default;
-$button-small-font-size: $global-small-font-size !default;
-$button-large-font-size: $global-medium-font-size !default;
-$button-padding-horizontal: $global-gutter !default;
-$button-small-padding-horizontal: $global-small-gutter !default;
-$button-large-padding-horizontal: $global-medium-gutter !default;
-$button-default-background: $global-muted-background !default;
-$button-default-color: $global-emphasis-color !default;
-$button-default-hover-background: darken($button-default-background, 5%) !default;
-$button-default-hover-color: $global-emphasis-color !default;
-$button-default-active-background: darken($button-default-background, 10%) !default;
-$button-default-active-color: $global-emphasis-color !default;
-$button-primary-background: $global-primary-background !default;
-$button-primary-color: $global-inverse-color !default;
-$button-primary-hover-background: darken($button-primary-background, 5%) !default;
-$button-primary-hover-color: $global-inverse-color !default;
-$button-primary-active-background: darken($button-primary-background, 10%) !default;
-$button-primary-active-color: $global-inverse-color !default;
-$button-secondary-background: $global-secondary-background !default;
-$button-secondary-color: $global-inverse-color !default;
-$button-secondary-hover-background: darken($button-secondary-background, 5%) !default;
-$button-secondary-hover-color: $global-inverse-color !default;
-$button-secondary-active-background: darken($button-secondary-background, 10%) !default;
-$button-secondary-active-color: $global-inverse-color !default;
-$button-danger-background: $global-danger-background !default;
-$button-danger-color: $global-inverse-color !default;
-$button-danger-hover-background: darken($button-danger-background, 5%) !default;
-$button-danger-hover-color: $global-inverse-color !default;
-$button-danger-active-background: darken($button-danger-background, 10%) !default;
-$button-danger-active-color: $global-inverse-color !default;
-$button-disabled-background: $global-muted-background !default;
-$button-disabled-color: $global-muted-color !default;
-$button-text-line-height: $global-line-height !default;
-$button-text-color: $global-muted-color !default;
-$button-text-hover-color: $global-color !default;
-$button-text-disabled-color: $global-muted-color !default;
-$button-link-line-height: $global-line-height !default;
-$button-link-color: $global-link-color !default;
-$button-link-hover-color: $global-link-hover-color !default;
-$button-link-hover-text-decoration: underline !default;
-$button-link-disabled-color: $global-muted-color !default;
-$inverse-button-default-background: $inverse-global-primary-background !default;
-$inverse-button-default-color: $inverse-global-inverse-color !default;
-$inverse-button-default-hover-background: darken($inverse-button-default-background, 5%) !default;
-$inverse-button-default-hover-color: $inverse-global-inverse-color !default;
-$inverse-button-default-active-background: darken($inverse-button-default-background, 10%) !default;
-$inverse-button-default-active-color: $inverse-global-inverse-color !default;
-$inverse-button-primary-background: $inverse-global-primary-background !default;
-$inverse-button-primary-color: $inverse-global-inverse-color !default;
-$inverse-button-primary-hover-background: darken($inverse-button-primary-background, 5%) !default;
-$inverse-button-primary-hover-color: $inverse-global-inverse-color !default;
-$inverse-button-primary-active-background: darken($inverse-button-primary-background, 10%) !default;
-$inverse-button-primary-active-color: $inverse-global-inverse-color !default;
-$inverse-button-secondary-background: $inverse-global-primary-background !default;
-$inverse-button-secondary-color: $inverse-global-inverse-color !default;
-$inverse-button-secondary-hover-background: darken($inverse-button-secondary-background, 5%) !default;
-$inverse-button-secondary-hover-color: $inverse-global-inverse-color !default;
-$inverse-button-secondary-active-background: darken($inverse-button-secondary-background, 10%) !default;
-$inverse-button-secondary-active-color: $inverse-global-inverse-color !default;
-$inverse-button-text-color: $inverse-global-muted-color !default;
-$inverse-button-text-hover-color: $inverse-global-color !default;
-$inverse-button-text-disabled-color: $inverse-global-muted-color !default;
-$inverse-button-link-color: $inverse-global-muted-color !default;
-$inverse-button-link-hover-color: $inverse-global-color !default;
-$card-body-padding-horizontal: $global-gutter !default;
-$card-body-padding-vertical: $global-gutter !default;
-$card-body-padding-horizontal-l: $global-medium-gutter !default;
-$card-body-padding-vertical-l: $global-medium-gutter !default;
-$card-header-padding-horizontal: $global-gutter !default;
-$card-header-padding-vertical: round($global-gutter / 2) !default;
-$card-header-padding-horizontal-l: $global-medium-gutter !default;
-$card-header-padding-vertical-l: round($global-medium-gutter / 2) !default;
-$card-footer-padding-horizontal: $global-gutter !default;
-$card-footer-padding-vertical: ($global-gutter / 2) !default;
-$card-footer-padding-horizontal-l: $global-medium-gutter !default;
-$card-footer-padding-vertical-l: round($global-medium-gutter / 2) !default;
-$card-title-font-size: $global-large-font-size !default;
-$card-title-line-height: 1.4 !default;
-$card-badge-top: $global-gutter !default;
-$card-badge-right: $card-badge-top !default;
-$card-hover-background: $global-muted-background !default;
-$card-default-background: $global-muted-background !default;
-$card-default-color: $global-color !default;
-$card-default-title-color: $global-emphasis-color !default;
-$card-default-hover-background: darken($card-default-background, 5%) !default;
-$card-primary-background: $global-primary-background !default;
-$card-primary-color: $global-inverse-color !default;
-$card-primary-title-color: $card-primary-color !default;
-$card-primary-hover-background: darken($card-primary-background, 5%) !default;
-$card-primary-color-mode: light !default;
-$card-secondary-background: $global-secondary-background !default;
-$card-secondary-color: $global-inverse-color !default;
-$card-secondary-title-color: $card-secondary-color !default;
-$card-secondary-hover-background: darken($card-secondary-background, 5%) !default;
-$card-secondary-color-mode: light !default;
-$card-small-body-padding-horizontal: $global-margin !default;
-$card-small-body-padding-vertical: $global-margin !default;
-$card-small-header-padding-horizontal: $global-margin !default;
-$card-small-header-padding-vertical: round($global-margin / 1.5) !default;
-$card-small-footer-padding-horizontal: $global-margin !default;
-$card-small-footer-padding-vertical: round($global-margin / 1.5) !default;
-$global-large-gutter: 70px !default;
-$card-large-body-padding-horizontal-l: $global-large-gutter !default;
-$card-large-body-padding-vertical-l: $global-large-gutter !default;
-$card-large-header-padding-horizontal-l: $global-large-gutter !default;
-$card-large-header-padding-vertical-l: round($global-large-gutter / 2) !default;
-$card-large-footer-padding-horizontal-l: $global-large-gutter !default;
-$card-large-footer-padding-vertical-l: round($global-large-gutter / 2) !default;
-$close-color: $global-muted-color !default;
-$close-hover-color: $global-color !default;
-$inverse-close-color: $inverse-global-muted-color !default;
-$inverse-close-hover-color: $inverse-global-color !default;
-$column-gutter: $global-gutter !default;
-$column-gutter-l: $global-medium-gutter !default;
-$column-divider-rule-color: $global-border !default;
-$column-divider-rule-width: 1px !default;
-$inverse-column-divider-rule-color: $inverse-global-border !default;
-$comment-header-margin-bottom: $global-margin !default;
-$comment-title-font-size: $global-medium-font-size !default;
-$comment-title-line-height: 1.4 !default;
-$comment-meta-font-size: $global-small-font-size !default;
-$comment-meta-line-height: 1.4 !default;
-$comment-meta-color: $global-muted-color !default;
-$comment-list-margin-top: $global-large-margin !default;
-$comment-list-padding-left: 30px !default;
-$comment-list-padding-left-m: 100px !default;
-$container-max-width: 1200px !default;
-$container-small-max-width: 900px !default;
-$container-large-max-width: 1600px !default;
-$container-padding-horizontal: 15px !default;
-$container-padding-horizontal-s: $global-gutter !default;
-$container-padding-horizontal-m: $global-medium-gutter !default;
-$countdown-item-line-height: 70px !default;
-$countdown-number-font-size: 2rem !default;
-$countdown-number-font-size-s: 4rem !default;
-$countdown-number-font-size-m: 6rem !default;
-$countdown-separator-font-size: 1rem !default;
-$countdown-separator-font-size-s: 2rem !default;
-$countdown-separator-font-size-m: 3rem !default;
-$description-list-term-color: $global-emphasis-color !default;
-$description-list-term-margin-top: $global-margin !default;
-$description-list-divider-term-margin-top: $global-margin !default;
-$description-list-divider-term-border-width: $global-border-width !default;
-$description-list-divider-term-border: $global-border !default;
-$divider-margin-vertical: $global-margin !default;
-$divider-icon-width: 50px !default;
-$divider-icon-height: 20px !default;
-$divider-icon-color: $global-border !default;
-$divider-icon-line-top: 50% !default;
-$divider-icon-line-width: 100% !default;
-$divider-icon-line-border-width: $global-border-width !default;
-$divider-icon-line-border: $global-border !default;
-$internal-divider-icon-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2220%22%20height%3D%2220%22%20viewBox%3D%220%200%2020%2020%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Ccircle%20fill%3D%22none%22%20stroke%3D%22#000%22%20stroke-width%3D%222%22%20cx%3D%2210%22%20cy%3D%2210%22%20r%3D%227%22%20%2F%3E%0A%3C%2Fsvg%3E%0A" !default;
-$divider-small-width: 100px !default;
-$divider-small-border-width: $global-border-width !default;
-$divider-small-border: $global-border !default;
-$inverse-divider-icon-color: $inverse-global-border !default;
-$inverse-divider-icon-line-border: $inverse-global-border !default;
-$inverse-divider-small-border: $inverse-global-border !default;
-$dotnav-margin-horizontal: 12px !default;
-$dotnav-margin-vertical: $dotnav-margin-horizontal !default;
-$dotnav-item-width: 10px !default;
-$dotnav-item-height: $dotnav-item-width !default;
-$dotnav-item-border-radius: 50% !default;
-$dotnav-item-background: rgba($global-color, 0.2) !default;
-$dotnav-item-hover-background: rgba($global-color, 0.6) !default;
-$dotnav-item-onclick-background: rgba($global-color, 0.2) !default;
-$dotnav-item-active-background: rgba($global-color, 0.6) !default;
-$inverse-dotnav-item-background: rgba($inverse-global-color, 0.5) !default;
-$inverse-dotnav-item-hover-background: rgba($inverse-global-color, 0.9) !default;
-$inverse-dotnav-item-onclick-background: rgba($inverse-global-color, 0.5) !default;
-$inverse-dotnav-item-active-background: rgba($inverse-global-color, 0.9) !default;
-$global-z-index: 1000 !default;
-$drop-z-index: $global-z-index + 20 !default;
-$drop-width: 300px !default;
-$drop-margin: $global-margin !default;
-$dropdown-z-index: $global-z-index + 20 !default;
-$dropdown-min-width: 200px !default;
-$dropdown-padding: 15px !default;
-$dropdown-background: $global-muted-background !default;
-$dropdown-color: $global-color !default;
-$dropdown-margin: $global-small-margin !default;
-$dropdown-nav-item-color: $global-muted-color !default;
-$dropdown-nav-item-hover-color: $global-color !default;
-$dropdown-nav-header-color: $global-emphasis-color !default;
-$dropdown-nav-divider-border-width: $global-border-width !default;
-$dropdown-nav-divider-border: $global-border !default;
-$dropdown-nav-sublist-item-color: $global-muted-color !default;
-$dropdown-nav-sublist-item-hover-color: $global-color !default;
-$form-range-thumb-height: 15px !default;
-$form-range-thumb-border-radius: 500px !default;
-$form-range-thumb-background: $global-color !default;
-$form-range-track-height: 3px !default;
-$form-range-track-background: darken($global-muted-background, 5%) !default;
-$form-range-track-focus-background: darken($global-muted-background, 15%) !default;
-$form-height: $global-control-height !default;
-$form-line-height: $form-height !default;
-$form-padding-horizontal: 10px !default;
-$form-padding-vertical: 4px !default;
-$form-background: $global-muted-background !default;
-$form-color: $global-color !default;
-$form-focus-background: $global-muted-background !default;
-$form-focus-color: $global-color !default;
-$form-disabled-background: $global-muted-background !default;
-$form-disabled-color: $global-muted-color !default;
-$form-placeholder-color: $global-muted-color !default;
-$form-small-height: $global-control-small-height !default;
-$form-small-padding-horizontal: 8px !default;
-$form-small-line-height: $form-small-height !default;
-$form-small-font-size: $global-small-font-size !default;
-$form-large-height: $global-control-large-height !default;
-$form-large-padding-horizontal: 12px !default;
-$form-large-line-height: $form-large-height !default;
-$form-large-font-size: $global-medium-font-size !default;
-$form-danger-color: $global-danger-background !default;
-$form-success-color: $global-success-background !default;
-$form-width-xsmall: 50px !default;
-$form-width-small: 130px !default;
-$form-width-medium: 200px !default;
-$form-width-large: 500px !default;
-$form-select-padding-right: 20px !default;
-$form-select-icon-color: $global-color !default;
-$form-select-disabled-icon-color: $global-muted-color !default;
-$form-radio-size: 16px !default;
-$form-radio-margin-top: -4px !default;
-$form-radio-background: darken($global-muted-background, 5%) !default;
-$form-radio-checked-background: $global-primary-background !default;
-$form-radio-checked-icon-color: $global-inverse-color !default;
-$form-radio-checked-focus-background: darken($global-primary-background, 10%) !default;
-$form-radio-disabled-background: $global-muted-background !default;
-$form-radio-disabled-icon-color: $global-muted-color !default;
-$form-legend-font-size: $global-large-font-size !default;
-$form-legend-line-height: 1.4 !default;
-$form-stacked-margin-bottom: $global-small-margin !default;
-$form-horizontal-label-width: 200px !default;
-$form-horizontal-label-margin-top: 7px !default;
-$form-horizontal-controls-margin-left: 215px !default;
-$form-horizontal-controls-text-padding-top: 7px !default;
-$form-icon-width: $form-height !default;
-$form-icon-font-size: $global-font-size !default;
-$form-icon-color: $global-muted-color !default;
-$form-icon-hover-color: $global-color !default;
-$internal-form-select-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2224%22%20height%3D%2216%22%20viewBox%3D%220%200%2024%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22#000%22%20points%3D%2212%201%209%206%2015%206%22%20%2F%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22#000%22%20points%3D%2212%2013%209%208%2015%208%22%20%2F%3E%0A%3C%2Fsvg%3E%0A" !default;
-$internal-form-radio-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Ccircle%20fill%3D%22#000%22%20cx%3D%228%22%20cy%3D%228%22%20r%3D%222%22%20%2F%3E%0A%3C%2Fsvg%3E" !default;
-$internal-form-checkbox-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2214%22%20height%3D%2211%22%20viewBox%3D%220%200%2014%2011%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22#000%22%20points%3D%2212%201%205%207.5%202%205%201%205.5%205%2010%2013%201.5%22%20%2F%3E%0A%3C%2Fsvg%3E%0A" !default;
-$internal-form-checkbox-indeterminate-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Crect%20fill%3D%22#000%22%20x%3D%223%22%20y%3D%228%22%20width%3D%2210%22%20height%3D%221%22%20%2F%3E%0A%3C%2Fsvg%3E" !default;
-$inverse-global-muted-background: rgba($global-inverse-color, 0.1) !default;
-$inverse-form-background: $inverse-global-muted-background !default;
-$inverse-form-color: $inverse-global-color !default;
-$inverse-form-focus-background: $inverse-global-muted-background !default;
-$inverse-form-focus-color: $inverse-global-color !default;
-$inverse-form-placeholder-color: $inverse-global-muted-color !default;
-$inverse-form-select-icon-color: $inverse-global-color !default;
-$inverse-form-radio-background: darken($inverse-global-muted-background, 5%) !default;
-$inverse-form-radio-checked-background: $inverse-global-primary-background !default;
-$inverse-form-radio-checked-icon-color: $inverse-global-inverse-color !default;
-$inverse-form-radio-checked-focus-background: darken($inverse-global-primary-background, 10%) !default;
-$grid-gutter-horizontal: $global-gutter !default;
-$grid-gutter-vertical: $grid-gutter-horizontal !default;
-$grid-gutter-horizontal-l: $global-medium-gutter !default;
-$grid-gutter-vertical-l: $grid-gutter-horizontal-l !default;
-$grid-small-gutter-horizontal: $global-small-gutter !default;
-$grid-small-gutter-vertical: $grid-small-gutter-horizontal !default;
-$grid-medium-gutter-horizontal: $global-gutter !default;
-$grid-medium-gutter-vertical: $grid-medium-gutter-horizontal !default;
-$grid-large-gutter-horizontal: $global-medium-gutter !default;
-$grid-large-gutter-vertical: $grid-large-gutter-horizontal !default;
-$grid-large-gutter-horizontal-l: $global-large-gutter !default;
-$grid-large-gutter-vertical-l: $grid-large-gutter-horizontal-l !default;
-$grid-divider-border-width: $global-border-width !default;
-$grid-divider-border: $global-border !default;
-$inverse-grid-divider-border: $inverse-global-border !default;
-$heading-primary-font-size: $global-xxlarge-font-size !default;
-$heading-primary-line-height: 1.2 !default;
-$heading-primary-font-size-m: 3.75rem !default;
-$heading-primary-line-height-m: 1.1 !default;
-$heading-hero-font-size: 4rem !default;
-$heading-hero-line-height: 1.1 !default;
-$heading-hero-font-size-s: 6rem !default;
-$heading-hero-line-height-s: 1 !default;
-$heading-hero-font-size-m: 8rem !default;
-$heading-hero-line-height-m: 1 !default;
-$heading-divider-padding-bottom: 10px !default;
-$heading-divider-border-width: $global-border-width !default;
-$heading-divider-border: $global-border !default;
-$heading-bullet-top: unquote('calc(-0.1 * 1em)') !default;
-$heading-bullet-height: 0.9em !default;
-$heading-bullet-margin-right: 10px !default;
-$heading-bullet-border-width: 5px !default;
-$heading-bullet-border: $global-border !default;
-$heading-line-top: 50% !default;
-$heading-line-border-width: $global-border-width !default;
-$heading-line-height: $heading-line-border-width !default;
-$heading-line-width: 2000px !default;
-$heading-line-border: $global-border !default;
-$heading-line-margin-horizontal: 0.6em !default;
-$inverse-heading-divider-border: $inverse-global-border !default;
-$inverse-heading-bullet-border: $inverse-global-border !default;
-$inverse-heading-line-border: $inverse-global-border !default;
-$icon-image-size: 20px !default;
-$icon-link-color: $global-muted-color !default;
-$icon-link-hover-color: $global-color !default;
-$icon-link-active-color: darken($global-color, 5%) !default;
-$icon-button-size: 36px !default;
-$icon-button-border-radius: 500px !default;
-$icon-button-background: $global-muted-background !default;
-$icon-button-color: $global-muted-color !default;
-$icon-button-hover-background: darken($icon-button-background, 5%) !default;
-$icon-button-hover-color: $global-color !default;
-$icon-button-active-background: darken($icon-button-background, 10%) !default;
-$icon-button-active-color: $global-color !default;
-$inverse-icon-link-color: $inverse-global-muted-color !default;
-$inverse-icon-link-hover-color: $inverse-global-color !default;
-$inverse-icon-link-active-color: $inverse-global-color !default;
-$inverse-icon-button-background: $inverse-global-muted-background !default;
-$inverse-icon-button-color: $inverse-global-muted-color !default;
-$inverse-icon-button-hover-background: darken($inverse-icon-button-background, 5%) !default;
-$inverse-icon-button-hover-color: $inverse-global-color !default;
-$inverse-icon-button-active-background: darken($inverse-icon-button-background, 10%) !default;
-$inverse-icon-button-active-color: $inverse-global-color !default;
-$iconnav-margin-horizontal: $global-small-margin !default;
-$iconnav-margin-vertical: $iconnav-margin-horizontal !default;
-$iconnav-item-color: $global-muted-color !default;
-$iconnav-item-hover-color: $global-color !default;
-$iconnav-item-active-color: $global-color !default;
-$inverse-iconnav-item-color: $inverse-global-muted-color !default;
-$inverse-iconnav-item-hover-color: $inverse-global-color !default;
-$inverse-iconnav-item-active-color: $inverse-global-color !default;
-$inverse-global-color-mode: light !default;
-$label-padding-vertical: 0 !default;
-$label-padding-horizontal: $global-small-margin !default;
-$label-background: $global-primary-background !default;
-$label-line-height: $global-line-height !default;
-$label-font-size: $global-small-font-size !default;
-$label-color: $global-inverse-color !default;
-$label-success-background: $global-success-background !default;
-$label-success-color: $global-inverse-color !default;
-$label-warning-background: $global-warning-background !default;
-$label-warning-color: $global-inverse-color !default;
-$label-danger-background: $global-danger-background !default;
-$label-danger-color: $global-inverse-color !default;
-$inverse-label-background: $inverse-global-primary-background !default;
-$inverse-label-color: $inverse-global-inverse-color !default;
-$lightbox-z-index: $global-z-index + 10 !default;
-$lightbox-background: #000 !default;
-$lightbox-item-color: rgba(255,255,255,0.7) !default;
-$lightbox-toolbar-padding-vertical: 10px !default;
-$lightbox-toolbar-padding-horizontal: 10px !default;
-$lightbox-toolbar-background: rgba(0,0,0,0.3) !default;
-$lightbox-toolbar-color: rgba(255,255,255,0.7) !default;
-$lightbox-toolbar-icon-padding: 5px !default;
-$lightbox-toolbar-icon-color: rgba(255,255,255,0.7) !default;
-$lightbox-toolbar-icon-hover-color: #fff !default;
-$lightbox-button-size: 50px !default;
-$lightbox-button-background: $lightbox-toolbar-background !default;
-$lightbox-button-color: rgba(255,255,255,0.7) !default;
-$lightbox-button-hover-color: #fff !default;
-$link-muted-color: $global-muted-color !default;
-$link-muted-hover-color: $global-color !default;
-$link-text-hover-color: $global-muted-color !default;
-$link-heading-hover-color: $global-primary-background !default;
-$link-heading-hover-text-decoration: none !default;
-$inverse-link-muted-color: $inverse-global-muted-color !default;
-$inverse-link-muted-hover-color: $inverse-global-color !default;
-$inverse-link-text-hover-color: $inverse-global-muted-color !default;
-$inverse-link-heading-hover-color: $inverse-global-primary-background !default;
-$list-margin-top: $global-small-margin !default;
-$list-nested-padding-left: $global-gutter !default;
-$list-divider-margin-top: $global-small-margin !default;
-$list-divider-border-width: $global-border-width !default;
-$list-divider-border: $global-border !default;
-$list-striped-padding-vertical: $global-small-margin !default;
-$list-striped-padding-horizontal: $global-small-margin !default;
-$list-striped-background: $global-muted-background !default;
-$list-bullet-width: ($global-line-height * 1em) !default;
-$list-bullet-height: $list-bullet-width !default;
-$list-bullet-margin-right: $global-small-margin !default;
-$list-bullet-icon-color: $global-color !default;
-$list-large-margin-top: $global-margin !default;
-$list-large-divider-margin-top: $global-margin !default;
-$list-large-striped-padding-vertical: $global-margin !default;
-$list-large-striped-padding-horizontal: $global-small-margin !default;
-$internal-list-bullet-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%226%22%20height%3D%226%22%20viewBox%3D%220%200%206%206%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Ccircle%20fill%3D%22#000%22%20cx%3D%223%22%20cy%3D%223%22%20r%3D%223%22%20%2F%3E%0A%3C%2Fsvg%3E" !default;
-$inverse-list-divider-border: $inverse-global-border !default;
-$inverse-list-striped-background: $inverse-global-muted-background !default;
-$inverse-list-bullet-icon-color: $inverse-global-color !default;
-$margin-margin: $global-margin !default;
-$margin-small-margin: $global-small-margin !default;
-$margin-medium-margin: $global-medium-margin !default;
-$margin-large-margin: $global-medium-margin !default;
-$margin-large-margin-l: $global-large-margin !default;
-$margin-xlarge-margin: $global-large-margin !default;
-$global-xlarge-margin: 140px !default;
-$margin-xlarge-margin-l: $global-xlarge-margin !default;
-$marker-padding: 5px !default;
-$marker-background: $global-secondary-background !default;
-$marker-color: $global-inverse-color !default;
-$marker-hover-color: $global-inverse-color !default;
-$inverse-marker-background: $global-muted-background !default;
-$inverse-marker-color: $global-color !default;
-$inverse-marker-hover-color: $global-color !default;
-$modal-z-index: $global-z-index + 10 !default;
-$modal-background: rgba(0,0,0,0.6) !default;
-$modal-padding-horizontal: 15px !default;
-$modal-padding-horizontal-s: $global-gutter !default;
-$modal-padding-horizontal-m: $global-medium-gutter !default;
-$modal-padding-vertical: $modal-padding-horizontal !default;
-$modal-padding-vertical-s: 50px !default;
-$modal-dialog-width: 600px !default;
-$modal-dialog-background: $global-background !default;
-$modal-container-width: 1200px !default;
-$modal-body-padding-horizontal: $global-gutter !default;
-$modal-body-padding-vertical: $global-gutter !default;
-$modal-header-padding-horizontal: $global-gutter !default;
-$modal-header-padding-vertical: ($modal-header-padding-horizontal / 2) !default;
-$modal-header-background: $global-muted-background !default;
-$modal-footer-padding-horizontal: $global-gutter !default;
-$modal-footer-padding-vertical: ($modal-footer-padding-horizontal / 2) !default;
-$modal-footer-background: $global-muted-background !default;
-$modal-title-font-size: $global-xlarge-font-size !default;
-$modal-title-line-height: 1.3 !default;
-$modal-close-position: $global-small-margin !default;
-$modal-close-padding: 5px !default;
-$modal-close-outside-position: 0 !default;
-$modal-close-outside-translate: 100% !default;
-$modal-close-outside-color: lighten($global-inverse-color, 20%) !default;
-$modal-close-outside-hover-color: $global-inverse-color !default;
-$nav-item-padding-vertical: 5px !default;
-$nav-item-padding-horizontal: 0 !default;
-$nav-sublist-padding-vertical: 5px !default;
-$nav-sublist-padding-left: 15px !default;
-$nav-sublist-deeper-padding-left: 15px !default;
-$nav-sublist-item-padding-vertical: 2px !default;
-$nav-parent-icon-width: ($global-line-height * 1em) !default;
-$nav-parent-icon-height: $nav-parent-icon-width !default;
-$nav-parent-icon-color: $global-color !default;
-$nav-header-padding-vertical: $nav-item-padding-vertical !default;
-$nav-header-padding-horizontal: $nav-item-padding-horizontal !default;
-$nav-header-font-size: $global-small-font-size !default;
-$nav-header-text-transform: uppercase !default;
-$nav-header-margin-top: $global-margin !default;
-$nav-divider-margin-vertical: 5px !default;
-$nav-divider-margin-horizontal: 0 !default;
-$nav-default-item-color: $global-muted-color !default;
-$nav-default-item-hover-color: $global-color !default;
-$nav-default-item-active-color: $global-emphasis-color !default;
-$nav-default-header-color: $global-emphasis-color !default;
-$nav-default-divider-border-width: $global-border-width !default;
-$nav-default-divider-border: $global-border !default;
-$nav-default-sublist-item-color: $global-muted-color !default;
-$nav-default-sublist-item-hover-color: $global-color !default;
-$nav-primary-item-font-size: $global-large-font-size !default;
-$nav-primary-item-line-height: $global-line-height !default;
-$nav-primary-item-color: $global-muted-color !default;
-$nav-primary-item-hover-color: $global-color !default;
-$nav-primary-item-active-color: $global-emphasis-color !default;
-$nav-primary-header-color: $global-emphasis-color !default;
-$nav-primary-divider-border-width: $global-border-width !default;
-$nav-primary-divider-border: $global-border !default;
-$nav-primary-sublist-item-color: $global-muted-color !default;
-$nav-primary-sublist-item-hover-color: $global-color !default;
-$internal-nav-parent-close-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2214%22%20height%3D%2214%22%20viewBox%3D%220%200%2014%2014%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolyline%20fill%3D%22none%22%20stroke%3D%22#000%22%20stroke-width%3D%221.1%22%20points%3D%2210%201%204%207%2010%2013%22%20%2F%3E%0A%3C%2Fsvg%3E" !default;
-$internal-nav-parent-open-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2214%22%20height%3D%2214%22%20viewBox%3D%220%200%2014%2014%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolyline%20fill%3D%22none%22%20stroke%3D%22#000%22%20stroke-width%3D%221.1%22%20points%3D%221%204%207%2010%2013%204%22%20%2F%3E%0A%3C%2Fsvg%3E" !default;
-$inverse-nav-parent-icon-color: $inverse-global-color !default;
-$inverse-nav-default-item-color: $inverse-global-muted-color !default;
-$inverse-nav-default-item-hover-color: $inverse-global-color !default;
-$inverse-nav-default-item-active-color: $inverse-global-emphasis-color !default;
-$inverse-nav-default-header-color: $inverse-global-emphasis-color !default;
-$inverse-nav-default-divider-border: $inverse-global-border !default;
-$inverse-nav-default-sublist-item-color: $inverse-global-muted-color !default;
-$inverse-nav-default-sublist-item-hover-color: $inverse-global-color !default;
-$inverse-nav-primary-item-color: $inverse-global-muted-color !default;
-$inverse-nav-primary-item-hover-color: $inverse-global-color !default;
-$inverse-nav-primary-item-active-color: $inverse-global-emphasis-color !default;
-$inverse-nav-primary-header-color: $inverse-global-emphasis-color !default;
-$inverse-nav-primary-divider-border: $inverse-global-border !default;
-$inverse-nav-primary-sublist-item-color: $inverse-global-muted-color !default;
-$inverse-nav-primary-sublist-item-hover-color: $inverse-global-color !default;
-$navbar-background: $global-muted-background !default;
-$navbar-color-mode: none !default;
-$navbar-nav-item-height: 80px !default;
-$navbar-nav-item-padding-horizontal: 15px !default;
-$navbar-nav-item-color: $global-muted-color !default;
-$navbar-nav-item-font-size: $global-font-size !default;
-$navbar-nav-item-font-family: $global-font-family !default;
-$navbar-nav-item-hover-color: $global-color !default;
-$navbar-nav-item-onclick-color: $global-emphasis-color !default;
-$navbar-nav-item-active-color: $global-emphasis-color !default;
-$navbar-item-color: $global-color !default;
-$navbar-toggle-color: $global-muted-color !default;
-$navbar-toggle-hover-color: $global-color !default;
-$navbar-subtitle-font-size: $global-small-font-size !default;
-$navbar-dropdown-z-index: $global-z-index + 20 !default;
-$navbar-dropdown-width: 200px !default;
-$navbar-dropdown-margin: 0 !default;
-$navbar-dropdown-padding: 15px !default;
-$navbar-dropdown-background: $global-muted-background !default;
-$navbar-dropdown-color: $global-color !default;
-$navbar-dropdown-grid-gutter-horizontal: $global-gutter !default;
-$navbar-dropdown-grid-gutter-vertical: $navbar-dropdown-grid-gutter-horizontal !default;
-$navbar-dropdown-dropbar-margin-top: 0 !default;
-$navbar-dropdown-dropbar-margin-bottom: $navbar-dropdown-dropbar-margin-top !default;
-$navbar-dropdown-nav-item-color: $global-muted-color !default;
-$navbar-dropdown-nav-item-hover-color: $global-color !default;
-$navbar-dropdown-nav-item-active-color: $global-emphasis-color !default;
-$navbar-dropdown-nav-header-color: $global-emphasis-color !default;
-$navbar-dropdown-nav-divider-border-width: $global-border-width !default;
-$navbar-dropdown-nav-divider-border: $global-border !default;
-$navbar-dropdown-nav-sublist-item-color: $global-muted-color !default;
-$navbar-dropdown-nav-sublist-item-hover-color: $global-color !default;
-$navbar-dropbar-background: $navbar-dropdown-background !default;
-$navbar-dropbar-z-index: $global-z-index - 20 !default;
-$inverse-navbar-nav-item-color: $inverse-global-muted-color !default;
-$inverse-navbar-nav-item-hover-color: $inverse-global-color !default;
-$inverse-navbar-nav-item-onclick-color: $inverse-global-emphasis-color !default;
-$inverse-navbar-nav-item-active-color: $inverse-global-emphasis-color !default;
-$inverse-navbar-item-color: $inverse-global-color !default;
-$inverse-navbar-toggle-color: $inverse-global-muted-color !default;
-$inverse-navbar-toggle-hover-color: $inverse-global-color !default;
-$notification-position: 10px !default;
-$notification-z-index: $global-z-index + 40 !default;
-$notification-width: 350px !default;
-$notification-message-margin-bottom: 10px !default;
-$notification-message-padding: $global-small-gutter !default;
-$notification-message-background: $global-muted-background !default;
-$notification-message-color: $global-color !default;
-$notification-message-font-size: $global-medium-font-size !default;
-$notification-message-line-height: 1.4 !default;
-$notification-close-top: $notification-message-padding + 5px !default;
-$notification-close-right: $notification-message-padding !default;
-$notification-message-primary-color: $global-primary-background !default;
-$notification-message-success-color: $global-success-background !default;
-$notification-message-warning-color: $global-warning-background !default;
-$notification-message-danger-color: $global-danger-background !default;
-$offcanvas-z-index: $global-z-index !default;
-$offcanvas-bar-width: 270px !default;
-$offcanvas-bar-padding-vertical: $global-margin !default;
-$offcanvas-bar-padding-horizontal: $global-margin !default;
-$offcanvas-bar-background: $global-secondary-background !default;
-$offcanvas-bar-color-mode: light !default;
-$offcanvas-bar-width-m: 350px !default;
-$offcanvas-bar-padding-vertical-m: $global-medium-gutter !default;
-$offcanvas-bar-padding-horizontal-m: $global-medium-gutter !default;
-$offcanvas-close-position: 20px !default;
-$offcanvas-close-padding: 5px !default;
-$offcanvas-overlay-background: rgba(0,0,0,0.1) !default;
-$overlay-padding-horizontal: $global-gutter !default;
-$overlay-padding-vertical: $global-gutter !default;
-$overlay-default-background: rgba($global-background, 0.8) !default;
-$overlay-primary-background: rgba($global-secondary-background, 0.8) !default;
-$overlay-primary-color-mode: light !default;
-$padding-padding: $global-gutter !default;
-$padding-padding-l: $global-medium-gutter !default;
-$padding-small-padding: $global-small-gutter !default;
-$padding-large-padding: $global-gutter !default;
-$padding-large-padding-l: $global-large-gutter !default;
-$pagination-margin-horizontal: 20px !default;
-$pagination-item-color: $global-muted-color !default;
-$pagination-item-hover-color: $global-color !default;
-$pagination-item-hover-text-decoration: none !default;
-$pagination-item-active-color: $global-color !default;
-$pagination-item-disabled-color: $global-muted-color !default;
-$inverse-pagination-item-color: $inverse-global-muted-color !default;
-$inverse-pagination-item-hover-color: $inverse-global-color !default;
-$inverse-pagination-item-active-color: $inverse-global-color !default;
-$inverse-pagination-item-disabled-color: $inverse-global-muted-color !default;
-$placeholder-margin-vertical: $global-margin !default;
-$placeholder-padding-vertical: $global-gutter !default;
-$placeholder-padding-horizontal: $global-gutter !default;
-$placeholder-background: $global-muted-background !default;
-$position-small-margin: $global-small-gutter !default;
-$position-medium-margin: $global-gutter !default;
-$position-large-margin: $global-gutter !default;
-$position-large-margin-l: 50px !default;
-$progress-height: 15px !default;
-$progress-margin-vertical: $global-margin !default;
-$progress-background: $global-muted-background !default;
-$progress-bar-background: $global-primary-background !default;
-$search-color: $global-color !default;
-$search-placeholder-color: $global-muted-color !default;
-$search-icon-color: $global-muted-color !default;
-$search-default-width: 180px !default;
-$search-default-height: $global-control-height !default;
-$search-default-padding-horizontal: 6px !default;
-$search-default-background: $global-muted-background !default;
-$search-default-focus-background: $search-default-background !default;
-$search-default-icon-width: $global-control-height !default;
-$search-navbar-width: 400px !default;
-$search-navbar-height: 40px !default;
-$search-navbar-background: transparent !default;
-$search-navbar-font-size: $global-large-font-size !default;
-$search-navbar-icon-width: 40px !default;
-$search-large-width: 500px !default;
-$search-large-height: 80px !default;
-$search-large-background: transparent !default;
-$search-large-font-size: $global-xxlarge-font-size !default;
-$search-large-icon-width: 80px !default;
-$search-toggle-color: $global-muted-color !default;
-$search-toggle-hover-color: $global-color !default;
-$inverse-search-color: $inverse-global-color !default;
-$inverse-search-placeholder-color: $inverse-global-muted-color !default;
-$inverse-search-icon-color: $inverse-global-muted-color !default;
-$inverse-search-default-background: $inverse-global-muted-background !default;
-$inverse-search-default-focus-background: $inverse-search-default-background !default;
-$inverse-search-navbar-background: transparent !default;
-$inverse-search-large-background: transparent !default;
-$inverse-search-toggle-color: $inverse-global-muted-color !default;
-$inverse-search-toggle-hover-color: $inverse-global-color !default;
-$section-padding-vertical: $global-medium-margin !default;
-$section-padding-vertical-m: $global-large-margin !default;
-$section-xsmall-padding-vertical: $global-margin !default;
-$section-small-padding-vertical: $global-medium-margin !default;
-$section-large-padding-vertical: $global-large-margin !default;
-$section-large-padding-vertical-m: $global-xlarge-margin !default;
-$section-xlarge-padding-vertical: $global-xlarge-margin !default;
-$section-xlarge-padding-vertical-m: ($global-large-margin + $global-xlarge-margin) !default;
-$section-default-background: $global-background !default;
-$section-muted-background: $global-muted-background !default;
-$section-primary-background: $global-primary-background !default;
-$section-primary-color-mode: light !default;
-$section-secondary-background: $global-secondary-background !default;
-$section-secondary-color-mode: light !default;
-$slidenav-padding-vertical: 5px !default;
-$slidenav-padding-horizontal: 10px !default;
-$slidenav-color: rgba($global-color, 0.5) !default;
-$slidenav-hover-color: rgba($global-color, 0.9) !default;
-$slidenav-active-color: rgba($global-color, 0.5) !default;
-$slidenav-large-padding-vertical: 10px !default;
-$slidenav-large-padding-horizontal: $slidenav-large-padding-vertical !default;
-$inverse-slidenav-color: rgba($inverse-global-color, 0.7) !default;
-$inverse-slidenav-hover-color: rgba($inverse-global-color, 0.95) !default;
-$inverse-slidenav-active-color: rgba($inverse-global-color, 0.7) !default;
-$sortable-dragged-z-index: $global-z-index + 50 !default;
-$sortable-placeholder-opacity: 0 !default;
-$sortable-empty-height: 50px !default;
-$spinner-size: 30px !default;
-$spinner-stroke-width: 1 !default;
-$spinner-radius: floor(($spinner-size - $spinner-stroke-width) / 2) !default;
-$spinner-circumference: round(2 * 3.141 * $spinner-radius) !default;
-$spinner-duration: 1.4s !default;
-$sticky-z-index: $global-z-index - 20 !default;
-$sticky-animation-duration: 0.2s !default;
-$sticky-reverse-animation-duration: 0.2s !default;
-$subnav-margin-horizontal: 20px !default;
-$subnav-item-color: $global-muted-color !default;
-$subnav-item-hover-color: $global-color !default;
-$subnav-item-hover-text-decoration: none !default;
-$subnav-item-active-color: $global-emphasis-color !default;
-$subnav-divider-margin-horizontal: $subnav-margin-horizontal !default;
-$subnav-divider-border-height: 1.5em !default;
-$subnav-divider-border-width: $global-border-width !default;
-$subnav-divider-border: $global-border !default;
-$subnav-pill-item-padding-vertical: 5px !default;
-$subnav-pill-item-padding-horizontal: 10px !default;
-$subnav-pill-item-background: transparent !default;
-$subnav-pill-item-color: $subnav-item-color !default;
-$subnav-pill-item-hover-background: $global-muted-background !default;
-$subnav-pill-item-hover-color: $global-color !default;
-$subnav-pill-item-onclick-background: $subnav-pill-item-hover-background !default;
-$subnav-pill-item-onclick-color: $subnav-pill-item-hover-color !default;
-$subnav-pill-item-active-background: $global-primary-background !default;
-$subnav-pill-item-active-color: $global-inverse-color !default;
-$subnav-item-disabled-color: $global-muted-color !default;
-$inverse-subnav-item-color: $inverse-global-muted-color !default;
-$inverse-subnav-item-hover-color: $inverse-global-color !default;
-$inverse-subnav-item-active-color: $inverse-global-emphasis-color !default;
-$inverse-subnav-divider-border: $inverse-global-border !default;
-$inverse-subnav-pill-item-background: transparent !default;
-$inverse-subnav-pill-item-color: $inverse-global-muted-color !default;
-$inverse-subnav-pill-item-hover-background: $inverse-global-muted-background !default;
-$inverse-subnav-pill-item-hover-color: $inverse-global-color !default;
-$inverse-subnav-pill-item-onclick-background: $inverse-subnav-pill-item-hover-background !default;
-$inverse-subnav-pill-item-onclick-color: $inverse-subnav-pill-item-hover-color !default;
-$inverse-subnav-pill-item-active-background: $inverse-global-primary-background !default;
-$inverse-subnav-pill-item-active-color: $inverse-global-inverse-color !default;
-$inverse-subnav-item-disabled-color: $inverse-global-muted-color !default;
-$tab-margin-horizontal: 20px !default;
-$tab-item-padding-horizontal: 10px !default;
-$tab-item-padding-vertical: 5px !default;
-$tab-item-color: $global-muted-color !default;
-$tab-item-hover-color: $global-color !default;
-$tab-item-hover-text-decoration: none !default;
-$tab-item-active-color: $global-emphasis-color !default;
-$tab-item-disabled-color: $global-muted-color !default;
-$inverse-tab-item-color: $inverse-global-muted-color !default;
-$inverse-tab-item-hover-color: $inverse-global-color !default;
-$inverse-tab-item-active-color: $inverse-global-emphasis-color !default;
-$inverse-tab-item-disabled-color: $inverse-global-muted-color !default;
-$table-margin-vertical: $global-margin !default;
-$table-cell-padding-vertical: 16px !default;
-$table-cell-padding-horizontal: 12px !default;
-$table-header-cell-font-size: $global-font-size !default;
-$table-header-cell-font-weight: bold !default;
-$table-header-cell-color: $global-color !default;
-$table-footer-font-size: $global-small-font-size !default;
-$table-caption-font-size: $global-small-font-size !default;
-$table-caption-color: $global-muted-color !default;
-$table-row-active-background: #ffd !default;
-$table-divider-border-width: $global-border-width !default;
-$table-divider-border: $global-border !default;
-$table-striped-row-background: $global-muted-background !default;
-$table-hover-row-background: $table-row-active-background !default;
-$table-small-cell-padding-vertical: 10px !default;
-$table-small-cell-padding-horizontal: 12px !default;
-$table-large-cell-padding-vertical: 22px !default;
-$table-large-cell-padding-horizontal: 12px !default;
-$table-expand-min-width: 150px !default;
-$inverse-table-header-cell-color: $inverse-global-color !default;
-$inverse-table-caption-color: $inverse-global-muted-color !default;
-$inverse-table-row-active-background: fade-out($inverse-global-muted-background, 0.02) !default;
-$inverse-table-divider-border: $inverse-global-border !default;
-$inverse-table-striped-row-background: $inverse-global-muted-background !default;
-$inverse-table-hover-row-background: $inverse-table-row-active-background !default;
-$text-lead-font-size: $global-large-font-size !default;
-$text-lead-line-height: 1.5 !default;
-$text-lead-color: $global-emphasis-color !default;
-$text-meta-font-size: $global-small-font-size !default;
-$text-meta-line-height: 1.4 !default;
-$text-meta-color: $global-muted-color !default;
-$text-small-font-size: $global-small-font-size !default;
-$text-small-line-height: 1.5 !default;
-$text-large-font-size: $global-large-font-size !default;
-$text-large-line-height: 1.5 !default;
-$text-bold-font-weight: bolder !default;
-$text-muted-color: $global-muted-color !default;
-$text-primary-color: $global-primary-background !default;
-$text-success-color: $global-success-background !default;
-$text-warning-color: $global-warning-background !default;
-$text-danger-color: $global-danger-background !default;
-$text-background-color: $global-primary-background !default;
-$inverse-text-lead-color: $inverse-global-color !default;
-$inverse-text-meta-color: $inverse-global-muted-color !default;
-$inverse-text-muted-color: $inverse-global-muted-color !default;
-$inverse-text-primary-color: $inverse-global-color !default;
-$thumbnav-margin-horizontal: 15px !default;
-$thumbnav-margin-vertical: $thumbnav-margin-horizontal !default;
-$tile-padding-horizontal: 15px !default;
-$tile-padding-horizontal-s: $global-gutter !default;
-$tile-padding-horizontal-m: $global-medium-gutter !default;
-$tile-padding-vertical: $global-medium-margin !default;
-$tile-padding-vertical-m: $global-large-margin !default;
-$tile-xsmall-padding-vertical: $global-margin !default;
-$tile-small-padding-vertical: $global-medium-margin !default;
-$tile-large-padding-vertical: $global-large-margin !default;
-$tile-large-padding-vertical-m: $global-xlarge-margin !default;
-$tile-xlarge-padding-vertical: $global-xlarge-margin !default;
-$tile-xlarge-padding-vertical-m: ($global-large-margin + $global-xlarge-margin) !default;
-$tile-default-background: $global-background !default;
-$tile-muted-background: $global-muted-background !default;
-$tile-primary-background: $global-primary-background !default;
-$tile-primary-color-mode: light !default;
-$tile-secondary-background: $global-secondary-background !default;
-$tile-secondary-color-mode: light !default;
-$tooltip-z-index: $global-z-index + 30 !default;
-$tooltip-max-width: 200px !default;
-$tooltip-padding-vertical: 3px !default;
-$tooltip-padding-horizontal: 6px !default;
-$tooltip-background: #666 !default;
-$tooltip-border-radius: 2px !default;
-$tooltip-color: $global-inverse-color !default;
-$tooltip-font-size: 12px !default;
-$tooltip-margin: 10px !default;
-$totop-padding: 5px !default;
-$totop-color: $global-muted-color !default;
-$totop-hover-color: $global-color !default;
-$totop-active-color: $global-emphasis-color !default;
-$inverse-totop-color: $inverse-global-muted-color !default;
-$inverse-totop-hover-color: $inverse-global-color !default;
-$inverse-totop-active-color: $inverse-global-emphasis-color !default;
-$transition-duration: 0.3s !default;
-$transition-scale: 1.1 !default;
-$transition-slide-small-translate: 10px !default;
-$transition-slide-medium-translate: 50px !default;
-$transition-slow-duration: 0.7s !default;
-$panel-scrollable-height: 170px !default;
-$panel-scrollable-padding: 10px !default;
-$panel-scrollable-border-width: $global-border-width !default;
-$panel-scrollable-border: $global-border !default;
-$height-small-height: 150px !default;
-$height-medium-height: 300px !default;
-$height-large-height: 450px !default;
-$border-rounded-border-radius: 5px !default;
-$box-shadow-duration: 0.1s !default;
-$box-shadow-bottom-height: 30px !default;
-$box-shadow-bottom-border-radius: 100% !default;
-$box-shadow-bottom-background: #444 !default;
-$box-shadow-bottom-blur: 20px !default;
-$dropcap-margin-right: 10px !default;
-$dropcap-font-size: (($global-line-height * 3) * 1em) !default;
-$leader-fill-content: '.' !default;
-$leader-fill-margin-left: $global-small-gutter !default;
-$logo-font-size: $global-large-font-size !default;
-$logo-font-family: $global-font-family !default;
-$logo-color: $global-color !default;
-$logo-hover-color: $global-color !default;
-$dragover-box-shadow: 0 0 20px rgba(100,100,100,0.3) !default;
-$inverse-logo-color: $inverse-global-color !default;
-$inverse-logo-hover-color: $inverse-global-color !default;
-$breakpoint-small: 640px !default;
-$breakpoint-medium: 960px !default;
-$breakpoint-large: 1200px !default;
-$breakpoint-xlarge: 1600px !default;
-$breakpoint-xsmall-max: ($breakpoint-small - 1) !default;
-$breakpoint-small-max: ($breakpoint-medium - 1) !default;
-$breakpoint-medium-max: ($breakpoint-large - 1) !default;
-$breakpoint-large-max: ($breakpoint-xlarge - 1) !default;
-$global-small-box-shadow: 0 2px 8px rgba(0,0,0,0.08) !default;
-$global-medium-box-shadow: 0 5px 15px rgba(0,0,0,0.08) !default;
-$global-large-box-shadow: 0 14px 25px rgba(0,0,0,0.16) !default;
-$global-xlarge-box-shadow: 0 28px 50px rgba(0,0,0,0.16) !default;
-$width-small-width: 150px !default;
-$width-medium-width: 300px !default;
-$width-large-width: 450px !default;
-$width-xlarge-width: 600px !default;
-$width-xxlarge-width: 750px !default;
\ No newline at end of file
diff --git a/_site/2017/05/25/post63.html b/_site/2017/05/25/post63.html
deleted file mode 100644
index edf224762c..0000000000
--- a/_site/2017/05/25/post63.html
+++ /dev/null
@@ -1,356 +0,0 @@
-
-
-
-
-
-
-
-
-
Site tags | Blockstack
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Site tags
-
-
-
-
-
-
https://zbabystack.netlify.com/assets/posts/
-
-
/2017/05/25/post63.html
-
-
Musce libero nunc, dignissim quis turpis quis, semper vehicula dolor. Suspendisse tincidunt consequat quam, ac posuere leo dapibus id. Cras fringilla convallis elit, at eleifend mi interam.
-
-
Nulla non sollicitudin. Morbi sit amet laoreet ipsum, vel pretium mi. Morbi varius, tellus in accumsan blandit, elit ligula eleifend velit, luctus mattis ante nulla condimentum nulla. Etiam vestibulum risus vel arcu elementum eleifend. Cras at dolor eget urna varius faucibus tempus in elit.
-
-
Image Lightbox Example
-
Nunc porta malesuada porta. Etiam tristique vestibulum dolor at ultricies. Proin hendrerit sapien sed erat fermentum, at commodo velit consectetur.
-
-
-
-
-
-
-
-
-
-
- Image in lightbox
-
-
-
Etiam vestibulum risus vel arcu elementum eleifend. Cras at dolor eget urna varius faucibus tempus in elit. Cras a dui imperdiet, tempus metus quis, pharetra turpis. Phasellus at massa sit amet ante semper fermentum sed eget lectus. Quisque id dictum magna, et dapibus turpis.
-
-
Example Of Code Block
-
In accumsan lacus ac neque maximus dictum. Phasellus eleifend leo id mattis bibendum. Curabitur et purus turpis. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;
-
-
<head>
- <meta charset= "utf-8" >
- <meta http-equiv= "X-UA-Compatible" content= "IE=edge" >
- <meta name= "viewport" content= "width=device-width, initial-scale=1" >
- <link rel= "stylesheet" href= "/assets/css/main.css" >
- <link rel= "shortcut icon" type= "image/png" href= "/assets/img/favicon.png" >
- <script src= "/assets/js/main.js" ></script>
-</head>
-
-
-
-
Text and Quote
-
Cras at dolor eget urna varius faucibus tempus in elit. Cras a dui imperdiet, tempus metus quis, pharetra turpis. Phasellus at massa sit amet ante semper fermentum sed eget lectus. Quisque id dictum magna turpis.
-
-
- Etiam vestibulum risus vel arcu elementum eleifend. Cras at dolor eget urna varius faucibus tempus in elit. Cras a dui imperdiet
-
-
-
In accumsan lacus ac neque maximus dictum. Phasellus eleifend leo id mattis bibendum. Curabitur et purus turpis. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;
-
-
Etiam in fermentum mi. Sed et tempor felis, eu aliquet nisi. Nam eget ullamcorper arcu. Nunc porttitor nisl a dolor blandit, eget consequat sem maximus. Phasellus lacinia quam porta orci malesuada, vel tincidunt.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Blockstack
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/_site/404.html b/_site/404.html
deleted file mode 100644
index 61521fc718..0000000000
--- a/_site/404.html
+++ /dev/null
@@ -1,263 +0,0 @@
-
-
-
-
-
-
-
-
-
Feeling Lost | Blockstack
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Feeling Lost
-
-
-
The page you are looking for cannot be found. Please navigate to homepage .
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Blockstack
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/_site/android/images/app-flow.png b/_site/android/images/app-flow.png
deleted file mode 100644
index fa8b85a3bd..0000000000
Binary files a/_site/android/images/app-flow.png and /dev/null differ
diff --git a/_site/android/images/blockstack-install.png b/_site/android/images/blockstack-install.png
deleted file mode 100644
index 5e4d6256ad..0000000000
Binary files a/_site/android/images/blockstack-install.png and /dev/null differ
diff --git a/_site/android/images/blockstack-signin.png b/_site/android/images/blockstack-signin.png
deleted file mode 100644
index 081d505034..0000000000
Binary files a/_site/android/images/blockstack-signin.png and /dev/null differ
diff --git a/_site/android/images/chrome-prompt.png b/_site/android/images/chrome-prompt.png
deleted file mode 100644
index f60822ab55..0000000000
Binary files a/_site/android/images/chrome-prompt.png and /dev/null differ
diff --git a/_site/android/images/configure-activity.png b/_site/android/images/configure-activity.png
deleted file mode 100644
index 1be7edf580..0000000000
Binary files a/_site/android/images/configure-activity.png and /dev/null differ
diff --git a/_site/android/images/create-restore.png b/_site/android/images/create-restore.png
deleted file mode 100644
index 914b26e5b3..0000000000
Binary files a/_site/android/images/create-restore.png and /dev/null differ
diff --git a/_site/android/images/final-app.png b/_site/android/images/final-app.png
deleted file mode 100644
index 01f62b839a..0000000000
Binary files a/_site/android/images/final-app.png and /dev/null differ
diff --git a/_site/android/images/hello-andriod-1.png b/_site/android/images/hello-andriod-1.png
deleted file mode 100644
index c3680a2df8..0000000000
Binary files a/_site/android/images/hello-andriod-1.png and /dev/null differ
diff --git a/_site/android/images/initial-build.png b/_site/android/images/initial-build.png
deleted file mode 100644
index 601f3e8a18..0000000000
Binary files a/_site/android/images/initial-build.png and /dev/null differ
diff --git a/_site/android/images/new-interface.png b/_site/android/images/new-interface.png
deleted file mode 100644
index d434f9bba3..0000000000
Binary files a/_site/android/images/new-interface.png and /dev/null differ
diff --git a/_site/android/images/oreo-api.png b/_site/android/images/oreo-api.png
deleted file mode 100644
index 1de356914c..0000000000
Binary files a/_site/android/images/oreo-api.png and /dev/null differ
diff --git a/_site/android/images/running-app.png b/_site/android/images/running-app.png
deleted file mode 100644
index 9838c05f8c..0000000000
Binary files a/_site/android/images/running-app.png and /dev/null differ
diff --git a/_site/android/images/select-hdw.png b/_site/android/images/select-hdw.png
deleted file mode 100644
index 2eaccb4fcb..0000000000
Binary files a/_site/android/images/select-hdw.png and /dev/null differ
diff --git a/_site/android/images/studio-download.png b/_site/android/images/studio-download.png
deleted file mode 100644
index 8dc7314278..0000000000
Binary files a/_site/android/images/studio-download.png and /dev/null differ
diff --git a/_site/android/images/sync-project.png b/_site/android/images/sync-project.png
deleted file mode 100644
index b5e5c1412f..0000000000
Binary files a/_site/android/images/sync-project.png and /dev/null differ
diff --git a/_site/android/images/sync-success.png b/_site/android/images/sync-success.png
deleted file mode 100644
index 62ae3f5d21..0000000000
Binary files a/_site/android/images/sync-success.png and /dev/null differ
diff --git a/_site/android/tutorial.html b/_site/android/tutorial.html
deleted file mode 100644
index 576b1246f8..0000000000
--- a/_site/android/tutorial.html
+++ /dev/null
@@ -1,1236 +0,0 @@
-
-
-
-
-
-
-
-
-
Android SDK Tutorial (Pre-release) | Blockstack
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Android SDK Tutorial (Pre-release)
-
-
-
-
-
-
-
-
This tutorial is written for readers who are new to either or both Blockstack
-and Android to create a decentralized application. It contains the following
-content:
-
-
-
-
This tutorial was extensively tested using Android Studio 3.1 on a MacBook Air
-running High Sierra 10.13.4. If your environment is different, you may encounter
-slight or even major discrepancies when performing the procedures in this
-tutorial. Please join the Blockstack community
-Slack and post questions or comments to
-the #support channel.
-
-
Finally, this tutorial is written for all levels from the beginner to the most
-experienced. For best results, beginners should follow the guide as written. It
-is expected that the fast or furiously brilliant will skip ahead and improvise
-on this material at will. Fair journey one and all.
-
-
If you prefer, you can skip working through the tutorial all together. Instead,
-you can download the final project code and import it
-into Android Studio to review it.
-
-
Understand the sample application flow
-
-
When complete, the sample application is a simple hello-world display. It is
-intended for user on an Android phone.
-
-
-
-
Only users with an existing blockstack.id can run your
-final sample application. When complete, users interact with the sample
-application by doing the following:
-
-
-
-
Set up your environment
-
-
This sample application has two code bases, a BlockStack hello-blockstack
-application and a hello-andriod Android application. Before you start
-developing the sample, there are a few elements you need in your environment.
-
-
Install Android Studio
-
-
If you are an experienced Android developer and already have an Android
-development environment on your workstation, you can use that and skip this
-step. However, you will need to adjust the remaining instructions for your
-environment.
-
-
Follow the installation instructions to download and Android Studio
-3.1 for your operating system.
-Depending on your network connection, this can take between 15-30 minutes.
-
-
-
-
Do you have npm?
-
-
The Blockstack code in this tutorial relies on the npm dependency manager.
-Before you begin, verify you have installed npm using the which command to
-verify.
-
-
$ which npm
-/usr/local/bin/npm
-
-
-
-
If you don’t find npm in your system, install
-it .
-
-
Install the Blockstack test rig
-
-
Users interact with Blockstack-enabled applications through a web browser. You
-can BlockStack in test mode, on localhost or you can interact with completed
-apps through the Blockstack webapp which is available at
-[https://browser.blockstack.org/].
-
-
If you have already installed Blockstack for testing locally and have an
-existing Blockstack ID, skip this section. Otherwise, continue onto install
-BlockStack.
-
-
-
- Go to Blockstack
-
-
-
-
- Install the version appropriate for your operating system.
-
-
-
-
Use npm to install Yeoman and the Blockstack App Generator
-
-
You use npm to install Yeoman. Yeoman is a generic scaffolding system that
-helps users rapidly start new projects and streamline the maintenance of
-existing projects.
-
-
-
- Install Yeoman.
-
-
-
-
- Install the Blockstack application generator.
-
- npm install -g generator-blockstack
-
-
-
-
-
-
Build the Blockstack hello-world
-
-
In this section, you build a Blockstack hello-world application. Then, you
-modify the hello-world to interact with the Android app via a redirect.
-
-
Generate and launch your hello-blockstack application
-
-
In this section, you build an initial React.js application called
-hello-blockstack.
-
-
-
- Create a hello-blockstack directory.
-
- mkdir hello-blockstack
-
-
-
-
- Change into your new directory.
-
-
-
-
- Use Yeoman and the Blockstack application generator to create your initial hello-blockstack application.
-
-
-
- You should see several interactive prompts.
-
- $ yo blockstack:react
- ==========================================================================
- We are constantly looking for ways to make yo better!
- May we anonymously report usage statistics to improve the tool over time ?
- More info: https://github.com/yeoman/insight & http://yeoman.io
- ========================================================================== No
-
- _-----_ ╭──────────────────────────╮
- | | │ Welcome to the │
- |--( o) --| │ Blockstack app │
- --------- │ generator! │
- ( _U_ ) ╰──────────────────────────╯
- /___A___\ /
- | ~ |
- __'.___.' __
- |° Y
-
- ? Are you ready to build a Blockstack app in React? ( Y/n)
-
-
-
-
- Respond to the prompts to populate the initial app.
-
- After the process completes successfully, you see a prompt similar to the following:
-
- [ fsevents] Success:
- "/Users/theuser/repos/hello-blockstack/node_modules/fsevents/lib/binding/Release/node-v59-darwin-x64/fse.node"
- is installed via remote npm notice created a lockfile as package-lock.json.
- You should commit this file. added 1060 packages in 26.901s
-
-
-
-
- Run the initial application.
-
- $ npm start
-
- > hello-blockstack@0.0.0 start /Users/moxiegirl/repos/hello-blockstack
- > webpack-dev-server
-
- Project is running at http://localhost:8080/
- webpack output is served from /
- 404s will fallback to /index.html
- Hash: 4d2312ba236a4b95dc3a
- Version: webpack 2.7.0
- Time: 2969ms
- Asset Size Chunks Chunk Names
- ....
- Child html-webpack-plugin for "index.html" :
- chunk { 0} index.html 541 kB [ entry] [ rendered]
- [ 0] ./~/lodash/lodash.js 540 kB { 0} [ built]
- [ 1] ./~/html-webpack-plugin/lib/loader.js!./src/index.html 533 bytes { 0} [ built]
- [ 2] ( webpack) /buildin/global.js 509 bytes { 0} [ built]
- [ 3] ( webpack) /buildin/module.js 517 bytes { 0} [ built]
- webpack: Compiled successfully.
-
-
-
- The system opens a browser displaying your running application.
-
-
-
- At this point, the browser is running a Blockstack server on your local host.
-This is for testing your applications only.
-
-
- Choose Sign in with Blockstack
-
- The system displays a prompt allowing you to create a new Blockstack ID or restore an existing one.
-
-
-
-
- Follow the prompts appropriate to your situation.
-
- If you are restoring an existing ID, you may see a prompt about your user
- being nameless, ignore it. At this point you have only a single application
- on your test server. So, you should see this single application, with your
- own blockstack.id display name, once you are signed in:
-
-
-
-
-
-
Add a redirect end point to your application
-
-
When a user opens the webapp from the Blockstack browser on an Android phone,
-you want the web app to redirect the user to your Android application. The work
-you do here will allow it.
-
-
-
- From the terminal command line, change directory to the root of your sample
-application directory.
-
-
- Use the touch command to add a redirect endpoint to your application.
-
- This endpoint on the web version of your app will redirect Android users back
- to your mobile app.
-
- $ touch public/redirect.html
-
-
-
-
- Open redirect.html and add code to the endpoint.
-
- <!DOCTYPE html>
- <html>
- <head>
- <title> Hello, Blockstack!</title>
- <script>
- function getParameterByName ( name ) {
- var match = RegExp ( '[?&]' + name + '=([^&]*)' ). exec ( window . location . search );
- return match && decodeURIComponent ( match [ 1 ]. replace ( / \+ /g , ' ' ));
- }
-
- var authResponse = getParameterByName ( 'authResponse' )
- window . location = "myblockstackapp:" + authResponse
- </script>
- <body>
- </body>
- </html>
-
-
-
- Blockstack apps are identified by their domain names. The endpoint will
- receive a get request with the query parameter authResponse=XXXX and
- should redirect the browser to myblockstackapp:XXXX.
-
- myblockstackapp: is custom protocol handler. The handler should be unique
- to your application. Your app’s web-based authentication uses this handler
- to redirect the user back to your Android app. Later, you’ll add a reference
- to this handler in your Android application.
-
- Close and save the redirect.html file.
- Ensure your Blockstack compiles successfully.
-
-
-
Create the hello-android project
-
-
In this section, you’ll create an Android application in Android Studio. You’ll
-run the application in the emulator to test it.
-
-
Create a simple project
-
-
In this section, you create an inital project. You’ll validate the application’s
-iniatial state by creating an emulator to run it in. Open Android Studio and do the following:
-
-
-
- Open Android Studio and choose Start a new Andriod Studio project .
-
- If studio is already started, choose File > New > New Project .
-
-
- Enter these fields in the Create Android Project page.
-
-
-
- Application Name
- hello-android
-
-
- Company domain
- USERNAME .example.com
-
-
- Project location
- /Users/USERNAME /AndroidStudioProjects/helloandroid
-
-
- Include Kotlin support
- Set (checked)
-
-
-
- Press Next to display Target Android Devices .
- Check Phone and Tablet .
- Choose API 27: Andriod 8.1 (Oreo) for the target version.
- Press Next .
- Choose Empty Activity and press Next .
-
- Leave the Configure Activity dialog with its defaults.
-
-
-
-
- Press Finish .
-
- Android studio builds your initial project. This can take a bit the first time you do it.
-
-
-
-
-
-
Run the app in an emulator
-
-
In this section, you run the appliation and create an emulator when prompted.
-
-
-
- Once the project is imported into studio, click the app module in the Project window.
-
-
- Then, select Run > Run (or click the green arrow in the toolbar).
-
- Studio prompts you to Select Deployment Target .
-
-
- Choose Create New Virtual Device and press OK .
-
- Studio prompts you to Select Hardware .
-
-
- Choose a Phone running Pixel XL.
-
-
-
- Studio prompts you for a system image.
-
-
- Choose Oreo which is API level 27 and press Next .
-
-
-
- Studio asks you to verify your new emulator configuration.
-
-
- Press Finish .
-
- The emulation takes a moment to build. Then, studio launches the emulation and opens your application.
-
-
-
-
-
-
-
-
Now that you have created your initial project and verified it running in an emulator, you are ready to begin configuring the application for use with Blockstack.
-
-
- In studio, open the AndroidManifest.xml file.
-
- Add an <intent-filter> with the custom handler for Blockstack.
-
- <intent-filter>
- <action android:name="android.intent.action.VIEW" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.BROWSABLE" />
- <data android:scheme="myblockstackapp" />
- </intent-filter>
-
-
- Open the Project’s build.gradle file.
-
- Add the Jitpack repository maven { url 'https://jitpack.io' } to the repositories section.
-
- When you finish, that section looks like this:
-
- allprojects {
- repositories {
- google()
- jcenter()
- maven { url 'https://jitpack.io' }
- }
- }
-
-
- Open the Module build.gradle file.
-
- Set the defaultConfig minSdkVersion to 19.
-
- When you are done, you should see (within your own username not moxiegirl):
-
- android {
- compileSdkVersion 27
- defaultConfig {
- applicationId "com.example.moxiegirl.hello_android"
- minSdkVersion 19
- targetSdkVersion 27
- versionCode 1
- versionName "1.0"
- testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
- }
- ...
-}
-
-
-
- Below this, add the Blockstack Android SDK dependency to your project’s dependencies list:
-
- When you are done you should see:
-
- dependencies {
- implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
- implementation 'com.android.support:appcompat-v7:27.1.0'
- implementation 'com.android.support.constraint:constraint-layout:1.1.2'
- testImplementation 'junit:junit:4.12'
- androidTestImplementation 'com.android.support.test:runner:1.0.2'
- androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
- implementation 'com.github.blockstack:blockstack-android:0.3.0'
- }
-
-
-
- NOTE : Ignore the warning on the appcompat` dependencies.
-
-
- Sync your project.
-
-
-
- Be sure to check the sync completed successfully.
-
-
-
-
- Run your app in the emulator.
-
- You’ve made a lot of changes, make sure the emulator is still running
-correctly.
-
-
-
-
Add a simple interface
-
-
-
- Open the app/res/layout/activity_main.xml file.
-
- The activity_main.xml file defines the graphical elements. Some elements are required before you can functionality to your MainActivity.kt code.
-
-
- Replace the entire content of the file with the following code:
-
- The new interface includes a BlockstackSignInButton which is provided by
-the SDK. This SDK includes a themed “Sign in with Blockstack” button
-(BlockstackSignInButton). You use this button in your here with the
-org.blockstack.android.sdk.ui.BlockstackSignInButton class.
-
- <?xml version="1.0" encoding="utf-8"?>
- <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- tools:context=".MainActivity">
-
- <org.blockstack.android.sdk.ui.BlockstackSignInButton
- android:id="@+id/signInButton"
- android:layout_width="307dp"
- android:layout_height="45dp"
- android:layout_margin="4dp"
- android:layout_marginEnd="185dp"
- android:layout_marginStart="39dp"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- tools:layout_editor_absoluteY="16dp" />
-
- <TextView
- android:id="@+id/userDataTextView"
- android:layout_width="370dp"
- android:layout_height="27dp"
- tools:layout_editor_absoluteX="6dp"
- tools:layout_editor_absoluteY="70dp" />
-
- </android
-
-
- This codes adds a button and some text to your application.
-
-
- Choose Run > Apply changes .
-
-
- Choose Run > Run app in the emulator.
-
- The emulator now contains a new interface with a button:
-
-
-
-
-
-
Add session & authentication code
-
-
- Open the MainActivity.kt file.
-
- Add some additional imports to the top below the android.os.Bundle import.
-
- When you are done, your imports should appear as follows:
-
-
- import android.support.v7.app.AppCompatActivity
- import android.os.Bundle
-
- import android.support.v7.app.AppCompatActivity
- import android.view.View
- import kotlinx.android.synthetic.main.activity_main.*
- import org.blockstack.android.sdk.BlockstackSession
- import org.blockstack.android.sdk.Scope
- import org.blockstack.android.sdk.UserData
- import java.net.URI
-
-
-
-
- Add a variable for the Blockstack session before onCreate.
-
- class MainActivity : AppCompatActivity () {
-
- private var _blockstackSession : BlockstackSession ? = null
-
-
- override fun onCreate ( savedInstanceState : Bundle ?) {
- super . onCreate ( savedInstanceState )
- setContentView ( R . layout . activity_main )
- }
- }
-
-
-
-
- Replae the existing the onCreate function with the following:
-
- override fun onCreate ( savedInstanceState : Bundle ?) {
- super . onCreate ( savedInstanceState )
- setContentView ( R . layout . activity_main )
-
- signInButton . isEnabled = false
-
- val appDomain = URI ( "https://flamboyant-darwin-d11c17.netlify.com" )
- val redirectURI = URI ( "${appDomain}/redirect" )
- val manifestURI = URI ( "${appDomain}/manifest.json" )
- val scopes = arrayOf ( Scope . StoreWrite )
-
- val config = java . net . URI ( "https://flamboyant-darwin-d11c17.netlify.com" ). run {
- org . blockstack . android . sdk . BlockstackConfig (
- this ,
- redirectURI ,
- manifestURI ,
- scopes
- }
-
- _blockstackSession = BlockstackSession ( this , config ,
- onLoadedCallback = {
- signInButton . isEnabled = true
- })
-
-
- signInButton . setOnClickListener { view : View ->
- blockstackSession (). redirectUserToSignIn { userData ->
- if ( userData . hasValue ) {
- runOnUiThread {
- onSignIn ( userData . value !! )
- }
- }
- }
- }
- if ( intent ?. action == Intent . ACTION_VIEW ) {
- // handle the redirect from sign in
- handleAuthResponse ( intent )
- }
- }
-
-
-
- This new onCreate does several things:
-
-
- Define the initial state for the signInButton.
- Supply authentication information for connecting to your Blockstack app: appDomain, redirectURI, manifestURI and scopes
- Add a listener for the button click.
-
-
- Notice that the application in this example is a URI you have not set up.
- Registering and application name takes time, so in time’s interest you’ll
- use an existing app that is identical to the hello-world you created
- earlier. For a produciton verison, you’ll need to replace appDomain,
- redirectURI, manifestURI and scopes with values appropriate for your
- app.
-
-
- Add a private function to reflect when a user successfully signs in.
-
- private fun onSignIn ( userData : UserData ) {
- userDataTextView . text = "Signed in as ${userData.decentralizedID}"
-
- signInButton . isEnabled = false
-
- }
-
-
-
-
- Handle sign in requests with an onNewIntent function if the activity was already opened when signing in
-
- Retrieve the authentication token from the custom protocol handler call and
- send it to the Blockstack session.
-
- override fun onNewIntent ( intent : Intent ?) {
- super . onNewIntent ( intent )
-
- if ( intent ?. action == Intent . ACTION_VIEW ) {
- handleAuthResponse ( intent )
- }
- }
-
-
-
-
- Create a handler for the authentication response.
-
- private fun handleAuthResponse ( intent : Intent ) {
- val response = intent . dataString
- if ( response != null ) {
- val authResponseTokens = response . split ( ':' )
-
- if ( authResponseTokens . size > 1 ) {
- val authResponse = authResponseTokens [ 1 ]
-
- blockstackSession (). handlePendingSignIn ( authResponse , { userData ->
- if ( userData . hasValue ) {
- // The user is now signed in!
- runOnUiThread {
- onSignIn ( userData . value !! )
- }
- }
- })
- }
- }
- }
-
-
-
-
- Add the convenience method to access the blockstack session.
-
- fun blockstackSession () : BlockstackSession {
- val session = _blockstackSession
- if ( session != null ) {
- return session
- } else {
- throw IllegalStateException ( "No session." )
- }
- }
-
-
-
-
- Verify your final MainActivity.kt code looks like this:
-
- class MainActivity : AppCompatActivity () {
-
- private var _blockstackSession : BlockstackSession ? = null
-
-
- override fun onCreate ( savedInstanceState : Bundle ?) {
- super . onCreate ( savedInstanceState )
- setContentView ( R . layout . activity_main )
-
- signInButton . isEnabled = false
-
- val appDomain = URI ( "https://flamboyant-darwin-d11c17.netlify.com" )
- val redirectURI = URI ( "${appDomain}/redirect" )
- val manifestURI = URI ( "${appDomain}/manifest.json" )
- val scopes = arrayOf ( Scope . StoreWrite )
-
- _blockstackSession = BlockstackSession ( this , appDomain , redirectURI , manifestURI , scopes ,
- onLoadedCallback = { signInButton . isEnabled = true
- })
-
-
- signInButton . setOnClickListener { view : View ->
- blockstackSession (). redirectUserToSignIn { userData ->
- if ( userData . hasValue ) {
- runOnUiThread {
- onSignIn ( userData )
- }
- }
- }
- }
- if ( intent ?. action == Intent . ACTION_VIEW ) {
- handleAuthResponse ( intent )
- }
- }
-
- private fun onSignIn ( userData : UserData ) {
- userDataTextView . text = "Signed in as ${userData.decentralizedID}"
-
- signInButton . isEnabled = false
-
- }
-
- override fun onNewIntent ( intent : Intent ?) {
- super . onNewIntent ( intent )
-
- if ( intent ?. action == Intent . ACTION_VIEW ) {
- handleAuthResponse ( intent )
- }
- }
-
- private fun handleAuthResponse ( intent : Intent ) {
- val response = intent . dataString
- if ( response != null ) {
- val authResponseTokens = response . split ( ':' )
-
- if ( authResponseTokens . size > 1 ) {
- val authResponse = authResponseTokens [ 1 ]
-
- blockstackSession (). handlePendingSignIn ( authResponse , { userData ->
- if ( userData . hasValue ) {
- // The user is now signed in!
- runOnUiThread {
- onSignIn ( userData . value !! )
- }
- }
- })
- }
- }
- }
-
- fun blockstackSession () : BlockstackSession {
- val session = _blockstackSession
- if ( session != null ) {
- return session
- } else {
- throw IllegalStateException ( "No session." )
- }
- }
-
-
- }
-
-
-
-
-
-
Run the final app in the emulator
-
-
- Choose Run > Apply changes .
- Choose Run > Run app in the emulator.
-
- When you see the application open, choose Sign in with Blockstack .
-
- The system prompts you how to open.
-
-
-
- Choose Chrome and click ALWAYS .
-
- Move through the rest of the Chrome prompts.
-
- The system presents you with your final application.
-
-
-
- Work through the Blockstack prompts to login.
-
-
-
Where to go next
-
-
Congratulations, you’ve completed your Android app using the new, pre-release
-Blockstack Android SDK. Thank you for trying this pre-release. Please let us
-know about your experience by tweeting to
-@blockstack .
-
-
Learn more about Blockstack by trying another tutorial .
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Related Articles
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Blockstack
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/_site/assets/css/main.css b/_site/assets/css/main.css
deleted file mode 100644
index a7790286bd..0000000000
--- a/_site/assets/css/main.css
+++ /dev/null
@@ -1 +0,0 @@
-/*! system-font.css v2.0.2 | CC0-1.0 License | github.com/jonathantneal/system-font-css */@font-face{font-family:system-ui;font-style:normal;font-weight:300;src:local(".SFNSText-Light"),local(".HelveticaNeueDeskInterface-Light"),local(".LucidaGrandeUI"),local("Segoe UI Light"),local("Ubuntu Light"),local("Roboto-Light"),local("DroidSans"),local("Tahoma")}@font-face{font-family:system-ui;font-style:italic;font-weight:300;src:local(".SFNSText-LightItalic"),local(".HelveticaNeueDeskInterface-Italic"),local(".LucidaGrandeUI"),local("Segoe UI Light Italic"),local("Ubuntu Light Italic"),local("Roboto-LightItalic"),local("DroidSans"),local("Tahoma")}@font-face{font-family:system-ui;font-style:normal;font-weight:400;src:local(".SFNSText-Regular"),local(".HelveticaNeueDeskInterface-Regular"),local(".LucidaGrandeUI"),local("Segoe UI"),local("Ubuntu"),local("Roboto-Regular"),local("DroidSans"),local("Tahoma")}@font-face{font-family:system-ui;font-style:italic;font-weight:400;src:local(".SFNSText-Italic"),local(".HelveticaNeueDeskInterface-Italic"),local(".LucidaGrandeUI"),local("Segoe UI Italic"),local("Ubuntu Italic"),local("Roboto-Italic"),local("DroidSans"),local("Tahoma")}@font-face{font-family:system-ui;font-style:normal;font-weight:500;src:local(".SFNSText-Medium"),local(".HelveticaNeueDeskInterface-MediumP4"),local(".LucidaGrandeUI"),local("Segoe UI Semibold"),local("Ubuntu Medium"),local("Roboto-Medium"),local("DroidSans-Bold"),local("Tahoma Bold")}@font-face{font-family:system-ui;font-style:italic;font-weight:500;src:local(".SFNSText-MediumItalic"),local(".HelveticaNeueDeskInterface-MediumItalicP4"),local(".LucidaGrandeUI"),local("Segoe UI Semibold Italic"),local("Ubuntu Medium Italic"),local("Roboto-MediumItalic"),local("DroidSans-Bold"),local("Tahoma Bold")}@font-face{font-family:system-ui;font-style:normal;font-weight:700;src:local(".SFNSText-Bold"),local(".HelveticaNeueDeskInterface-Bold"),local(".LucidaGrandeUI"),local("Segoe UI Bold"),local("Ubuntu Bold"),local("Roboto-Bold"),local("DroidSans-Bold"),local("Tahoma Bold")}@font-face{font-family:system-ui;font-style:italic;font-weight:700;src:local(".SFNSText-BoldItalic"),local(".HelveticaNeueDeskInterface-BoldItalic"),local(".LucidaGrandeUI"),local("Segoe UI Bold Italic"),local("Ubuntu Bold Italic"),local("Roboto-BoldItalic"),local("DroidSans-Bold"),local("Tahoma Bold")}.sidebar-fixed-width{width:260px}.sidebar-docs{width:220px;padding-right:40px;top:112px;bottom:70px;overflow-y:scroll;overflow-x:hidden}.sidebar-docs>h5{margin:15px 0 0}.sidebar-docs>h5:first-child{margin-top:17px}@media (min-width: 1200px){.sidebar-fixed-width{width:360px}.sidebar-docs{width:290px;padding-right:70px}}ul.doc-nav{padding-left:14px;margin-top:5px}.doc-nav>li.uk-active>a{position:relative}.doc-nav>li.uk-active>a:before{content:"";position:absolute;top:15px;left:-14px;width:7px;border-top:1px solid #0F1214}.hero-image img{max-width:200px;max-height:75px}.button-cta:nth-child(2n),.button-cta:nth-child(3n){margin-top:20px}.heading-hero-2{font-size:1.875rem}@media (min-width: 640px){.heading-hero-2{font-size:1.375rem}}@media (min-width: 960px){.heading-hero-2{font-size:1.75rem}}.list-featured>li:first-child{margin-top:20px}@media (min-width: 640px){.tm-timeline{box-sizing:border-box;position:relative}.tm-timeline *{box-sizing:border-box}.tm-timeline:before{content:'';position:absolute;top:0;left:calc(30% - 2px);bottom:0;width:4px;background:#0F1214}.tm-timeline:after{content:"";display:table;clear:both}.tm-timeline-entry{clear:both;text-align:left;position:relative}.tm-timeline-entry+.tm-timeline-entry{margin-top:70px}.tm-timeline-entry:after{display:block;content:"";clear:both}.tm-timeline-entry .tm-timeline-time{float:left;width:30%;padding-right:70px;text-align:right;position:relative}.tm-timeline-entry .tm-timeline-time:before{content:'';position:absolute;width:20px;height:20px;border:4px solid #0F1214;background-color:#fff;border-radius:100%;top:0;right:-14px;z-index:99}.tm-timeline-entry .tm-timeline-time h5{margin:3px 0 0}.tm-timeline-entry .tm-timeline-body{float:right;width:70%;padding-left:70px;margin-top:-2px}.tm-timeline-entry .tm-timeline-body h3{margin:0 0 15px}.tm-timeline-entry .tm-timeline-body h3 span{font-size:.7rem;margin-bottom:4px;padding:0 5px}}html{font-family:system-ui;font-size:16px;font-weight:normal;line-height:1.5;-webkit-text-size-adjust:100%;background:#fff;color:#0F1214;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}body{margin:0}a{-webkit-text-decoration-skip:objects}a:active,a:hover{outline:none}a,.uk-link{color:#7a838a;text-decoration:none;cursor:pointer}a:hover,.uk-link:hover{color:#000;text-decoration:underline}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}:not(pre)>code,:not(pre)>kbd,:not(pre)>samp{font-family:Consolas,monaco,monospace;font-size:.875rem;color:#f0506e;white-space:nowrap;padding:2px 6px;background:#f8f8f8}em{color:#f0506e}ins{background:#ffd;color:#666;text-decoration:none}mark{background:#ffd;color:#666}q{font-style:italic}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}audio,canvas,iframe,img,svg,video{vertical-align:middle}audio,canvas,img,video{max-width:100%;height:auto;box-sizing:border-box}svg:not(:root){overflow:hidden}p,ul,ol,dl,pre,address,fieldset,figure{margin:0 0 20px 0}*+p,*+ul,*+ol,*+dl,*+pre,*+address,*+fieldset,*+figure{margin-top:20px}h1,.uk-h1,h2,.uk-h2,h3,.uk-h3,h4,.uk-h4,h5,.uk-h5,h6,.uk-h6{margin:0 0 20px 0;font-family:system-ui;font-weight:bold;color:#0F1214;text-transform:none}*+h1,*+.uk-h1,*+h2,*+.uk-h2,*+h3,*+.uk-h3,*+h4,*+.uk-h4,*+h5,*+.uk-h5,*+h6,*+.uk-h6{margin-top:50px}h1,.uk-h1{font-size:1.875rem;line-height:1.2}h2,.uk-h2{font-size:1.625rem;line-height:1.4}h3,.uk-h3{font-size:1.375rem;line-height:1.4}h4,.uk-h4{font-size:1.125rem;line-height:1.4}h5,.uk-h5{font-size:16px;line-height:1.4}h6,.uk-h6{font-size:.875rem;line-height:1.4}ul,ol{padding-left:30px}ul>li>ul,ul>li>ol,ol>li>ol,ol>li>ul{margin:0}dt{font-weight:bold}dd{margin-left:0}hr,.uk-hr{box-sizing:content-box;height:0;overflow:visible;text-align:inherit;margin:0 0 20px 0;border:0;border-top:1px solid #e7e8e9}*+hr,*+.uk-hr{margin-top:20px}address{font-style:normal}blockquote{margin:0 0 20px 0;font-size:1.125rem;line-height:1.5;font-style:italic;color:#333}*+blockquote{margin-top:20px}blockquote p:last-of-type{margin-bottom:0}blockquote footer{margin-top:10px;font-size:.875rem;line-height:1.5;color:#666}blockquote footer::before{content:"— "}pre{font:.875rem / 1.5 Consolas,monaco,monospace;color:#666;-moz-tab-size:4;tab-size:4;overflow:auto;padding:10px;border:1px solid #c4c7ca;border-radius:3px;background:#fff}pre code{font-family:Consolas,monaco,monospace}::-moz-selection{background:#39f;color:#fff;text-shadow:none}::selection{background:#39f;color:#fff;text-shadow:none}details,main{display:block}summary{display:list-item}template{display:none}iframe{border:0}a,area,button,input,label,select,summary,textarea{touch-action:manipulation}.var-media-s::before{content:"640px"}.var-media-m::before{content:"960px"}.var-media-l::before{content:"1200px"}.var-media-xl::before{content:"1600px"}input[type="submit" i]{-webkit-appearance:none}a.uk-link-muted,.uk-link-muted a{color:#7a838a}a.uk-link-muted:hover,.uk-link-muted a:hover{color:#0F1214}a.uk-link-text:not(:hover),.uk-link-text a:not(:hover){color:inherit}a.uk-link-text:hover,.uk-link-text a:hover{color:#7a838a}a.uk-link-heading:not(:hover),.uk-link-heading a:not(:hover){color:inherit}a.uk-link-heading:hover,.uk-link-heading a:hover{color:#0F1214;text-decoration:none}a.uk-link-reset,a.uk-link-reset:hover,.uk-link-reset a,.uk-link-reset a:hover{color:inherit !important;text-decoration:none !important}.uk-heading-primary{font-size:1.875rem;line-height:1.2}@media (min-width: 960px){.uk-heading-primary{font-size:3.75rem;line-height:1.1}}.uk-heading-hero{font-size:2.375rem;line-height:1.3;font-weight:bold}@media (min-width: 640px){.uk-heading-hero{font-size:2.9375rem;line-height:1.3}}@media (min-width: 960px){.uk-heading-hero{font-size:3.625rem;line-height:1.4}}.uk-heading-divider{padding-bottom:10px;border-bottom:1px solid #c4c7ca}.uk-heading-bullet{position:relative}.uk-heading-bullet::before{content:"";display:inline-block;position:relative;top:calc(-0.1 * 1em);vertical-align:middle;height:.9em;margin-right:10px;border-left:5px solid #c4c7ca}.uk-heading-line{overflow:hidden}.uk-heading-line>*{display:inline-block;position:relative}.uk-heading-line>::before,.uk-heading-line>::after{content:"";position:absolute;top:calc(50% - (1px / 2));width:2000px;border-bottom:1px solid #c4c7ca}.uk-heading-line>::before{right:100%;margin-right:.6em}.uk-heading-line>::after{left:100%;margin-left:.6em}[class*='uk-divider']{border:none;margin-bottom:20px}*+[class*='uk-divider']{margin-top:20px}.uk-divider-icon{position:relative;height:20px;background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2220%22%20height%3D%2220%22%20viewBox%3D%220%200%2020%2020%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Ccircle%20fill%3D%22none%22%20stroke%3D%22%23c4c7ca%22%20stroke-width%3D%222%22%20cx%3D%2210%22%20cy%3D%2210%22%20r%3D%227%22%20%2F%3E%0A%3C%2Fsvg%3E%0A");background-repeat:no-repeat;background-position:50% 50%}.uk-divider-icon::before,.uk-divider-icon::after{content:"";position:absolute;top:50%;max-width:calc(50% - (50px / 2));border-bottom:1px solid #c4c7ca}.uk-divider-icon::before{right:calc(50% + (50px / 2));width:100%}.uk-divider-icon::after{left:calc(50% + (50px / 2));width:100%}.uk-divider-small{line-height:0}.uk-divider-small::after{content:"";display:inline-block;width:100px;max-width:100%;border-top:1px solid #c4c7ca;vertical-align:top}.uk-list{padding:0;list-style:none}.uk-list>li::before,.uk-list>li::after{content:"";display:table}.uk-list>li::after{clear:both}.uk-list>li>:last-child{margin-bottom:0}.uk-list ul{margin:0;padding-left:30px;list-style:none}.uk-list>li:nth-child(n+2),.uk-list>li>ul{margin-top:10px}.uk-list-divider>li:nth-child(n+2){margin-top:10px;padding-top:10px;border-top:1px solid #c4c7ca}.uk-list-striped>li{padding:10px 10px}.uk-list-striped>li:nth-of-type(odd){border-top:1px solid #c4c7ca;border-bottom:1px solid #c4c7ca}.uk-list-striped>li:nth-of-type(odd){background:#f8f8f8}.uk-list-striped>li:nth-child(n+2){margin-top:0}.uk-list-bullet>li{position:relative;padding-left:calc(1.5em + 10px)}.uk-list-bullet>li::before{content:"";position:absolute;top:0;left:0;width:1.5em;height:1.5em;background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%226%22%20height%3D%226%22%20viewBox%3D%220%200%206%206%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Ccircle%20fill%3D%22%23666%22%20cx%3D%223%22%20cy%3D%223%22%20r%3D%223%22%20%2F%3E%0A%3C%2Fsvg%3E");background-repeat:no-repeat;background-position:50% 50%;float:left}.uk-list-large>li:nth-child(n+2),.uk-list-large>li>ul{margin-top:20px}.uk-list-large.uk-list-divider>li:nth-child(n+2){margin-top:20px;padding-top:20px}.uk-list-large.uk-list-striped>li{padding:20px 10px}.uk-list-large.uk-list-striped>li:nth-of-type(odd){border-top:1px solid #c4c7ca;border-bottom:1px solid #c4c7ca}.uk-list-large.uk-list-striped>li:nth-child(n+2){margin-top:0}.uk-list{margin:0}.uk-icon{margin:0;border:none;border-radius:0;overflow:visible;font:inherit;color:inherit;text-transform:none;padding:0;background-color:transparent;display:inline-block;fill:currentcolor;line-height:0}button.uk-icon:not(:disabled){cursor:pointer}.uk-icon::-moz-focus-inner{border:0;padding:0}.uk-icon [fill*='#']:not(.uk-preserve),.uk-icon [FILL*='#']:not(.uk-preserve){fill:currentcolor}.uk-icon [stroke*='#']:not(.uk-preserve),.uk-icon [STROKE*='#']:not(.uk-preserve){stroke:currentcolor}.uk-icon>*{transform:translate(0, 0)}.uk-icon-image{width:20px;height:20px;background-position:50% 50%;background-repeat:no-repeat;background-size:contain;vertical-align:middle}.uk-icon-link{color:#7a838a}.uk-icon-link:hover,.uk-icon-link:focus{color:#666;outline:none}.uk-icon-link:active,.uk-active>.uk-icon-link{color:#595959}.uk-icon-button{box-sizing:border-box;width:36px;height:36px;border-radius:500px;background:#f8f8f8;color:#7a838a;vertical-align:middle;display:inline-flex;justify-content:center;align-items:center;transition:0.1s ease-in-out;transition-property:color,background-color}.uk-icon-button:hover,.uk-icon-button:focus{background-color:#ebebeb;color:#666;outline:none}.uk-icon-button:active,.uk-active>.uk-icon-button{background-color:#dfdfdf;color:#666}.uk-input,.uk-select,.uk-textarea,.uk-radio,.uk-checkbox{box-sizing:border-box;margin:0;border-radius:0;font:inherit}.uk-input{overflow:visible}.uk-select{text-transform:none}.uk-select optgroup{font:inherit;font-weight:bold}.uk-textarea{overflow:auto}.uk-input[type="search"]::-webkit-search-cancel-button,.uk-input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}.uk-input[type="number"]::-webkit-inner-spin-button,.uk-input[type="number"]::-webkit-outer-spin-button{height:auto}.uk-input::-moz-placeholder,.uk-textarea::-moz-placeholder{opacity:1}.uk-radio:not(:disabled),.uk-checkbox:not(:disabled){cursor:pointer}.uk-fieldset{border:none;margin:0;padding:0}.uk-input,.uk-textarea{-webkit-appearance:none}.uk-input,.uk-select,.uk-textarea{max-width:100%;width:100%;border:0 none;padding:0 10px;background:#fff;color:#666;border:solid 1px #c4c7ca}.uk-input,.uk-select:not([multiple]):not([size]){height:40px;vertical-align:middle;display:inline-block}.uk-input:not(input),.uk-select:not(select){line-height:38px}.uk-select[multiple],.uk-select[size],.uk-textarea{padding-top:4px;padding-bottom:4px;vertical-align:top}.uk-input:focus,.uk-select:focus,.uk-textarea:focus{outline:none;background-color:#fff;color:#666;border-color:#0F1214}.uk-input:disabled,.uk-select:disabled,.uk-textarea:disabled{background-color:#f8f8f8;color:#7a838a;border-color:#c4c7ca}.uk-input:-ms-input-placeholder{color:#7a838a !important}.uk-input::placeholder{color:#7a838a}.uk-textarea:-ms-input-placeholder{color:#7a838a !important}.uk-textarea::placeholder{color:#7a838a}.uk-form-small{font-size:.875rem}.uk-form-small:not(textarea):not([multiple]):not([size]){height:30px;padding-left:8px;padding-right:8px}.uk-form-small:not(select):not(input):not(textarea){line-height:28px}.uk-form-large{font-size:1.125rem}.uk-form-large:not(textarea):not([multiple]):not([size]){height:55px;padding-left:12px;padding-right:12px}.uk-form-large:not(select):not(input):not(textarea){line-height:53px}.uk-form-danger,.uk-form-danger:focus{color:#f0506e;border-color:#f0506e}.uk-form-success,.uk-form-success:focus{color:#32d296;border-color:#32d296}.uk-form-blank{background:none;border-color:transparent}.uk-form-blank:focus{border-color:#c4c7ca;border-style:dashed}input.uk-form-width-xsmall{width:50px}select.uk-form-width-xsmall{width:75px}.uk-form-width-small{width:130px}.uk-form-width-medium{width:200px}.uk-form-width-large{width:500px}.uk-select:not([multiple]):not([size]){-webkit-appearance:none;-moz-appearance:none;padding-right:20px;background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2224%22%20height%3D%2216%22%20viewBox%3D%220%200%2024%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22%23666%22%20points%3D%2212%201%209%206%2015%206%22%20%2F%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22%23666%22%20points%3D%2212%2013%209%208%2015%208%22%20%2F%3E%0A%3C%2Fsvg%3E%0A");background-repeat:no-repeat;background-position:100% 50%}.uk-select:not([multiple]):not([size])::-ms-expand{display:none}.uk-select:not([multiple]):not([size]):disabled{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2224%22%20height%3D%2216%22%20viewBox%3D%220%200%2024%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22%237a838a%22%20points%3D%2212%201%209%206%2015%206%22%20%2F%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22%237a838a%22%20points%3D%2212%2013%209%208%2015%208%22%20%2F%3E%0A%3C%2Fsvg%3E%0A")}.uk-radio,.uk-checkbox{display:inline-block;height:16px;width:16px;overflow:hidden;margin-top:-4px;vertical-align:middle;-webkit-appearance:none;-moz-appearance:none;background-color:transparent;background-repeat:no-repeat;background-position:50% 50%;border:1px solid #a9aeb2;transition:0.2s ease-in-out;transition-property:background-color, border}.uk-radio{border-radius:50%}.uk-radio:focus,.uk-checkbox:focus{outline:none;border-color:#0F1214}.uk-radio:checked,.uk-checkbox:checked,.uk-checkbox:indeterminate{background-color:#0F1214;border-color:transparent}.uk-radio:checked:focus,.uk-checkbox:checked:focus,.uk-checkbox:indeterminate:focus{background-color:#000}.uk-radio:checked{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Ccircle%20fill%3D%22%23fff%22%20cx%3D%228%22%20cy%3D%228%22%20r%3D%222%22%20%2F%3E%0A%3C%2Fsvg%3E")}.uk-checkbox:checked{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2214%22%20height%3D%2211%22%20viewBox%3D%220%200%2014%2011%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22%23fff%22%20points%3D%2212%201%205%207.5%202%205%201%205.5%205%2010%2013%201.5%22%20%2F%3E%0A%3C%2Fsvg%3E%0A")}.uk-checkbox:indeterminate{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Crect%20fill%3D%22%23fff%22%20x%3D%223%22%20y%3D%228%22%20width%3D%2210%22%20height%3D%221%22%20%2F%3E%0A%3C%2Fsvg%3E")}.uk-radio:disabled,.uk-checkbox:disabled{background-color:#f8f8f8;border-color:#c4c7ca}.uk-radio:disabled:checked{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Ccircle%20fill%3D%22%237a838a%22%20cx%3D%228%22%20cy%3D%228%22%20r%3D%222%22%20%2F%3E%0A%3C%2Fsvg%3E")}.uk-checkbox:disabled:checked{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2214%22%20height%3D%2211%22%20viewBox%3D%220%200%2014%2011%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22%237a838a%22%20points%3D%2212%201%205%207.5%202%205%201%205.5%205%2010%2013%201.5%22%20%2F%3E%0A%3C%2Fsvg%3E%0A")}.uk-checkbox:disabled:indeterminate{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Crect%20fill%3D%22%237a838a%22%20x%3D%223%22%20y%3D%228%22%20width%3D%2210%22%20height%3D%221%22%20%2F%3E%0A%3C%2Fsvg%3E")}.uk-legend{width:100%;color:inherit;padding:0;font-size:1.375rem;line-height:1.4}.uk-form-custom{display:inline-block;position:relative;max-width:100%;vertical-align:middle}.uk-form-custom select,.uk-form-custom input[type="file"]{position:absolute;top:0;z-index:1;width:100%;height:100%;left:0;-webkit-appearance:none;opacity:0;cursor:pointer}.uk-form-custom input[type="file"]{font-size:500px;overflow:hidden}.uk-form-label{color:#333;font-size:.875rem}.uk-form-stacked .uk-form-label{display:block;margin-bottom:5px}@media (max-width: 959px){.uk-form-horizontal .uk-form-label{display:block;margin-bottom:5px}}@media (min-width: 960px){.uk-form-horizontal .uk-form-label{width:200px;margin-top:7px;float:left}.uk-form-horizontal .uk-form-controls{margin-left:215px}.uk-form-horizontal .uk-form-controls-text{padding-top:7px}}.uk-form-icon{position:absolute;top:0;bottom:0;left:0;width:40px;display:inline-flex;justify-content:center;align-items:center;color:#7a838a}.uk-form-icon:hover{color:#666}.uk-form-icon:not(a):not(button):not(input){pointer-events:none}.uk-form-icon:not(.uk-form-icon-flip)+.uk-input{padding-left:40px !important}.uk-form-icon-flip{right:0;left:auto}.uk-form-icon-flip+.uk-input{padding-right:40px !important}.uk-button{margin:0;border:none;border-radius:0;overflow:visible;font:inherit;color:inherit;text-transform:none;display:inline-block;box-sizing:border-box;padding:0 30px;vertical-align:middle;font-size:.875rem;line-height:38px;text-align:center;text-decoration:none;border-radius:5px}.uk-button:not(:disabled){cursor:pointer}.uk-button::-moz-focus-inner{border:0;padding:0}.uk-button:hover{text-decoration:none}.uk-button:focus{outline:none}.uk-button-default{background-color:transparent;color:#333;border:1px solid #c4c7ca}.uk-button-default:hover,.uk-button-default:focus{background-color:transparent;color:#333;border-color:#8e949a}.uk-button-default:active,.uk-button-default.uk-active{background-color:transparent;color:#333;border-color:#747b81}.uk-button-primary{background-color:#0F1214;color:#fff;border:1px solid transparent}.uk-button-primary:hover,.uk-button-primary:focus{background-color:#000;color:#fff}.uk-button-primary:active,.uk-button-primary.uk-active{background-color:#000;color:#fff}.uk-button-secondary{background-color:#222;color:#fff;border:1px solid transparent}.uk-button-secondary:hover,.uk-button-secondary:focus{background-color:#151515;color:#fff}.uk-button-secondary:active,.uk-button-secondary.uk-active{background-color:#090909;color:#fff}.uk-button-danger{background-color:#f0506e;color:#fff;border:1px solid transparent}.uk-button-danger:hover,.uk-button-danger:focus{background-color:#ee395b;color:#fff}.uk-button-danger:active,.uk-button-danger.uk-active{background-color:#ec2147;color:#fff}.uk-button-default:disabled,.uk-button-primary:disabled,.uk-button-secondary:disabled,.uk-button-danger:disabled{background-color:transparent;color:#7a838a;border-color:#c4c7ca}.uk-button-small{padding:0 15px;line-height:28px;font-size:.875rem}.uk-button-large{padding:0 40px;line-height:53px;font-size:.875rem}.uk-button-text{padding:0;line-height:1.5;background:none;color:#333;position:relative}.uk-button-text::before{content:"";position:absolute;bottom:0;left:0;right:100%;border-bottom:1px solid #333;transition:right 0.3s ease-out}.uk-button-text:hover,.uk-button-text:focus{color:#333}.uk-button-text:hover::before,.uk-button-text:focus::before{right:0}.uk-button-text:disabled{color:#7a838a}.uk-button-text:disabled::before{display:none}.uk-button-link{padding:0;line-height:1.5;background:none;color:#7a838a}.uk-button-link:hover,.uk-button-link:focus{color:#000;text-decoration:underline}.uk-button-link:disabled{color:#7a838a;text-decoration:none}.uk-button-group{display:inline-flex;vertical-align:middle;position:relative}.uk-button-group>.uk-button:nth-child(n+2),.uk-button-group>div:nth-child(n+2) .uk-button{margin-left:-1px}.uk-button-group .uk-button:hover,.uk-button-group .uk-button:focus,.uk-button-group .uk-button:active,.uk-button-group .uk-button.uk-active{position:relative;z-index:1}.uk-section{box-sizing:border-box;padding-top:40px;padding-bottom:40px}@media (min-width: 960px){.uk-section{padding-top:15px;padding-bottom:15px}}.uk-section::before,.uk-section::after{content:"";display:table}.uk-section::after{clear:both}.uk-section>:last-child{margin-bottom:0}.uk-section-xsmall{padding-top:20px;padding-bottom:20px}.uk-section-small{padding-top:40px;padding-bottom:40px}.uk-section-large{padding-top:70px;padding-bottom:70px}@media (min-width: 960px){.uk-section-large{padding-top:140px;padding-bottom:140px}}.uk-section-xlarge{padding-top:140px;padding-bottom:140px}@media (min-width: 960px){.uk-section-xlarge{padding-top:210px;padding-bottom:210px}}.uk-section-default{background:#fff}.uk-section-muted{background:#f8f8f8}.uk-section-primary{background:#0F1214}.uk-section-secondary{background:#222}.uk-container{box-sizing:content-box;max-width:1100px;margin-left:auto;margin-right:auto;padding-left:15px;padding-right:15px}@media (min-width: 640px){.uk-container{padding-left:30px;padding-right:30px}}@media (min-width: 960px){.uk-container{padding-left:40px;padding-right:40px}}.uk-container::before,.uk-container::after{content:"";display:table}.uk-container::after{clear:both}.uk-container>:last-child{margin-bottom:0}.uk-container .uk-container{padding-left:0;padding-right:0}.uk-container-small{max-width:800px}.uk-container-large{max-width:1600px}.uk-container-expand{max-width:none}.uk-grid{display:flex;flex-wrap:wrap;margin:0;padding:0;list-style:none}.uk-grid>*{margin:0}.uk-grid>*>:last-child{margin-bottom:0}.uk-grid{margin-left:-30px}.uk-grid>*{padding-left:30px}.uk-grid+.uk-grid,.uk-grid>.uk-grid-margin,*+.uk-grid-margin{margin-top:30px}@media (min-width: 1200px){.uk-grid{margin-left:-40px}.uk-grid>*{padding-left:40px}.uk-grid+.uk-grid,.uk-grid>.uk-grid-margin,*+.uk-grid-margin{margin-top:40px}}.uk-grid-small{margin-left:-15px}.uk-grid-small>*{padding-left:15px}.uk-grid+.uk-grid-small,.uk-grid-small>.uk-grid-margin,*+.uk-grid-margin-small{margin-top:15px}.uk-grid-medium{margin-left:-30px}.uk-grid-medium>*{padding-left:30px}.uk-grid+.uk-grid-medium,.uk-grid-medium>.uk-grid-margin,*+.uk-grid-margin-medium{margin-top:30px}.uk-grid-large{margin-left:-40px}.uk-grid-large>*{padding-left:40px}.uk-grid+.uk-grid-large,.uk-grid-large>.uk-grid-margin,*+.uk-grid-margin-large{margin-top:40px}@media (min-width: 1200px){.uk-grid-large{margin-left:-70px}.uk-grid-large>*{padding-left:70px}.uk-grid+.uk-grid-large,.uk-grid-large>.uk-grid-margin,*+.uk-grid-margin-large{margin-top:70px}}.uk-grid-collapse{margin-left:0}.uk-grid-collapse>*{padding-left:0}.uk-grid+.uk-grid-collapse,.uk-grid-collapse>.uk-grid-margin{margin-top:0}.uk-grid-divider>*{position:relative}.uk-grid-divider>:not(.uk-first-column)::before{content:"";position:absolute;top:0;bottom:0;border-left:1px solid #c4c7ca}.uk-grid-divider.uk-grid-stack>.uk-grid-margin::before{content:"";position:absolute;left:0;right:0;border-top:1px solid #c4c7ca}.uk-grid-divider{margin-left:-60px}.uk-grid-divider>*{padding-left:60px}.uk-grid-divider>:not(.uk-first-column)::before{left:30px}.uk-grid-divider.uk-grid-stack>.uk-grid-margin{margin-top:60px}.uk-grid-divider.uk-grid-stack>.uk-grid-margin::before{top:-30px;left:60px}@media (min-width: 1200px){.uk-grid-divider{margin-left:-80px}.uk-grid-divider>*{padding-left:80px}.uk-grid-divider>:not(.uk-first-column)::before{left:40px}.uk-grid-divider.uk-grid-stack>.uk-grid-margin{margin-top:80px}.uk-grid-divider.uk-grid-stack>.uk-grid-margin::before{top:-40px;left:80px}}.uk-grid-divider.uk-grid-small{margin-left:-30px}.uk-grid-divider.uk-grid-small>*{padding-left:30px}.uk-grid-divider.uk-grid-small>:not(.uk-first-column)::before{left:15px}.uk-grid-divider.uk-grid-small.uk-grid-stack>.uk-grid-margin{margin-top:30px}.uk-grid-divider.uk-grid-small.uk-grid-stack>.uk-grid-margin::before{top:-15px;left:30px}.uk-grid-divider.uk-grid-medium{margin-left:-60px}.uk-grid-divider.uk-grid-medium>*{padding-left:60px}.uk-grid-divider.uk-grid-medium>:not(.uk-first-column)::before{left:30px}.uk-grid-divider.uk-grid-medium.uk-grid-stack>.uk-grid-margin{margin-top:60px}.uk-grid-divider.uk-grid-medium.uk-grid-stack>.uk-grid-margin::before{top:-30px;left:60px}.uk-grid-divider.uk-grid-large{margin-left:-80px}.uk-grid-divider.uk-grid-large>*{padding-left:80px}.uk-grid-divider.uk-grid-large>:not(.uk-first-column)::before{left:40px}.uk-grid-divider.uk-grid-large.uk-grid-stack>.uk-grid-margin{margin-top:80px}.uk-grid-divider.uk-grid-large.uk-grid-stack>.uk-grid-margin::before{top:-40px;left:80px}@media (min-width: 1200px){.uk-grid-divider.uk-grid-large{margin-left:-140px}.uk-grid-divider.uk-grid-large>*{padding-left:140px}.uk-grid-divider.uk-grid-large>:not(.uk-first-column)::before{left:70px}.uk-grid-divider.uk-grid-large.uk-grid-stack>.uk-grid-margin{margin-top:140px}.uk-grid-divider.uk-grid-large.uk-grid-stack>.uk-grid-margin::before{top:-70px;left:140px}}.uk-grid-match>*,.uk-grid-item-match{display:flex;flex-wrap:wrap}.uk-grid-match>*>:not([class*='uk-width']),.uk-grid-item-match>:not([class*='uk-width']){box-sizing:border-box;width:100%;flex:auto}.uk-tile{position:relative;box-sizing:border-box;padding-left:15px;padding-right:15px;padding-top:40px;padding-bottom:40px}@media (min-width: 640px){.uk-tile{padding-left:30px;padding-right:30px}}@media (min-width: 960px){.uk-tile{padding-left:40px;padding-right:40px;padding-top:70px;padding-bottom:70px}}.uk-tile::before,.uk-tile::after{content:"";display:table}.uk-tile::after{clear:both}.uk-tile>:last-child{margin-bottom:0}.uk-tile-xsmall{padding-top:20px;padding-bottom:20px}.uk-tile-small{padding-top:40px;padding-bottom:40px}.uk-tile-large{padding-top:70px;padding-bottom:70px}@media (min-width: 960px){.uk-tile-large{padding-top:140px;padding-bottom:140px}}.uk-tile-xlarge{padding-top:140px;padding-bottom:140px}@media (min-width: 960px){.uk-tile-xlarge{padding-top:210px;padding-bottom:210px}}.uk-tile-default{background:#fff}.uk-tile-muted{background:#f8f8f8}.uk-tile-primary{background:#0F1214}.uk-tile-secondary{background:#222}.uk-card{position:relative;box-sizing:border-box;border:solid 1px #dfe1e2}.uk-card:hover{border-color:#a9aeb2}.uk-card-body{padding:30px 30px}.uk-card-body>p{font-size:.875rem}.uk-card-body>span{color:#0F1214}.uk-card-header{padding:15px 30px}.uk-card-footer{padding:15px 30px}@media (min-width: 1200px){.uk-card-body{padding:40px 40px}.uk-card-header{padding:20px 40px}.uk-card-footer{padding:20px 40px}}.uk-card-body::before,.uk-card-body::after,.uk-card-header::before,.uk-card-header::after,.uk-card-footer::before,.uk-card-footer::after{content:"";display:table}.uk-card-body::after,.uk-card-header::after,.uk-card-footer::after{clear:both}.uk-card-body>:last-child,.uk-card-header>:last-child,.uk-card-footer>:last-child{margin-bottom:0}.uk-card-title{font-size:1.375rem;line-height:1.4;font-size:1.125rem}.uk-card-badge{position:absolute;top:30px;right:30px;z-index:1}.uk-card-badge:first-child+*{margin-top:0}.uk-card-hover:not(.uk-card-default):not(.uk-card-primary):not(.uk-card-secondary):hover{background:#fff;box-shadow:0 14px 25px rgba(0,0,0,0.16)}.uk-card-default{background:#fff;color:#666;box-shadow:0 5px 15px rgba(0,0,0,0.08)}.uk-card-default .uk-card-title{color:#333}.uk-card-default.uk-card-hover:hover{background-color:#fff;box-shadow:0 14px 25px rgba(0,0,0,0.16)}.uk-card-default .uk-card-header{border-bottom:1px solid #c4c7ca}.uk-card-default .uk-card-footer{border-top:1px solid #c4c7ca}.uk-card-primary{background:#0F1214;color:#fff;box-shadow:0 5px 15px rgba(0,0,0,0.08)}.uk-card-primary .uk-card-title{color:#fff}.uk-card-primary.uk-card-hover:hover{background-color:#0F1214;box-shadow:0 14px 25px rgba(0,0,0,0.16)}.uk-card-secondary{background:#222;color:#fff;box-shadow:0 5px 15px rgba(0,0,0,0.08)}.uk-card-secondary .uk-card-title{color:#fff}.uk-card-secondary.uk-card-hover:hover{background-color:#222;box-shadow:0 14px 25px rgba(0,0,0,0.16)}.uk-card-small.uk-card-body,.uk-card-small .uk-card-body{padding:25px 25px}.uk-card-small .uk-card-header{padding:13px 20px}.uk-card-small .uk-card-footer{padding:13px 20px}@media (min-width: 1200px){.uk-card-large.uk-card-body,.uk-card-large .uk-card-body{padding:70px 70px}.uk-card-large .uk-card-header{padding:35px 70px}.uk-card-large .uk-card-footer{padding:35px 70px}}.uk-position-cover{z-index:1}.card-category h3:nth-child(2n){margin-top:0 !important}.card-post .uk-card-header{padding-top:40px;padding-bottom:0}.card-post .uk-card-body{padding-top:20px;padding-bottom:20px}.card-post .uk-card-footer{padding-bottom:32px;padding-top:0}.uk-close{color:#7a838a;transition:0.1s ease-in-out;transition-property:color, opacity}.uk-close:hover,.uk-close:focus{color:#666;outline:none}.uk-totop{padding:5px;color:#7a838a;transition:color 0.1s ease-in-out}.uk-totop:hover,.uk-totop:focus{color:#666;outline:none}.uk-totop:active{color:#333}.uk-label{display:inline-block;padding:0 10px;background:#0F1214;line-height:1.5;font-size:.875rem;color:#fff;vertical-align:middle;white-space:nowrap;border-radius:2px;text-transform:uppercase}.uk-label-success{background-color:#32d296;color:#fff}.uk-label-warning{background-color:#faa05a;color:#fff}.uk-label-danger{background-color:#f0506e;color:#fff}.uk-overlay{padding:30px 30px}.uk-overlay>:last-child{margin-bottom:0}.uk-overlay-default{background:rgba(255,255,255,0.8)}.uk-overlay-primary{background:rgba(34,34,34,0.8)}.uk-article figure,.uk-article .uk-slideshow{margin-top:44px;margin-bottom:60px}.uk-article figure img+div .uk-overlay-icon{color:rgba(255,255,255,0)}.uk-article figure img:hover+div .uk-overlay-icon{color:#fff}.uk-article figure figcaption{margin-left:0}.uk-article figure figcaption span{padding-right:20px;margin-bottom:-43px;margin-top:20px;border-right:solid 2px #7a838a;font-style:italic;font-size:0.8rem;line-height:1.8}.uk-article blockquote{border-left:solid 2px #7a838a;padding-left:20px;line-height:1.7;margin-top:40px;margin-bottom:40px}.uk-article .highlight,.uk-article .highlighter-rouge{margin-top:40px;margin-bottom:40px}.uk-article::before,.uk-article::after{content:"";display:table}.uk-article::after{clear:both}.uk-article>:last-child{margin-bottom:0}.uk-article+.uk-article{margin-top:70px}.uk-article-title{font-size:1.875rem;line-height:1.4;margin-bottom:20px}.uk-article-meta{font-size:.8125rem;line-height:1.3;color:#7a838a}.uk-article-meta a{color:#7a838a}.uk-article-meta a:hover{color:#0F1214}.uk-article-meta .avatar{margin-right:10px;float:left}.article-content{line-height:1.8}.avatar{border-radius:50%}.paginate-post .uk-text-small{line-height:1.75}.uk-search{display:inline-block;position:relative;max-width:100%;margin:0}.uk-search-input::-webkit-search-cancel-button,.uk-search-input::-webkit-search-decoration{-webkit-appearance:none}.uk-search-input::-moz-placeholder{opacity:1}.uk-search-input{box-sizing:border-box;margin:0;border-radius:0;font:inherit;overflow:visible;-webkit-appearance:none;vertical-align:middle;width:100%;border:none;color:#666}.uk-search-input:focus{outline:none}.uk-search-input:-ms-input-placeholder{color:#7a838a !important}.uk-search-input::placeholder{color:#7a838a}.uk-search-icon:focus{outline:none}.uk-search .uk-search-icon{position:absolute;top:0;bottom:0;left:0;display:inline-flex;justify-content:center;align-items:center;color:#7a838a}.uk-search .uk-search-icon:hover{color:#7a838a}.uk-search .uk-search-icon:not(a):not(button):not(input){pointer-events:none}.uk-search .uk-search-icon-flip{right:0;left:auto}.uk-search-default{width:180px}.uk-search-default .uk-search-input{height:40px;padding-left:6px;padding-right:6px;background:transparent;border:1px solid #9ca1a6}.uk-search-default .uk-search-input:focus{background-color:transparent}.uk-search-default .uk-search-icon{width:40px}.uk-search-default .uk-search-icon:not(.uk-search-icon-flip)+.uk-search-input{padding-left:40px}.uk-search-default .uk-search-icon-flip+.uk-search-input{padding-right:40px}.uk-search-navbar{width:400px}.uk-search-navbar .uk-search-input{height:40px;background:transparent;font-size:1.375rem}.uk-search-navbar .uk-search-icon{width:40px}.uk-search-navbar .uk-search-icon:not(.uk-search-icon-flip)+.uk-search-input{padding-left:40px}.uk-search-navbar .uk-search-icon-flip+.uk-search-input{padding-right:40px}.uk-search-large{width:500px}.uk-search-large .uk-search-input{height:80px;background:transparent;font-size:1.875rem}.uk-search-large .uk-search-icon{width:80px}.uk-search-large .uk-search-icon:not(.uk-search-icon-flip)+.uk-search-input{padding-left:80px}.uk-search-large .uk-search-icon-flip+.uk-search-input{padding-right:80px}.uk-search-toggle{color:#7a838a}.uk-search-toggle:hover,.uk-search-toggle:focus{color:#666}.uk-nav,.uk-nav ul{margin:0;padding:0;list-style:none}.uk-nav li>a{display:block;text-decoration:none}.uk-nav li>a:focus{outline:none}.uk-nav>li>a{padding:5px 0}ul.uk-nav-sub{padding:5px 0 5px 15px}.uk-nav-sub ul{padding-left:15px}.uk-nav-sub a{padding:2px 0}.uk-nav-parent-icon>.uk-parent>a::after{content:"";width:1.5em;height:1.5em;float:right;background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2214%22%20height%3D%2214%22%20viewBox%3D%220%200%2014%2014%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolyline%20fill%3D%22none%22%20stroke%3D%22%23666%22%20stroke-width%3D%221.1%22%20points%3D%2210%201%204%207%2010%2013%22%20%2F%3E%0A%3C%2Fsvg%3E");background-repeat:no-repeat;background-position:50% 50%}.uk-nav-parent-icon>.uk-parent.uk-open>a::after{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2214%22%20height%3D%2214%22%20viewBox%3D%220%200%2014%2014%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolyline%20fill%3D%22none%22%20stroke%3D%22%23666%22%20stroke-width%3D%221.1%22%20points%3D%221%204%207%2010%2013%204%22%20%2F%3E%0A%3C%2Fsvg%3E")}.uk-nav-header{padding:5px 0;text-transform:uppercase;font-size:.875rem}.uk-nav-header:not(:first-child){margin-top:20px}.uk-nav-divider{margin:5px 0}.uk-nav-default{font-size:.875rem}.uk-nav-default>li>a{color:#7a838a}.uk-nav-default>li>a:hover,.uk-nav-default>li>a:focus{color:#666}.uk-nav-default>li.uk-active>a{color:#333}.uk-nav-default .uk-nav-header{color:#333}.uk-nav-default .uk-nav-divider{border-top:1px solid #c4c7ca}.uk-nav-default .uk-nav-sub a{color:#7a838a}.uk-nav-default .uk-nav-sub a:hover,.uk-nav-default .uk-nav-sub a:focus{color:#666}.uk-nav-primary>li>a{font-size:1.375rem;line-height:1.5;color:#7a838a}.uk-nav-primary>li>a:hover,.uk-nav-primary>li>a:focus{color:#666}.uk-nav-primary>li.uk-active>a{color:#333}.uk-nav-primary .uk-nav-header{color:#333}.uk-nav-primary .uk-nav-divider{border-top:1px solid #c4c7ca}.uk-nav-primary .uk-nav-sub a{color:#7a838a}.uk-nav-primary .uk-nav-sub a:hover,.uk-nav-primary .uk-nav-sub a:focus{color:#666}.uk-nav-center{text-align:center}.uk-nav-center .uk-nav-sub,.uk-nav-center .uk-nav-sub ul{padding-left:0}.uk-nav-center.uk-nav-parent-icon>.uk-parent>a::after{position:absolute}.uk-navbar{display:flex;position:relative;font-weight:500}.uk-navbar .uk-drop{width:360px}.uk-navbar .uk-search-navbar .uk-search-input{height:50px;font-size:1.0625rem;padding-left:1.1875rem;background:#fff}.uk-navbar-container:not(.uk-navbar-transparent){background:#fff}.uk-navbar-container>::before,.uk-navbar-container>::after{display:none !important}.uk-navbar-left,.uk-navbar-right,.uk-navbar-center,.uk-navbar-center-left>*,.uk-navbar-center-right>*{display:flex;align-items:center}.uk-navbar-right{margin-left:auto}.uk-navbar-center:only-child{margin-left:auto;margin-right:auto;position:relative}.uk-navbar-center:not(:only-child){position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);z-index:990}.uk-navbar-center:not(:only-child) .uk-navbar-nav>li>a,.uk-navbar-center:not(:only-child) .uk-navbar-item,.uk-navbar-center:not(:only-child) .uk-navbar-toggle{white-space:nowrap}.uk-navbar-center-left,.uk-navbar-center-right{position:absolute;top:0}.uk-navbar-center-left{right:100%}.uk-navbar-center-right{left:100%}[class*='uk-navbar-center-'] .uk-navbar-nav>li>a,[class*='uk-navbar-center-'] .uk-navbar-item,[class*='uk-navbar-center-'] .uk-navbar-toggle{white-space:nowrap}.uk-navbar-nav{display:flex;margin:0;padding:0;list-style:none}.uk-navbar-left,.uk-navbar-right,.uk-navbar-center:only-child{flex-wrap:wrap}.uk-navbar-nav>li>a,.uk-navbar-item,.uk-navbar-toggle{display:flex;justify-content:center;align-items:center;box-sizing:border-box;height:80px;padding:0 15px;font-size:.875rem;font-family:system-ui;text-decoration:none}.uk-navbar-nav>li>a{color:#7a838a;text-transform:none;transition:0.1s ease-in-out;transition-property:color, background-color}.uk-navbar-nav>li:hover>a,.uk-navbar-nav>li>a:focus,.uk-navbar-nav>li>a.uk-open{color:#0F1214;outline:none}.uk-navbar-nav>li>a:active{color:#333}.uk-navbar-nav>li.uk-active>a{color:#0F1214}.uk-navbar-item{color:#666}.uk-navbar-toggle{color:#7a838a}.uk-navbar-toggle:hover,.uk-navbar-toggle:focus,.uk-navbar-toggle.uk-open{color:#0F1214;outline:none;text-decoration:none}.uk-navbar-subtitle{font-size:.875rem}.uk-navbar-dropdown{display:none;position:absolute;z-index:1020;box-sizing:border-box;width:200px;padding:25px;background:#fff;color:#666;box-shadow:0 5px 12px rgba(0,0,0,0.15)}.uk-navbar-dropdown.uk-open{display:block}[class*='uk-navbar-dropdown-top']{margin-top:-15px}[class*='uk-navbar-dropdown-bottom']{margin-top:15px}[class*='uk-navbar-dropdown-left']{margin-left:-15px}[class*='uk-navbar-dropdown-right']{margin-left:15px}.uk-navbar-dropdown-grid{margin-left:-50px}.uk-navbar-dropdown-grid>*{padding-left:50px}.uk-navbar-dropdown-grid>.uk-grid-margin{margin-top:50px}.uk-navbar-dropdown-stack .uk-navbar-dropdown-grid>*{width:100% !important}.uk-navbar-dropdown-width-2:not(.uk-navbar-dropdown-stack){width:400px}.uk-navbar-dropdown-width-3:not(.uk-navbar-dropdown-stack){width:600px}.uk-navbar-dropdown-width-4:not(.uk-navbar-dropdown-stack){width:800px}.uk-navbar-dropdown-width-5:not(.uk-navbar-dropdown-stack){width:1000px}.uk-navbar-dropdown-dropbar{margin-top:0;margin-bottom:0;box-shadow:none}.uk-navbar-dropdown-nav{font-size:.875rem}.uk-navbar-dropdown-nav>li>a{color:#7a838a}.uk-navbar-dropdown-nav>li>a:hover,.uk-navbar-dropdown-nav>li>a:focus{color:#666}.uk-navbar-dropdown-nav>li.uk-active>a{color:#333}.uk-navbar-dropdown-nav .uk-nav-header{color:#333}.uk-navbar-dropdown-nav .uk-nav-divider{border-top:1px solid #c4c7ca}.uk-navbar-dropdown-nav .uk-nav-sub a{color:#7a838a}.uk-navbar-dropdown-nav .uk-nav-sub a:hover,.uk-navbar-dropdown-nav .uk-nav-sub a:focus{color:#666}.uk-navbar-dropbar{background:#fff}.uk-navbar-dropbar-slide{position:absolute;z-index:980;left:0;right:0;box-shadow:0 5px 7px rgba(0,0,0,0.05)}.uk-navbar-container>.uk-container .uk-navbar-left{margin-left:-15px;margin-right:-15px}.uk-navbar-container>.uk-container .uk-navbar-right{margin-right:-15px}.uk-navbar-dropdown-grid>*{position:relative}.uk-navbar-dropdown-grid>:not(.uk-first-column)::before{content:"";position:absolute;top:0;bottom:0;left:25px;border-left:1px solid #c4c7ca}.uk-navbar-dropdown-grid.uk-grid-stack>.uk-grid-margin::before{content:"";position:absolute;top:-25px;left:50px;right:0;border-top:1px solid #c4c7ca}.uk-subnav{display:flex;flex-wrap:wrap;margin-left:-20px;padding:0;list-style:none}.uk-subnav>*{flex:none;padding-left:20px;position:relative}.uk-subnav>*>:first-child{display:block;color:#7a838a;font-size:.875rem;text-transform:none;transition:0.1s ease-in-out;transition-property:color, background-color}.uk-subnav>*>a:hover,.uk-subnav>*>a:focus{color:#0F1214;text-decoration:none;outline:none}.uk-subnav>.uk-active>a{color:#333}.uk-subnav-divider>*{display:flex;align-items:center}.uk-subnav-divider>:nth-child(n+2):not(.uk-first-column)::before{content:"";height:1.5em;margin-left:0px;margin-right:20px;border-left:1px solid #c4c7ca}.uk-subnav-pill>*>:first-child{padding:5px 10px;background:transparent;color:#7a838a}.uk-subnav-pill>*>a:hover,.uk-subnav-pill>*>a:focus{background-color:#f8f8f8;color:#666}.uk-subnav-pill>*>a:active{background-color:#f8f8f8;color:#666}.uk-subnav-pill>.uk-active>a{background-color:#0F1214;color:#fff}.uk-subnav>.uk-disabled>a{color:#7a838a}.uk-pagination{display:flex;flex-wrap:wrap;margin-left:-20px;padding:0;list-style:none}.uk-pagination>*{flex:none;padding-left:20px;position:relative}.uk-pagination>*>*{display:block;color:#0F1214;transition:color 0.1s ease-in-out}.uk-pagination>*>:hover,.uk-pagination>*>:focus{color:#0F1214;text-decoration:none}.uk-pagination>.uk-active>*{color:#666}.uk-pagination>.uk-disabled>*{color:#7a838a}.uk-drop{display:none;position:absolute;z-index:1020;box-sizing:border-box;width:300px}.uk-drop.uk-open{display:block}[class*='uk-drop-top']{margin-top:-20px}[class*='uk-drop-bottom']{margin-top:20px}[class*='uk-drop-left']{margin-left:-20px}[class*='uk-drop-right']{margin-left:20px}.uk-drop-stack .uk-drop-grid>*{width:100% !important}.uk-dropdown{display:none;position:absolute;z-index:1020;box-sizing:border-box;min-width:200px;padding:25px;background:#fff;color:#666;box-shadow:0 5px 12px rgba(0,0,0,0.15)}.uk-dropdown.uk-open{display:block}.uk-dropdown-nav{white-space:nowrap;font-size:.875rem}.uk-dropdown-nav>li>a{color:#7a838a}.uk-dropdown-nav>li>a:hover,.uk-dropdown-nav>li>a:focus,.uk-dropdown-nav>li.uk-active>a{color:#666}.uk-dropdown-nav .uk-nav-header{color:#333}.uk-dropdown-nav .uk-nav-divider{border-top:1px solid #c4c7ca}.uk-dropdown-nav .uk-nav-sub a{color:#7a838a}.uk-dropdown-nav .uk-nav-sub a:hover,.uk-dropdown-nav .uk-nav-sub a:focus{color:#666}[class*='uk-dropdown-top']{margin-top:-10px}[class*='uk-dropdown-bottom']{margin-top:10px}[class*='uk-dropdown-left']{margin-left:-10px}[class*='uk-dropdown-right']{margin-left:10px}.uk-dropdown-stack .uk-dropdown-grid>*{width:100% !important}.uk-lightbox{display:none;position:fixed;top:0;right:0;bottom:0;left:0;z-index:1010;background:#000;opacity:0;transition:opacity 0.15s linear}.uk-lightbox.uk-open{display:block;opacity:1}.uk-lightbox-page{overflow:hidden}.uk-lightbox-items>*{position:absolute;top:0;right:0;bottom:0;left:0;display:none;justify-content:center;align-items:center;color:rgba(255,255,255,0.7);will-change:transform, opacity}.uk-lightbox-items>*>*{max-width:100vw;max-height:100vh}.uk-lightbox-items>*>:not(iframe){width:auto;height:auto}.uk-lightbox-items>.uk-active{display:flex}.uk-lightbox-toolbar{padding:10px 10px;background:rgba(0,0,0,0.3);color:rgba(255,255,255,0.7)}.uk-lightbox-toolbar *{color:rgba(255,255,255,0.7)}.uk-lightbox-toolbar-icon{padding:5px;color:rgba(255,255,255,0.7)}.uk-lightbox-toolbar-icon:hover{color:#fff}.uk-lightbox-button{box-sizing:border-box;width:50px;height:50px;background:rgba(0,0,0,0.3);color:rgba(255,255,255,0.7);display:inline-flex;justify-content:center;align-items:center}.uk-lightbox-button:hover{color:#fff}.uk-lightbox-iframe{width:80%;height:80%}.uk-slideshow{-webkit-tap-highlight-color:transparent}.uk-slideshow-items{position:relative;z-index:0;margin:0;padding:0;list-style:none;overflow:hidden;-webkit-touch-callout:none}.uk-slideshow-items>*{position:absolute;top:0;left:0;right:0;bottom:0;overflow:hidden;will-change:transform, opacity;touch-action:pan-y}.uk-slideshow-items>:not(.uk-active){display:none}.uk-sticky-fixed{z-index:980;box-sizing:border-box;margin:0 !important;-webkit-backface-visibility:hidden;backface-visibility:hidden}.uk-sticky[class*='uk-animation-']{animation-duration:.2s}.uk-sticky.uk-animation-reverse{animation-duration:.2s}.uk-offcanvas{display:none;position:fixed;top:0;bottom:0;left:0;z-index:1000}.uk-offcanvas-flip .uk-offcanvas{right:0;left:auto}.uk-offcanvas-bar{position:absolute;top:0;bottom:0;left:0;box-sizing:border-box;width:270px;padding:20px 20px;background:#fff;overflow-y:auto;-webkit-overflow-scrolling:touch;transform:translateX(-100%);font-weight:500}@media (min-width: 960px){.uk-offcanvas-bar{width:350px;padding:40px 40px}}.uk-offcanvas-flip .uk-offcanvas-bar{left:auto;right:0;transform:translateX(100%)}.uk-open>.uk-offcanvas-bar{transform:translateX(0)}.uk-offcanvas-bar-animation{transition:transform 0.3s ease-out}.uk-offcanvas-reveal{position:absolute;top:0;bottom:0;left:0;width:0;overflow:hidden;transition:width 0.3s ease-out}.uk-offcanvas-reveal .uk-offcanvas-bar{transform:translateX(0)}.uk-open>.uk-offcanvas-reveal{width:270px}@media (min-width: 960px){.uk-open>.uk-offcanvas-reveal{width:350px}}.uk-offcanvas-flip .uk-offcanvas-reveal{right:0;left:auto}.uk-offcanvas-close{position:absolute;z-index:1000;top:20px;right:20px;padding:5px}.uk-offcanvas-overlay{width:100vw;touch-action:none}.uk-offcanvas-overlay::before{content:"";position:absolute;top:0;bottom:0;left:0;right:0;background:rgba(0,0,0,0.1);opacity:0;transition:opacity 0.15s linear}.uk-offcanvas-overlay.uk-open::before{opacity:1}.uk-offcanvas-page,.uk-offcanvas-container{overflow-x:hidden}.uk-offcanvas-container-overlay{overflow:hidden}.uk-offcanvas-container .uk-offcanvas-content{position:relative;left:0;transition:left 0.3s ease-out;-webkit-overflow-scrolling:touch}.uk-offcanvas-overlay .uk-offcanvas-content{overflow-y:hidden}:not(.uk-offcanvas-flip)>.uk-offcanvas-content-animation{left:270px}.uk-offcanvas-flip>.uk-offcanvas-content-animation{left:-270px}@media (min-width: 960px){:not(.uk-offcanvas-flip)>.uk-offcanvas-content-animation{left:350px}.uk-offcanvas-flip>.uk-offcanvas-content-animation{left:-350px}}[class*='uk-animation-']{animation-duration:.5s;animation-timing-function:ease-out;animation-fill-mode:both}.uk-animation-reverse{animation-direction:reverse;animation-timing-function:ease-in}.uk-animation-fade{animation-name:uk-fade;animation-duration:.8s;animation-timing-function:linear}.uk-animation-scale-up{animation-name:uk-fade-scale-02}.uk-animation-scale-down{animation-name:uk-fade-scale-18}.uk-animation-slide-top{animation-name:uk-fade-top}.uk-animation-slide-bottom{animation-name:uk-fade-bottom}.uk-animation-slide-left{animation-name:uk-fade-left}.uk-animation-slide-right{animation-name:uk-fade-right}.uk-animation-slide-top-small{animation-name:uk-fade-top-small}.uk-animation-slide-bottom-small{animation-name:uk-fade-bottom-small}.uk-animation-slide-left-small{animation-name:uk-fade-left-small}.uk-animation-slide-right-small{animation-name:uk-fade-right-small}.uk-animation-slide-top-medium{animation-name:uk-fade-top-medium}.uk-animation-slide-bottom-medium{animation-name:uk-fade-bottom-medium}.uk-animation-slide-left-medium{animation-name:uk-fade-left-medium}.uk-animation-slide-right-medium{animation-name:uk-fade-right-medium}.uk-animation-kenburns{animation-name:uk-scale-kenburns;animation-duration:15s}.uk-animation-shake{animation-name:uk-shake}.uk-animation-fast{animation-duration:.1s}.uk-animation-toggle:not(:hover):not(.uk-hover) [class*='uk-animation-']{animation-name:none}@keyframes uk-fade{0%{opacity:0}100%{opacity:1}}@keyframes uk-fade-top{0%{opacity:0;transform:translateY(-100%)}100%{opacity:1;transform:translateY(0)}}@keyframes uk-fade-bottom{0%{opacity:0;transform:translateY(100%)}100%{opacity:1;transform:translateY(0)}}@keyframes uk-fade-left{0%{opacity:0;transform:translateX(-100%)}100%{opacity:1;transform:translateX(0)}}@keyframes uk-fade-right{0%{opacity:0;transform:translateX(100%)}100%{opacity:1;transform:translateX(0)}}@keyframes uk-fade-top-small{0%{opacity:0;transform:translateY(-10px)}100%{opacity:1;transform:translateY(0)}}@keyframes uk-fade-bottom-small{0%{opacity:0;transform:translateY(10px)}100%{opacity:1;transform:translateY(0)}}@keyframes uk-fade-left-small{0%{opacity:0;transform:translateX(-10px)}100%{opacity:1;transform:translateX(0)}}@keyframes uk-fade-right-small{0%{opacity:0;transform:translateX(10px)}100%{opacity:1;transform:translateX(0)}}@keyframes uk-fade-top-medium{0%{opacity:0;transform:translateY(-50px)}100%{opacity:1;transform:translateY(0)}}@keyframes uk-fade-bottom-medium{0%{opacity:0;transform:translateY(50px)}100%{opacity:1;transform:translateY(0)}}@keyframes uk-fade-left-medium{0%{opacity:0;transform:translateX(-50px)}100%{opacity:1;transform:translateX(0)}}@keyframes uk-fade-right-medium{0%{opacity:0;transform:translateX(50px)}100%{opacity:1;transform:translateX(0)}}@keyframes uk-fade-scale-02{0%{opacity:0;transform:scale(0.2)}100%{opacity:1;transform:scale(1)}}@keyframes uk-fade-scale-18{0%{opacity:0;transform:scale(1.8)}100%{opacity:1;transform:scale(1)}}@keyframes uk-scale-kenburns{0%{transform:scale(1)}100%{transform:scale(1.2)}}@keyframes uk-shake{0%, 100%{transform:translateX(0)}10%{transform:translateX(-9px)}20%{transform:translateX(8px)}30%{transform:translateX(-7px)}40%{transform:translateX(6px)}50%{transform:translateX(-5px)}60%{transform:translateX(4px)}70%{transform:translateX(-3px)}80%{transform:translateX(2px)}90%{transform:translateX(-1px)}}[class*='uk-child-width']>*{box-sizing:border-box;width:100%}.uk-child-width-1-2>*{width:50%}.uk-child-width-1-3>*{width:calc(100% * 1 / 3.001)}.uk-child-width-1-4>*{width:25%}.uk-child-width-1-5>*{width:20%}.uk-child-width-1-6>*{width:calc(100% * 1 / 6.001)}.uk-child-width-auto>*{width:auto}.uk-child-width-expand>*{width:1px}.uk-child-width-expand>:not([class*='uk-width']){flex:1;min-width:0;flex-basis:1px}@media (min-width: 640px){.uk-child-width-1-1\@s>*{width:100%}.uk-child-width-1-2\@s>*{width:50%}.uk-child-width-1-3\@s>*{width:calc(100% * 1 / 3.001)}.uk-child-width-1-4\@s>*{width:25%}.uk-child-width-1-5\@s>*{width:20%}.uk-child-width-1-6\@s>*{width:calc(100% * 1 / 6.001)}.uk-child-width-auto\@s>*{width:auto}.uk-child-width-expand\@s>*{width:1px}.uk-child-width-expand\@s>:not([class*='uk-width']){flex:1;min-width:0;flex-basis:1px}}@media (min-width: 960px){.uk-child-width-1-1\@m>*{width:100%}.uk-child-width-1-2\@m>*{width:50%}.uk-child-width-1-3\@m>*{width:calc(100% * 1 / 3.001)}.uk-child-width-1-4\@m>*{width:25%}.uk-child-width-1-5\@m>*{width:20%}.uk-child-width-1-6\@m>*{width:calc(100% * 1 / 6.001)}.uk-child-width-auto\@m>*{width:auto}.uk-child-width-expand\@m>*{width:1px}.uk-child-width-expand\@m>:not([class*='uk-width']){flex:1;min-width:0;flex-basis:1px}}@media (min-width: 1200px){.uk-child-width-1-1\@l>*{width:100%}.uk-child-width-1-2\@l>*{width:50%}.uk-child-width-1-3\@l>*{width:calc(100% * 1 / 3.001)}.uk-child-width-1-4\@l>*{width:25%}.uk-child-width-1-5\@l>*{width:20%}.uk-child-width-1-6\@l>*{width:calc(100% * 1 / 6.001)}.uk-child-width-auto\@l>*{width:auto}.uk-child-width-expand\@l>*{width:1px}.uk-child-width-expand\@l>:not([class*='uk-width']){flex:1;min-width:0;flex-basis:1px}}@media (min-width: 1600px){.uk-child-width-1-1\@xl>*{width:100%}.uk-child-width-1-2\@xl>*{width:50%}.uk-child-width-1-3\@xl>*{width:calc(100% * 1 / 3.001)}.uk-child-width-1-4\@xl>*{width:25%}.uk-child-width-1-5\@xl>*{width:20%}.uk-child-width-1-6\@xl>*{width:calc(100% * 1 / 6.001)}.uk-child-width-auto\@xl>*{width:auto}.uk-child-width-expand\@xl>*{width:1px}.uk-child-width-expand\@xl>:not([class*='uk-width']){flex:1;min-width:0;flex-basis:1px}}[class*='uk-width']{box-sizing:border-box;width:100%;max-width:100%}.uk-width-1-2{width:50%}.uk-width-1-3{width:calc(100% * 1 / 3.001)}.uk-width-2-3{width:calc(100% * 2 / 3.001)}.uk-width-1-4{width:25%}.uk-width-3-4{width:75%}.uk-width-1-5{width:20%}.uk-width-2-5{width:40%}.uk-width-3-5{width:60%}.uk-width-4-5{width:80%}.uk-width-1-6{width:calc(100% * 1 / 6.001)}.uk-width-5-6{width:calc(100% * 5 / 6.001)}.uk-width-small{width:150px}.uk-width-medium{width:300px}.uk-width-large{width:450px}.uk-width-xlarge{width:600px}.uk-width-xxlarge{width:750px}.uk-width-auto{width:auto}.uk-width-expand{width:1px;flex:1;min-width:0;flex-basis:1px}@media (min-width: 640px){.uk-width-1-1\@s{width:100%}.uk-width-1-2\@s{width:50%}.uk-width-1-3\@s{width:calc(100% * 1 / 3.001)}.uk-width-2-3\@s{width:calc(100% * 2 / 3.001)}.uk-width-1-4\@s{width:25%}.uk-width-3-4\@s{width:75%}.uk-width-1-5\@s{width:20%}.uk-width-2-5\@s{width:40%}.uk-width-3-5\@s{width:60%}.uk-width-4-5\@s{width:80%}.uk-width-1-6\@s{width:calc(100% * 1 / 6.001)}.uk-width-5-6\@s{width:calc(100% * 5 / 6.001)}.uk-width-small\@s{width:150px}.uk-width-medium\@s{width:300px}.uk-width-large\@s{width:450px}.uk-width-xlarge\@s{width:600px}.uk-width-xxlarge\@s{width:750px}.uk-width-auto\@s{width:auto}.uk-width-expand\@s{width:1px;flex:1;min-width:0;flex-basis:1px}}@media (min-width: 960px){.uk-width-1-1\@m{width:100%}.uk-width-1-2\@m{width:50%}.uk-width-1-3\@m{width:calc(100% * 1 / 3.001)}.uk-width-2-3\@m{width:calc(100% * 2 / 3.001)}.uk-width-1-4\@m{width:25%}.uk-width-3-4\@m{width:75%}.uk-width-1-5\@m{width:20%}.uk-width-2-5\@m{width:40%}.uk-width-3-5\@m{width:60%}.uk-width-4-5\@m{width:80%}.uk-width-1-6\@m{width:calc(100% * 1 / 6.001)}.uk-width-5-6\@m{width:calc(100% * 5 / 6.001)}.uk-width-small\@m{width:150px}.uk-width-medium\@m{width:300px}.uk-width-large\@m{width:450px}.uk-width-xlarge\@m{width:600px}.uk-width-xxlarge\@m{width:750px}.uk-width-auto\@m{width:auto}.uk-width-expand\@m{width:1px;flex:1;min-width:0;flex-basis:1px}}@media (min-width: 1200px){.uk-width-1-1\@l{width:100%}.uk-width-1-2\@l{width:50%}.uk-width-1-3\@l{width:calc(100% * 1 / 3.001)}.uk-width-2-3\@l{width:calc(100% * 2 / 3.001)}.uk-width-1-4\@l{width:25%}.uk-width-3-4\@l{width:75%}.uk-width-1-5\@l{width:20%}.uk-width-2-5\@l{width:40%}.uk-width-3-5\@l{width:60%}.uk-width-4-5\@l{width:80%}.uk-width-1-6\@l{width:calc(100% * 1 / 6.001)}.uk-width-5-6\@l{width:calc(100% * 5 / 6.001)}.uk-width-small\@l{width:150px}.uk-width-medium\@l{width:300px}.uk-width-large\@l{width:450px}.uk-width-xlarge\@l{width:600px}.uk-width-xxlarge\@l{width:750px}.uk-width-auto\@l{width:auto}.uk-width-expand\@l{width:1px;flex:1;min-width:0;flex-basis:1px}}@media (min-width: 1600px){.uk-width-1-1\@xl{width:100%}.uk-width-1-2\@xl{width:50%}.uk-width-1-3\@xl{width:calc(100% * 1 / 3.001)}.uk-width-2-3\@xl{width:calc(100% * 2 / 3.001)}.uk-width-1-4\@xl{width:25%}.uk-width-3-4\@xl{width:75%}.uk-width-1-5\@xl{width:20%}.uk-width-2-5\@xl{width:40%}.uk-width-3-5\@xl{width:60%}.uk-width-4-5\@xl{width:80%}.uk-width-1-6\@xl{width:calc(100% * 1 / 6.001)}.uk-width-5-6\@xl{width:calc(100% * 5 / 6.001)}.uk-width-small\@xl{width:150px}.uk-width-medium\@xl{width:300px}.uk-width-large\@xl{width:450px}.uk-width-xlarge\@xl{width:600px}.uk-width-xxlarge\@xl{width:750px}.uk-width-auto\@xl{width:auto}.uk-width-expand\@xl{width:1px;flex:1;min-width:0;flex-basis:1px}}.uk-text-lead{font-size:1.125rem;line-height:1.5;color:#333}.uk-text-meta{font-size:.875rem;line-height:1.4;color:#7a838a}.uk-text-meta a{color:#7a838a}.uk-text-meta a:hover{color:#666;text-decoration:none}.uk-text-small{font-size:.875rem;line-height:1.5}.uk-text-large{font-size:1.375rem;line-height:1.5}.uk-text-bold{font-weight:bolder}.uk-text-uppercase{text-transform:uppercase !important}.uk-text-capitalize{text-transform:capitalize !important}.uk-text-lowercase{text-transform:lowercase !important}.uk-text-muted{color:#7a838a !important}.uk-text-primary{color:#0F1214 !important}.uk-text-success{color:#32d296 !important}.uk-text-warning{color:#faa05a !important}.uk-text-danger{color:#f0506e !important}.uk-text-background{-webkit-background-clip:text;-webkit-text-fill-color:transparent;display:inline-block;color:#0F1214 !important}@supports (-webkit-background-clip: text){.uk-text-background{background-color:#0F1214}}.uk-text-left{text-align:left !important}.uk-text-right{text-align:right !important}.uk-text-center{text-align:center !important}.uk-text-justify{text-align:justify !important}@media (min-width: 640px){.uk-text-left\@s{text-align:left !important}.uk-text-right\@s{text-align:right !important}.uk-text-center\@s{text-align:center !important}}@media (min-width: 960px){.uk-text-left\@m{text-align:left !important}.uk-text-right\@m{text-align:right !important}.uk-text-center\@m{text-align:center !important}}@media (min-width: 1200px){.uk-text-left\@l{text-align:left !important}.uk-text-right\@l{text-align:right !important}.uk-text-center\@l{text-align:center !important}}@media (min-width: 1600px){.uk-text-left\@xl{text-align:left !important}.uk-text-right\@xl{text-align:right !important}.uk-text-center\@xl{text-align:center !important}}.uk-text-top{vertical-align:top !important}.uk-text-middle{vertical-align:middle !important}.uk-text-bottom{vertical-align:bottom !important}.uk-text-baseline{vertical-align:baseline !important}.uk-text-nowrap{white-space:nowrap}.uk-text-truncate{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}th.uk-text-truncate,td.uk-text-truncate{max-width:0}.uk-text-break{overflow-wrap:break-word;word-wrap:break-word;-ms-hyphens:auto;-webkit-hyphens:auto;hyphens:auto}th.uk-text-break,td.uk-text-break{word-break:break-all}[class*='uk-column-']{column-gap:30px}@media (min-width: 1200px){[class*='uk-column-']{column-gap:40px}}[class*='uk-column-'] img{transform:translate3d(0, 0, 0)}.uk-column-divider{column-rule:1px solid #c4c7ca;column-gap:60px}@media (min-width: 1200px){.uk-column-divider{column-gap:80px}}.uk-column-1-2{column-count:2}.uk-column-1-3{column-count:3}.uk-column-1-4{column-count:4}.uk-column-1-5{column-count:5}.uk-column-1-6{column-count:6}@media (min-width: 640px){.uk-column-1-2\@s{column-count:2}.uk-column-1-3\@s{column-count:3}.uk-column-1-4\@s{column-count:4}.uk-column-1-5\@s{column-count:5}.uk-column-1-6\@s{column-count:6}}@media (min-width: 960px){.uk-column-1-2\@m{column-count:2}.uk-column-1-3\@m{column-count:3}.uk-column-1-4\@m{column-count:4}.uk-column-1-5\@m{column-count:5}.uk-column-1-6\@m{column-count:6}}@media (min-width: 1200px){.uk-column-1-2\@l{column-count:2}.uk-column-1-3\@l{column-count:3}.uk-column-1-4\@l{column-count:4}.uk-column-1-5\@l{column-count:5}.uk-column-1-6\@l{column-count:6}}@media (min-width: 1600px){.uk-column-1-2\@xl{column-count:2}.uk-column-1-3\@xl{column-count:3}.uk-column-1-4\@xl{column-count:4}.uk-column-1-5\@xl{column-count:5}.uk-column-1-6\@xl{column-count:6}}.uk-column-span{column-span:all}.uk-cover{max-width:none;position:absolute;left:50%;top:50%;transform:translate(-50%, -50%)}iframe.uk-cover{pointer-events:none}.uk-cover-container{overflow:hidden;position:relative}[class*='uk-align']{display:block;margin-bottom:30px}*+[class*='uk-align']{margin-top:30px}.uk-align-center{margin-left:auto;margin-right:auto}.uk-align-left{margin-top:0;margin-right:30px;float:left}.uk-align-right{margin-top:0;margin-left:30px;float:right}@media (min-width: 640px){.uk-align-left\@s{margin-top:0;margin-right:30px;float:left}.uk-align-right\@s{margin-top:0;margin-left:30px;float:right}}@media (min-width: 960px){.uk-align-left\@m{margin-top:0;margin-right:30px;float:left}.uk-align-right\@m{margin-top:0;margin-left:30px;float:right}}@media (min-width: 1200px){.uk-align-left\@l{margin-top:0;float:left}.uk-align-right\@l{margin-top:0;float:right}.uk-align-left,.uk-align-left\@s,.uk-align-left\@m,.uk-align-left\@l{margin-right:40px}.uk-align-right,.uk-align-right\@s,.uk-align-right\@m,.uk-align-right\@l{margin-left:40px}}@media (min-width: 1600px){.uk-align-left\@xl{margin-top:0;margin-right:40px;float:left}.uk-align-right\@xl{margin-top:0;margin-left:40px;float:right}}.uk-panel{position:relative;box-sizing:border-box}.uk-panel::before,.uk-panel::after{content:"";display:table}.uk-panel::after{clear:both}.uk-panel>:last-child{margin-bottom:0}.uk-panel-scrollable{height:170px;padding:10px;border:1px solid #c4c7ca;overflow:auto;-webkit-overflow-scrolling:touch;resize:both}.uk-clearfix::before{content:"";display:table-cell}.uk-clearfix::after{content:"";display:table;clear:both}.uk-float-left{float:left}.uk-float-right{float:right}[class*='uk-float-']{max-width:100%}.uk-overflow-hidden{overflow:hidden}.uk-overflow-auto{overflow:auto;-webkit-overflow-scrolling:touch}.uk-overflow-auto>:last-child{margin-bottom:0}.uk-resize{resize:both}.uk-resize-vertical{resize:vertical}.uk-display-block{display:block !important}.uk-display-inline{display:inline !important}.uk-display-inline-block{display:inline-block !important}[class*='uk-inline']{display:inline-block;position:relative;max-width:100%;vertical-align:middle;-webkit-backface-visibility:hidden}.uk-inline-clip{overflow:hidden}[class*='uk-height']{box-sizing:border-box}.uk-height-1-1{height:100%}.uk-height-viewport{min-height:100vh}.uk-height-small{height:150px}.uk-height-medium{height:300px}.uk-height-large{height:450px}.uk-height-max-small{max-height:150px}.uk-height-max-medium{max-height:300px}.uk-height-max-large{max-height:450px}.uk-preserve-width,.uk-preserve-width audio,.uk-preserve-width canvas,.uk-preserve-width img,.uk-preserve-width svg,.uk-preserve-width video{max-width:none}.uk-responsive-width,.uk-responsive-height{box-sizing:border-box}.uk-responsive-width{max-width:100% !important;height:auto}.uk-responsive-height{max-height:100%;width:auto;max-width:none}.uk-border-circle{border-radius:50%}.uk-border-rounded{border-radius:5px}.uk-inline-clip[class*='uk-border-']{-webkit-transform:translateZ(0)}.uk-box-shadow-small{box-shadow:0 2px 8px rgba(0,0,0,0.08)}.uk-box-shadow-medium{box-shadow:0 5px 15px rgba(0,0,0,0.08)}.uk-box-shadow-large{box-shadow:0 14px 25px rgba(0,0,0,0.16)}.uk-box-shadow-xlarge{box-shadow:0 28px 50px rgba(0,0,0,0.16)}[class*='uk-box-shadow-hover']{transition:box-shadow .1s ease-in-out}.uk-box-shadow-hover-small:hover{box-shadow:0 2px 8px rgba(0,0,0,0.08)}.uk-box-shadow-hover-medium:hover{box-shadow:0 5px 15px rgba(0,0,0,0.08)}.uk-box-shadow-hover-large:hover{box-shadow:0 14px 25px rgba(0,0,0,0.16)}.uk-box-shadow-hover-xlarge:hover{box-shadow:0 28px 50px rgba(0,0,0,0.16)}@supports (filter: blur(0)){.uk-box-shadow-bottom{display:inline-block;position:relative;max-width:100%;vertical-align:middle}.uk-box-shadow-bottom::before{content:'';position:absolute;bottom:-30px;left:0;right:0;height:30px;border-radius:100%;background:#444;filter:blur(20px)}.uk-box-shadow-bottom>*{position:relative}}.uk-dropcap::first-letter,.uk-dropcap>p:first-of-type::first-letter{display:block;margin-right:10px;float:left;font-size:4.5em;line-height:1;margin-bottom:-2px}.uk-leader{overflow:hidden}.uk-leader-fill::after{display:inline-block;margin-left:15px;width:0;content:attr(data-fill);white-space:nowrap}.uk-leader-fill.uk-leader-hide::after{display:none}.var-leader-fill:before{content:"."}.uk-logo{font-size:1.375rem;font-family:system-ui;color:#666;text-decoration:none}.uk-logo:hover,.uk-logo:focus{color:#666;outline:none;text-decoration:none}.uk-logo-inverse{display:none}.uk-svg,.uk-svg:not(.uk-preserve) [fill*='#']:not(.uk-preserve),.uk-svg:not(.uk-preserve) [FILL*='#']:not(.uk-preserve){fill:currentcolor}.uk-svg:not(.uk-preserve) [stroke*='#']:not(.uk-preserve),.uk-svg:not(.uk-preserve) [STROKE*='#']:not(.uk-preserve){stroke:currentcolor}.uk-svg{transform:translate(0, 0)}.uk-disabled{pointer-events:none}.uk-drag,.uk-drag *{cursor:move}.uk-drag iframe{pointer-events:none}.uk-dragover{box-shadow:0 0 20px rgba(100,100,100,0.3)}.uk-blend-multiply{mix-blend-mode:multiply}.uk-blend-screen{mix-blend-mode:screen}.uk-blend-overlay{mix-blend-mode:overlay}.uk-blend-darken{mix-blend-mode:darken}.uk-blend-lighten{mix-blend-mode:lighten}.uk-blend-color-dodge{mix-blend-mode:color-dodge}.uk-blend-color-burn{mix-blend-mode:color-burn}.uk-blend-hard-light{mix-blend-mode:hard-light}.uk-blend-soft-light{mix-blend-mode:soft-light}.uk-blend-difference{mix-blend-mode:difference}.uk-blend-exclusion{mix-blend-mode:exclusion}.uk-blend-hue{mix-blend-mode:hue}.uk-blend-saturation{mix-blend-mode:saturation}.uk-blend-color{mix-blend-mode:color}.uk-blend-luminosity{mix-blend-mode:luminosity}.uk-transform-center{transform:translate(-50%, -50%)}.uk-transform-origin-top-left{transform-origin:0 0}.uk-transform-origin-top-center{transform-origin:50% 0}.uk-transform-origin-top-right{transform-origin:100% 0}.uk-transform-origin-center-left{transform-origin:0 50%}.uk-transform-origin-center-right{transform-origin:100% 50%}.uk-transform-origin-bottom-left{transform-origin:0 100%}.uk-transform-origin-bottom-center{transform-origin:50% 100%}.uk-transform-origin-bottom-right{transform-origin:100% 100%}.remove-underline,.remove-underline:hover{text-decoration:none}.link-dark{color:#0F1214 !important}.uk-container.uk-container-xsmall{max-width:700px}.hvr-forward{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px transparent;-webkit-transition-duration:0.3s;transition-duration:0.3s;-webkit-transition-property:transform;transition-property:transform}.hvr-forward:active,.hvr-forward:focus,.hvr-forward:hover{-webkit-transform:translateX(6px);transform:translateX(6px)}.hvr-back{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px transparent;-webkit-transition-duration:0.3s;transition-duration:0.3s;-webkit-transition-property:transform;transition-property:transform}.hvr-back:hover,.hvr-back:focus,.hvr-back:active{-webkit-transform:translateX(-6px);transform:translateX(-6px)}.social-networks{margin-top:70px}header .uk-logo{color:#0F1214}header .uk-logo:hover{color:#0F1214}.section-title{margin-bottom:40px}.section-title ~ .section-title{margin-top:40px}@media (min-width: 960px){.section-title ~ .section-title{margin-top:70px}}.section-hero .searchBox{max-width:550px;margin:60px auto 0 auto}.section-hero .searchBox .uk-search-input{height:50px;border-radius:50px;color:#7a838a;font-style:normal}.section-hero .searchBox .uk-search-input:focus{background:#ffffff}.section-hero .searchBox .uk-search-icon{width:50px;color:#7a838a}footer .uk-subnav>.uk-active>a{color:#7a838a}#markdown-toc{padding:0 0 0 20px;border-left:solid 2px #7a838a;list-style:none;margin-bottom:40px}#markdown-toc>li>:last-child{margin-bottom:0}#markdown-toc ul{margin:0;padding-left:20px;list-style:none}#markdown-toc>li:nth-child(n+2),#markdown-toc>li>ul{margin-top:5px}#markdown-toc a{color:#7a838a}.uk-article-content .no_toc{margin-top:40px;margin-bottom:40px}#searchBox-results,#searchBox-results{margin:10px 0 0 0;z-index:1}#searchBox-results li,#searchBox-results li{margin:0;padding:20px 25px 0;background:#fff;line-height:1.4;border-left:solid 1px #c4c7ca;border-right:solid 1px #c4c7ca}#searchBox-results li:first-child,#searchBox-results li:first-child{border-top-left-radius:5px;border-top-right-radius:5px;border-top:solid 1px #c4c7ca}#searchBox-results li:last-child,#searchBox-results li:last-child{border-bottom-left-radius:5px;border-bottom-right-radius:5px;padding-bottom:25px;border-bottom:solid 1px #c4c7ca}#searchBox-results li a:hover,#searchBox-results li a:hover{text-decoration:none}.uk-flex{display:flex}.uk-flex-inline{display:inline-flex}.uk-flex::before,.uk-flex::after,.uk-flex-inline::before,.uk-flex-inline::after{display:none}.uk-flex-left{justify-content:flex-start}.uk-flex-center{justify-content:center}.uk-flex-right{justify-content:flex-end}.uk-flex-between{justify-content:space-between}.uk-flex-around{justify-content:space-around}@media (min-width: 640px){.uk-flex-left\@s{justify-content:flex-start}.uk-flex-center\@s{justify-content:center}.uk-flex-right\@s{justify-content:flex-end}.uk-flex-between\@s{justify-content:space-between}.uk-flex-around\@s{justify-content:space-around}}@media (min-width: 960px){.uk-flex-left\@m{justify-content:flex-start}.uk-flex-center\@m{justify-content:center}.uk-flex-right\@m{justify-content:flex-end}.uk-flex-between\@m{justify-content:space-between}.uk-flex-around\@m{justify-content:space-around}}@media (min-width: 1200px){.uk-flex-left\@l{justify-content:flex-start}.uk-flex-center\@l{justify-content:center}.uk-flex-right\@l{justify-content:flex-end}.uk-flex-between\@l{justify-content:space-between}.uk-flex-around\@l{justify-content:space-around}}@media (min-width: 1600px){.uk-flex-left\@xl{justify-content:flex-start}.uk-flex-center\@xl{justify-content:center}.uk-flex-right\@xl{justify-content:flex-end}.uk-flex-between\@xl{justify-content:space-between}.uk-flex-around\@xl{justify-content:space-around}}.uk-flex-stretch{align-items:stretch}.uk-flex-top{align-items:flex-start}.uk-flex-middle{align-items:center}.uk-flex-bottom{align-items:flex-end}.uk-flex-row{flex-direction:row}.uk-flex-row-reverse{flex-direction:row-reverse}.uk-flex-column{flex-direction:column}.uk-flex-column-reverse{flex-direction:column-reverse}.uk-flex-nowrap{flex-wrap:nowrap}.uk-flex-wrap{flex-wrap:wrap}.uk-flex-wrap-reverse{flex-wrap:wrap-reverse}.uk-flex-wrap-stretch{align-content:stretch}.uk-flex-wrap-top{align-content:flex-start}.uk-flex-wrap-middle{align-content:center}.uk-flex-wrap-bottom{align-content:flex-end}.uk-flex-wrap-between{align-content:space-between}.uk-flex-wrap-around{align-content:space-around}.uk-flex-first{order:-1}.uk-flex-last{order:99}@media (min-width: 640px){.uk-flex-first\@s{order:-1}.uk-flex-last\@s{order:99}}@media (min-width: 960px){.uk-flex-first\@m{order:-1}.uk-flex-last\@m{order:99}}@media (min-width: 1200px){.uk-flex-first\@l{order:-1}.uk-flex-last\@l{order:99}}@media (min-width: 1600px){.uk-flex-first\@xl{order:-1}.uk-flex-last\@xl{order:99}}.uk-flex-none{flex:none}.uk-flex-auto{flex:auto}.uk-flex-1{flex:1}.uk-margin{margin-bottom:20px}*+.uk-margin{margin-top:20px !important}.uk-margin-top{margin-top:20px !important}.uk-margin-bottom{margin-bottom:20px !important}.uk-margin-left{margin-left:20px !important}.uk-margin-right{margin-right:20px !important}.uk-margin-small{margin-bottom:10px}*+.uk-margin-small{margin-top:10px !important}.uk-margin-small-top{margin-top:10px !important}.uk-margin-small-bottom{margin-bottom:10px !important}.uk-margin-small-left{margin-left:10px !important}.uk-margin-small-right{margin-right:10px !important}.uk-margin-medium{margin-bottom:40px}*+.uk-margin-medium{margin-top:40px !important}.uk-margin-medium-top{margin-top:40px !important}.uk-margin-medium-bottom{margin-bottom:40px !important}.uk-margin-medium-left{margin-left:40px !important}.uk-margin-medium-right{margin-right:40px !important}.uk-margin-large{margin-bottom:40px}*+.uk-margin-large{margin-top:40px !important}.uk-margin-large-top{margin-top:40px !important}.uk-margin-large-bottom{margin-bottom:40px !important}.uk-margin-large-left{margin-left:40px !important}.uk-margin-large-right{margin-right:40px !important}@media (min-width: 1200px){.uk-margin-large{margin-bottom:70px}*+.uk-margin-large{margin-top:70px !important}.uk-margin-large-top{margin-top:70px !important}.uk-margin-large-bottom{margin-bottom:70px !important}.uk-margin-large-left{margin-left:70px !important}.uk-margin-large-right{margin-right:70px !important}}.uk-margin-xlarge{margin-bottom:70px}*+.uk-margin-xlarge{margin-top:70px !important}.uk-margin-xlarge-top{margin-top:70px !important}.uk-margin-xlarge-bottom{margin-bottom:70px !important}.uk-margin-xlarge-left{margin-left:70px !important}.uk-margin-xlarge-right{margin-right:70px !important}@media (min-width: 1200px){.uk-margin-xlarge{margin-bottom:140px}*+.uk-margin-xlarge{margin-top:140px !important}.uk-margin-xlarge-top{margin-top:140px !important}.uk-margin-xlarge-bottom{margin-bottom:140px !important}.uk-margin-xlarge-left{margin-left:140px !important}.uk-margin-xlarge-right{margin-right:140px !important}}.uk-margin-remove{margin:0 !important}.uk-margin-remove-top{margin-top:0 !important}.uk-margin-remove-bottom{margin-bottom:0 !important}.uk-margin-remove-left{margin-left:0 !important}.uk-margin-remove-right{margin-right:0 !important}.uk-margin-remove-vertical{margin-top:0 !important;margin-bottom:0 !important}.uk-margin-remove-adjacent+*{margin-top:0 !important}.uk-margin-auto{margin-left:auto !important;margin-right:auto !important}.uk-margin-auto-top{margin-top:auto !important}.uk-margin-auto-bottom{margin-bottom:auto !important}.uk-margin-auto-left{margin-left:auto !important}.uk-margin-auto-right{margin-right:auto !important}.uk-margin-auto-vertical{margin-top:auto !important;margin-bottom:auto !important}.uk-padding{padding:30px}@media (min-width: 1200px){.uk-padding{padding:40px}}.uk-padding-small{padding:15px}.uk-padding-large{padding:30px}@media (min-width: 1200px){.uk-padding-large{padding:70px}}.uk-padding-remove{padding:0 !important}.uk-padding-remove-top{padding-top:0 !important}.uk-padding-remove-bottom{padding-bottom:0 !important}.uk-padding-remove-left{padding-left:0 !important}.uk-padding-remove-right{padding-right:0 !important}.uk-padding-remove-vertical{padding-top:0 !important;padding-bottom:0 !important}.uk-padding-remove-horizontal{padding-left:0 !important;padding-right:0 !important}[class*='uk-position-top'],[class*='uk-position-bottom'],[class*='uk-position-left'],[class*='uk-position-right'],[class*='uk-position-center']{position:absolute !important}.uk-position-top{top:0;left:0;right:0}.uk-position-bottom{bottom:0;left:0;right:0}.uk-position-left{top:0;bottom:0;left:0}.uk-position-right{top:0;bottom:0;right:0}.uk-position-top-left{top:0;left:0}.uk-position-top-right{top:0;right:0}.uk-position-bottom-left{bottom:0;left:0}.uk-position-bottom-right{bottom:0;right:0}.uk-position-center{top:50%;left:50%;transform:translate(-50%, -50%);display:table;width:-moz-max-content;max-width:100%;box-sizing:border-box}[class*='uk-position-center-left'],[class*='uk-position-center-right']{top:50%;transform:translateY(-50%)}.uk-position-center-left{left:0}.uk-position-center-right{right:0}.uk-position-center-left-out{right:100%;width:max-content}.uk-position-center-right-out{left:100%;width:max-content}.uk-position-top-center,.uk-position-bottom-center{left:50%;transform:translateX(-50%);display:table;width:-moz-max-content;max-width:100%;box-sizing:border-box}.uk-position-top-center{top:0}.uk-position-bottom-center{bottom:0}.uk-position-cover{position:absolute;top:0;bottom:0;left:0;right:0}.uk-position-relative{position:relative !important}.uk-position-absolute{position:absolute !important}.uk-position-fixed{position:fixed !important}.uk-position-z-index{z-index:1}.uk-position-small{margin:15px}.uk-position-small.uk-position-center{transform:translate(-50%, -50%) translate(-15px, -15px)}.uk-position-small[class*='uk-position-center-left'],.uk-position-small[class*='uk-position-center-right']{transform:translateY(-50%) translateY(-15px)}.uk-position-small.uk-position-top-center,.uk-position-small.uk-position-bottom-center{transform:translateX(-50%) translateX(-15px)}.uk-position-medium{margin:30px}.uk-position-medium.uk-position-center{transform:translate(-50%, -50%) translate(-30px, -30px)}.uk-position-medium[class*='uk-position-center-left'],.uk-position-medium[class*='uk-position-center-right']{transform:translateY(-50%) translateY(-30px)}.uk-position-medium.uk-position-top-center,.uk-position-medium.uk-position-bottom-center{transform:translateX(-50%) translateX(-30px)}.uk-position-large{margin:30px}.uk-position-large.uk-position-center{transform:translate(-50%, -50%) translate(-30px, -30px)}.uk-position-large[class*='uk-position-center-left'],.uk-position-large[class*='uk-position-center-right']{transform:translateY(-50%) translateY(-30px)}.uk-position-large.uk-position-top-center,.uk-position-large.uk-position-bottom-center{transform:translateX(-50%) translateX(-30px)}@media (min-width: 1200px){.uk-position-large{margin:50px}.uk-position-large.uk-position-center{transform:translate(-50%, -50%) translate(-50px, -50px)}.uk-position-large[class*='uk-position-center-left'],.uk-position-large[class*='uk-position-center-right']{transform:translateY(-50%) translateY(-50px)}.uk-position-large.uk-position-top-center,.uk-position-large.uk-position-bottom-center{transform:translateX(-50%) translateX(-50px)}}[hidden],.uk-hidden{display:none !important}@media (min-width: 640px){.uk-hidden\@s{display:none !important}}@media (min-width: 960px){.uk-hidden\@m{display:none !important}}@media (min-width: 1200px){.uk-hidden\@l{display:none !important}}@media (min-width: 1600px){.uk-hidden\@xl{display:none !important}}@media (max-width: 639px){.uk-visible\@s{display:none !important}}@media (max-width: 959px){.uk-visible\@m{display:none !important}}@media (max-width: 1199px){.uk-visible\@l{display:none !important}}@media (max-width: 1599px){.uk-visible\@xl{display:none !important}}.uk-invisible{visibility:hidden !important}.uk-visible-toggle:not(:hover):not(.uk-hover) .uk-hidden-hover:not(:focus){position:absolute !important;width:0 !important;height:0 !important;padding:0 !important;margin:0 !important;overflow:hidden !important}.uk-visible-toggle:not(:hover):not(.uk-hover) .uk-invisible-hover:not(:focus){opacity:0 !important}@media (pointer: coarse){.uk-hidden-touch{display:none !important}}.uk-hidden-notouch{display:none !important}@media (pointer: coarse){.uk-hidden-notouch{display:block !important}}@media print{*,*::before,*::after{background:transparent !important;color:black !important;box-shadow:none !important;text-shadow:none !important}a,a:visited{text-decoration:underline}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}}.highlight,.highlighter-rouge{background-color:#F7F8FA;color:#5A6575;border:none}.highlight .lineno{color:#B1B8C4}.highlight .c{color:#B1B8C4}.highlight .err{color:#5A6575}.highlight .g{color:#5A6575}.highlight .k{color:#25BEA1}.highlight .l{color:#5A6575}.highlight .n{color:#5A6575}.highlight .o{color:#25BEA1}.highlight .x{color:#FBBC09}.highlight .p{color:#25BEA1}.highlight .cm{color:#B1B8C4}.highlight .cp{color:#25BEA1}.highlight .c1{color:#B1B8C4}.highlight .cs{color:#25BEA1}.highlight .gd{color:#E56134}.highlight .ge{color:#5A6575;font-style:italic}.highlight .gr{color:#9961C9}.highlight .gh{color:#FBBC09}.highlight .gi{color:#25BEA1}.highlight .go{color:#5A6575}.highlight .gp{color:#FBBC09}.highlight .gs{color:#5A6575;font-weight:bold}.highlight .gu{color:#FBBC09}.highlight .gt{color:#5A6575}.highlight .kc{color:#FBBC09}.highlight .kd{color:#11A0F3}.highlight .kn{color:#25BEA1}.highlight .kp{color:#25BEA1}.highlight .kr{color:#11A0F3}.highlight .kt{color:#9961C9}.highlight .ld{color:#5A6575}.highlight .m{color:#E56134}.highlight .s{color:#E56134}.highlight .na{color:#5A6575}.highlight .nb{color:#5A6575}.highlight .nc{color:#11A0F3}.highlight .no{color:#5A6575}.highlight .nd{color:#11A0F3}.highlight .ni{color:#FBBC09}.highlight .ne{color:#FBBC09}.highlight .nf{color:#11A0F3}.highlight .nl{color:#5A6575}.highlight .nn{color:#5A6575}.highlight .nx{color:#5A6575}.highlight .py{color:#5A6575}.highlight .nt{color:#11A0F3}.highlight .nv{color:#5A6575}.highlight .ow{color:#25BEA1}.highlight .w{color:#5A6575}.highlight .mf{color:#E56134}.highlight .mh{color:#E56134}.highlight .mi{color:#E56134}.highlight .mo{color:#E56134}.highlight .sb{color:#B1B8C4}.highlight .sc{color:#E56134}.highlight .sd{color:#5A6575}.highlight .s2{color:#E56134}.highlight .se{color:#FBBC09}.highlight .sh{color:#5A6575}.highlight .si{color:#E56134}.highlight .sx{color:#E56134}.highlight .sr{color:#9961C9}.highlight .s1{color:#E56134}.highlight .ss{color:#E56134}.highlight .bp{color:#11A0F3}.highlight .vc{color:#11A0F3}.highlight .vg{color:#11A0F3}.highlight .vi{color:#11A0F3}.highlight .il{color:#E56134}
diff --git a/_site/assets/img/favicon.png b/_site/assets/img/favicon.png
deleted file mode 100644
index 09d6ca94a9..0000000000
Binary files a/_site/assets/img/favicon.png and /dev/null differ
diff --git a/_site/assets/img/location.svg b/_site/assets/img/location.svg
deleted file mode 100644
index e71e58b04c..0000000000
--- a/_site/assets/img/location.svg
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
- location-dark
- Created with Sketch.
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/_site/assets/img/touch-icon.png b/_site/assets/img/touch-icon.png
deleted file mode 100644
index 243615bb9f..0000000000
Binary files a/_site/assets/img/touch-icon.png and /dev/null differ
diff --git a/_site/assets/js/custom.js b/_site/assets/js/custom.js
deleted file mode 100644
index d123eb3515..0000000000
--- a/_site/assets/js/custom.js
+++ /dev/null
@@ -1 +0,0 @@
-// Custom scripts
diff --git a/_site/assets/js/main.js b/_site/assets/js/main.js
deleted file mode 100644
index 031cf722e2..0000000000
--- a/_site/assets/js/main.js
+++ /dev/null
@@ -1,8772 +0,0 @@
-(function(global, factory) {
- typeof exports === "object" && typeof module !== "undefined" ? module.exports = factory() : typeof define === "function" && define.amd ? define("uikit", factory) : global.UIkit = factory();
-})(this, function() {
- "use strict";
- function bind(fn, context) {
- return function(a) {
- var l = arguments.length;
- return l ? l > 1 ? fn.apply(context, arguments) : fn.call(context, a) : fn.call(context);
- };
- }
- var ref = Object.prototype;
- var hasOwnProperty = ref.hasOwnProperty;
- function hasOwn(obj, key) {
- return hasOwnProperty.call(obj, key);
- }
- var hyphenateRe = /([a-z\d])([A-Z])/g;
- function hyphenate(str) {
- return str.replace(hyphenateRe, "$1-$2").toLowerCase();
- }
- var camelizeRE = /-(\w)/g;
- function camelize(str) {
- return str.replace(camelizeRE, toUpper);
- }
- function toUpper(_, c) {
- return c ? c.toUpperCase() : "";
- }
- function ucfirst(str) {
- return str.length ? toUpper(null, str.charAt(0)) + str.slice(1) : "";
- }
- var strPrototype = String.prototype;
- var startsWithFn = strPrototype.startsWith || function(search) {
- return this.lastIndexOf(search, 0) === 0;
- };
- function startsWith(str, search) {
- return startsWithFn.call(str, search);
- }
- var endsWithFn = strPrototype.endsWith || function(search) {
- return this.substr(-search.length) === search;
- };
- function endsWith(str, search) {
- return endsWithFn.call(str, search);
- }
- var includesFn = function(search) {
- return ~this.indexOf(search);
- };
- var includesStr = strPrototype.includes || includesFn;
- var includesArray = Array.prototype.includes || includesFn;
- function includes(obj, search) {
- return obj && (isString(obj) ? includesStr : includesArray).call(obj, search);
- }
- var isArray = Array.isArray;
- function isFunction(obj) {
- return typeof obj === "function";
- }
- function isObject(obj) {
- return obj !== null && typeof obj === "object";
- }
- function isPlainObject(obj) {
- return isObject(obj) && Object.getPrototypeOf(obj) === Object.prototype;
- }
- function isWindow(obj) {
- return isObject(obj) && obj === obj.window;
- }
- function isDocument(obj) {
- return isObject(obj) && obj.nodeType === 9;
- }
- function isJQuery(obj) {
- return isObject(obj) && !!obj.jquery;
- }
- function isNode(element) {
- return element instanceof Node || isObject(element) && element.nodeType === 1;
- }
- function isNodeCollection(element) {
- return element instanceof NodeList || element instanceof HTMLCollection;
- }
- function isBoolean(value) {
- return typeof value === "boolean";
- }
- function isString(value) {
- return typeof value === "string";
- }
- function isNumber(value) {
- return typeof value === "number";
- }
- function isNumeric(value) {
- return isNumber(value) || isString(value) && !isNaN(value - parseFloat(value));
- }
- function isUndefined(value) {
- return value === void 0;
- }
- function toBoolean(value) {
- return isBoolean(value) ? value : value === "true" || value === "1" || value === "" ? true : value === "false" || value === "0" ? false : value;
- }
- function toNumber(value) {
- var number = Number(value);
- return !isNaN(number) ? number : false;
- }
- function toFloat(value) {
- return parseFloat(value) || 0;
- }
- function toNode(element) {
- return isNode(element) || isWindow(element) || isDocument(element) ? element : isNodeCollection(element) || isJQuery(element) ? element[0] : isArray(element) ? toNode(element[0]) : null;
- }
- var arrayProto = Array.prototype;
- function toNodes(element) {
- return isNode(element) ? [ element ] : isNodeCollection(element) ? arrayProto.slice.call(element) : isArray(element) ? element.map(toNode).filter(Boolean) : isJQuery(element) ? element.toArray() : [];
- }
- function toList(value) {
- return isArray(value) ? value : isString(value) ? value.split(/,(?![^(]*\))/).map(function(value) {
- return isNumeric(value) ? toNumber(value) : toBoolean(value.trim());
- }) : [ value ];
- }
- function toMs(time) {
- return !time ? 0 : endsWith(time, "ms") ? toFloat(time) : toFloat(time) * 1e3;
- }
- function swap(value, a, b) {
- return value.replace(new RegExp(a + "|" + b, "mg"), function(match) {
- return match === a ? b : a;
- });
- }
- var assign = Object.assign || function(target) {
- var args = [], len = arguments.length - 1;
- while (len-- > 0) args[len] = arguments[len + 1];
- target = Object(target);
- for (var i = 0; i < args.length; i++) {
- var source = args[i];
- if (source !== null) {
- for (var key in source) {
- if (hasOwn(source, key)) {
- target[key] = source[key];
- }
- }
- }
- }
- return target;
- };
- function each(obj, cb) {
- for (var key in obj) {
- if (cb.call(obj[key], obj[key], key) === false) {
- break;
- }
- }
- }
- function sortBy(collection, prop) {
- return collection.sort(function(a, b) {
- return a[prop] - b[prop];
- });
- }
- function clamp(number, min, max) {
- if (min === void 0) min = 0;
- if (max === void 0) max = 1;
- return Math.min(Math.max(number, min), max);
- }
- function noop() {}
- function intersectRect(r1, r2) {
- return r1.left <= r2.right && r2.left <= r1.right && r1.top <= r2.bottom && r2.top <= r1.bottom;
- }
- function pointInRect(point, rect) {
- return intersectRect({
- top: point.y,
- bottom: point.y,
- left: point.x,
- right: point.x
- }, rect);
- }
- var Dimensions = {
- ratio: function ratio(dimensions, prop, value) {
- var obj;
- var aProp = prop === "width" ? "height" : "width";
- return obj = {}, obj[aProp] = Math.round(value * dimensions[aProp] / dimensions[prop]),
- obj[prop] = value, obj;
- },
- contain: function contain(dimensions, maxDimensions) {
- var this$1 = this;
- dimensions = assign({}, dimensions);
- each(dimensions, function(_, prop) {
- return dimensions = dimensions[prop] > maxDimensions[prop] ? this$1.ratio(dimensions, prop, maxDimensions[prop]) : dimensions;
- });
- return dimensions;
- },
- cover: function cover(dimensions, maxDimensions) {
- var this$1 = this;
- dimensions = this.contain(dimensions, maxDimensions);
- each(dimensions, function(_, prop) {
- return dimensions = dimensions[prop] < maxDimensions[prop] ? this$1.ratio(dimensions, prop, maxDimensions[prop]) : dimensions;
- });
- return dimensions;
- }
- };
- function attr(element, name, value) {
- if (isObject(name)) {
- for (var key in name) {
- attr(element, key, name[key]);
- }
- return;
- }
- if (isUndefined(value)) {
- element = toNode(element);
- return element && element.getAttribute(name);
- } else {
- toNodes(element).forEach(function(element) {
- if (isFunction(value)) {
- value = value.call(element, attr(element, name));
- }
- if (value === null) {
- removeAttr(element, name);
- } else {
- element.setAttribute(name, value);
- }
- });
- }
- }
- function hasAttr(element, name) {
- return toNodes(element).some(function(element) {
- return element.hasAttribute(name);
- });
- }
- function removeAttr(element, name) {
- element = toNodes(element);
- name.split(" ").forEach(function(name) {
- return element.forEach(function(element) {
- return element.removeAttribute(name);
- });
- });
- }
- function filterAttr(element, attribute, pattern, replacement) {
- attr(element, attribute, function(value) {
- return value ? value.replace(pattern, replacement) : value;
- });
- }
- function data(element, attribute) {
- for (var i = 0, attrs = [ attribute, "data-" + attribute ]; i < attrs.length; i++) {
- if (hasAttr(element, attrs[i])) {
- return attr(element, attrs[i]);
- }
- }
- }
- function query(selector, context) {
- return toNode(selector) || find(selector, isContextSelector(selector) ? context : document);
- }
- function queryAll(selector, context) {
- var nodes = toNodes(selector);
- return nodes.length && nodes || findAll(selector, isContextSelector(selector) ? context : document);
- }
- function find(selector, context) {
- return toNode(_query(selector, context, "querySelector"));
- }
- function findAll(selector, context) {
- return toNodes(_query(selector, context, "querySelectorAll"));
- }
- function _query(selector, context, queryFn) {
- if (context === void 0) context = document;
- if (!selector || !isString(selector)) {
- return null;
- }
- selector = selector.replace(contextSanitizeRe, "$1 *");
- var removes;
- if (isContextSelector(selector)) {
- removes = [];
- selector = selector.split(",").map(function(selector, i) {
- var ctx = context;
- selector = selector.trim();
- if (selector[0] === "!") {
- var selectors = selector.substr(1).trim().split(" ");
- ctx = closest(context.parentNode, selectors[0]);
- selector = selectors.slice(1).join(" ");
- }
- if (!ctx) {
- return null;
- }
- if (!ctx.id) {
- ctx.id = "uk-" + Date.now() + i;
- removes.push(function() {
- return removeAttr(ctx, "id");
- });
- }
- return "#" + escape(ctx.id) + " " + selector;
- }).filter(Boolean).join(",");
- context = document;
- }
- try {
- return context[queryFn](selector);
- } catch (e) {
- return null;
- } finally {
- removes && removes.forEach(function(remove) {
- return remove();
- });
- }
- }
- var contextSelectorRe = /(^|,)\s*[!>+~]/;
- var contextSanitizeRe = /([!>+~])(?=\s+[!>+~]|\s*$)/g;
- function isContextSelector(selector) {
- return isString(selector) && selector.match(contextSelectorRe);
- }
- var elProto = Element.prototype;
- var matchesFn = elProto.matches || elProto.webkitMatchesSelector || elProto.msMatchesSelector;
- function matches(element, selector) {
- return toNodes(element).some(function(element) {
- return matchesFn.call(element, selector);
- });
- }
- var closestFn = elProto.closest || function(selector) {
- var ancestor = this;
- do {
- if (matches(ancestor, selector)) {
- return ancestor;
- }
- ancestor = ancestor.parentNode;
- } while (ancestor && ancestor.nodeType === 1);
- };
- function closest(element, selector) {
- if (startsWith(selector, ">")) {
- selector = selector.slice(1);
- }
- return isNode(element) ? element.parentNode && closestFn.call(element, selector) : toNodes(element).map(function(element) {
- return element.parentNode && closestFn.call(element, selector);
- }).filter(Boolean);
- }
- function parents(element, selector) {
- var elements = [];
- var parent = toNode(element).parentNode;
- while (parent && parent.nodeType === 1) {
- if (matches(parent, selector)) {
- elements.push(parent);
- }
- parent = parent.parentNode;
- }
- return elements;
- }
- var escapeFn = window.CSS && CSS.escape || function(css) {
- return css.replace(/([^\x7f-\uFFFF\w-])/g, function(match) {
- return "\\" + match;
- });
- };
- function escape(css) {
- return isString(css) ? escapeFn.call(null, css) : "";
- }
- var voidElements = {
- area: true,
- base: true,
- br: true,
- col: true,
- embed: true,
- hr: true,
- img: true,
- input: true,
- keygen: true,
- link: true,
- menuitem: true,
- meta: true,
- param: true,
- source: true,
- track: true,
- wbr: true
- };
- function isVoidElement(element) {
- return toNodes(element).some(function(element) {
- return voidElements[element.tagName.toLowerCase()];
- });
- }
- function isVisible(element) {
- return toNodes(element).some(function(element) {
- return element.offsetHeight || element.getBoundingClientRect().height;
- });
- }
- var selInput = "input,select,textarea,button";
- function isInput(element) {
- return toNodes(element).some(function(element) {
- return matches(element, selInput);
- });
- }
- function filter(element, selector) {
- return toNodes(element).filter(function(element) {
- return matches(element, selector);
- });
- }
- function within(element, selector) {
- return !isString(selector) ? element === selector || (isDocument(selector) ? selector.documentElement : toNode(selector)).contains(toNode(element)) : matches(element, selector) || closest(element, selector);
- }
- function on() {
- var args = [], len = arguments.length;
- while (len--) args[len] = arguments[len];
- var ref = getArgs(args);
- var target = ref[0];
- var type = ref[1];
- var selector = ref[2];
- var listener = ref[3];
- var useCapture = ref[4];
- target = toEventTarget(target);
- if (selector) {
- listener = delegate(target, selector, listener);
- }
- if (listener.length > 1) {
- listener = detail(listener);
- }
- type.split(" ").forEach(function(type) {
- return target && target.addEventListener(type, listener, useCapture);
- });
- return function() {
- return off(target, type, listener, useCapture);
- };
- }
- function off(target, type, listener, useCapture) {
- if (useCapture === void 0) useCapture = false;
- target = toEventTarget(target);
- target && type.split(" ").forEach(function(type) {
- return target.removeEventListener(type, listener, useCapture);
- });
- }
- function once() {
- var args = [], len = arguments.length;
- while (len--) args[len] = arguments[len];
- var ref = getArgs(args);
- var element = ref[0];
- var type = ref[1];
- var selector = ref[2];
- var listener = ref[3];
- var useCapture = ref[4];
- var condition = ref[5];
- var off = on(element, type, selector, function(e) {
- var result = !condition || condition(e);
- if (result) {
- off();
- listener(e, result);
- }
- }, useCapture);
- return off;
- }
- function trigger(target, event, detail) {
- return toEventTargets(target).reduce(function(notCanceled, target) {
- return notCanceled && target.dispatchEvent(createEvent(event, true, true, detail));
- }, true);
- }
- function createEvent(e, bubbles, cancelable, detail) {
- if (bubbles === void 0) bubbles = true;
- if (cancelable === void 0) cancelable = false;
- if (isString(e)) {
- var event = document.createEvent("CustomEvent");
- event.initCustomEvent(e, bubbles, cancelable, detail);
- e = event;
- }
- return e;
- }
- function getArgs(args) {
- if (isString(args[0])) {
- args[0] = find(args[0]);
- }
- if (isFunction(args[2])) {
- args.splice(2, 0, false);
- }
- return args;
- }
- function delegate(element, selector, listener) {
- var this$1 = this;
- return function(e) {
- var target = e.target;
- var current = selector[0] === ">" ? findAll(selector, element).reverse().filter(function(element) {
- return within(target, element);
- })[0] : closest(target, selector);
- if (current) {
- e.delegate = element;
- e.current = current;
- listener.call(this$1, e);
- }
- };
- }
- function detail(listener) {
- return function(e) {
- return isArray(e.detail) ? listener.apply(listener, [ e ].concat(e.detail)) : listener(e);
- };
- }
- function isEventTarget(target) {
- return "EventTarget" in window ? target instanceof EventTarget : target && "addEventListener" in target;
- }
- function toEventTarget(target) {
- return isEventTarget(target) ? target : toNode(target);
- }
- function toEventTargets(target) {
- return isEventTarget(target) ? [ target ] : isArray(target) ? target.map(toEventTarget).filter(Boolean) : toNodes(target);
- }
- function preventClick() {
- var timer = setTimeout(once(document, "click", function(e) {
- e.preventDefault();
- e.stopImmediatePropagation();
- clearTimeout(timer);
- }, true));
- trigger(document, "touchcancel");
- }
- var Promise = "Promise" in window ? window.Promise : PromiseFn;
- var Deferred = function Deferred() {
- var this$1 = this;
- this.promise = new Promise(function(resolve, reject) {
- this$1.reject = reject;
- this$1.resolve = resolve;
- });
- };
- var RESOLVED = 0;
- var REJECTED = 1;
- var PENDING = 2;
- var async = "setImmediate" in window ? setImmediate : setTimeout;
- function PromiseFn(executor) {
- this.state = PENDING;
- this.value = undefined;
- this.deferred = [];
- var promise = this;
- try {
- executor(function(x) {
- promise.resolve(x);
- }, function(r) {
- promise.reject(r);
- });
- } catch (e) {
- promise.reject(e);
- }
- }
- PromiseFn.reject = function(r) {
- return new PromiseFn(function(resolve, reject) {
- reject(r);
- });
- };
- PromiseFn.resolve = function(x) {
- return new PromiseFn(function(resolve, reject) {
- resolve(x);
- });
- };
- PromiseFn.all = function all(iterable) {
- return new PromiseFn(function(resolve, reject) {
- var result = [];
- var count = 0;
- if (iterable.length === 0) {
- resolve(result);
- }
- function resolver(i) {
- return function(x) {
- result[i] = x;
- count += 1;
- if (count === iterable.length) {
- resolve(result);
- }
- };
- }
- for (var i = 0; i < iterable.length; i += 1) {
- PromiseFn.resolve(iterable[i]).then(resolver(i), reject);
- }
- });
- };
- PromiseFn.race = function race(iterable) {
- return new PromiseFn(function(resolve, reject) {
- for (var i = 0; i < iterable.length; i += 1) {
- PromiseFn.resolve(iterable[i]).then(resolve, reject);
- }
- });
- };
- var p = PromiseFn.prototype;
- p.resolve = function resolve(x) {
- var promise = this;
- if (promise.state === PENDING) {
- if (x === promise) {
- throw new TypeError("Promise settled with itself.");
- }
- var called = false;
- try {
- var then = x && x.then;
- if (x !== null && isObject(x) && isFunction(then)) {
- then.call(x, function(x) {
- if (!called) {
- promise.resolve(x);
- }
- called = true;
- }, function(r) {
- if (!called) {
- promise.reject(r);
- }
- called = true;
- });
- return;
- }
- } catch (e) {
- if (!called) {
- promise.reject(e);
- }
- return;
- }
- promise.state = RESOLVED;
- promise.value = x;
- promise.notify();
- }
- };
- p.reject = function reject(reason) {
- var promise = this;
- if (promise.state === PENDING) {
- if (reason === promise) {
- throw new TypeError("Promise settled with itself.");
- }
- promise.state = REJECTED;
- promise.value = reason;
- promise.notify();
- }
- };
- p.notify = function notify() {
- var this$1 = this;
- async(function() {
- if (this$1.state !== PENDING) {
- while (this$1.deferred.length) {
- var ref = this$1.deferred.shift();
- var onResolved = ref[0];
- var onRejected = ref[1];
- var resolve = ref[2];
- var reject = ref[3];
- try {
- if (this$1.state === RESOLVED) {
- if (isFunction(onResolved)) {
- resolve(onResolved.call(undefined, this$1.value));
- } else {
- resolve(this$1.value);
- }
- } else if (this$1.state === REJECTED) {
- if (isFunction(onRejected)) {
- resolve(onRejected.call(undefined, this$1.value));
- } else {
- reject(this$1.value);
- }
- }
- } catch (e) {
- reject(e);
- }
- }
- }
- });
- };
- p.then = function then(onResolved, onRejected) {
- var this$1 = this;
- return new PromiseFn(function(resolve, reject) {
- this$1.deferred.push([ onResolved, onRejected, resolve, reject ]);
- this$1.notify();
- });
- };
- p.catch = function(onRejected) {
- return this.then(undefined, onRejected);
- };
- function ajax(url, options) {
- return new Promise(function(resolve, reject) {
- var env = assign({
- data: null,
- method: "GET",
- headers: {},
- xhr: new XMLHttpRequest(),
- beforeSend: noop,
- responseType: ""
- }, options);
- env.beforeSend(env);
- var xhr = env.xhr;
- for (var prop in env) {
- if (prop in xhr) {
- try {
- xhr[prop] = env[prop];
- } catch (e) {}
- }
- }
- xhr.open(env.method.toUpperCase(), url);
- for (var header in env.headers) {
- xhr.setRequestHeader(header, env.headers[header]);
- }
- on(xhr, "load", function() {
- if (xhr.status === 0 || xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) {
- resolve(xhr);
- } else {
- reject(assign(Error(xhr.statusText), {
- xhr: xhr,
- status: xhr.status
- }));
- }
- });
- on(xhr, "error", function() {
- return reject(assign(Error("Network Error"), {
- xhr: xhr
- }));
- });
- on(xhr, "timeout", function() {
- return reject(assign(Error("Network Timeout"), {
- xhr: xhr
- }));
- });
- xhr.send(env.data);
- });
- }
- function getImage(src) {
- return new Promise(function(resolve, reject) {
- var img = new Image();
- img.onerror = reject;
- img.onload = function() {
- return resolve(img);
- };
- img.src = src;
- });
- }
- function isReady() {
- return document.readyState === "complete" || document.readyState !== "loading" && !document.documentElement.doScroll;
- }
- function ready(fn) {
- if (isReady()) {
- fn();
- return;
- }
- var handle = function() {
- unbind1();
- unbind2();
- fn();
- };
- var unbind1 = on(document, "DOMContentLoaded", handle);
- var unbind2 = on(window, "load", handle);
- }
- function index(element, ref) {
- return ref ? toNodes(element).indexOf(toNode(ref)) : toNodes((element = toNode(element)) && element.parentNode.children).indexOf(element);
- }
- function getIndex(i, elements, current, finite) {
- if (current === void 0) current = 0;
- if (finite === void 0) finite = false;
- elements = toNodes(elements);
- var length = elements.length;
- i = isNumeric(i) ? toNumber(i) : i === "next" ? current + 1 : i === "previous" ? current - 1 : index(elements, i);
- if (finite) {
- return clamp(i, 0, length - 1);
- }
- i %= length;
- return i < 0 ? i + length : i;
- }
- function empty(element) {
- element = toNode(element);
- element.innerHTML = "";
- return element;
- }
- function html(parent, html) {
- parent = toNode(parent);
- return isUndefined(html) ? parent.innerHTML : append(parent.hasChildNodes() ? empty(parent) : parent, html);
- }
- function prepend(parent, element) {
- parent = toNode(parent);
- if (!parent.hasChildNodes()) {
- return append(parent, element);
- } else {
- return insertNodes(element, function(element) {
- return parent.insertBefore(element, parent.firstChild);
- });
- }
- }
- function append(parent, element) {
- parent = toNode(parent);
- return insertNodes(element, function(element) {
- return parent.appendChild(element);
- });
- }
- function before(ref, element) {
- ref = toNode(ref);
- return insertNodes(element, function(element) {
- return ref.parentNode.insertBefore(element, ref);
- });
- }
- function after(ref, element) {
- ref = toNode(ref);
- return insertNodes(element, function(element) {
- return ref.nextSibling ? before(ref.nextSibling, element) : append(ref.parentNode, element);
- });
- }
- function insertNodes(element, fn) {
- element = isString(element) ? fragment(element) : element;
- return element ? "length" in element ? toNodes(element).map(fn) : fn(element) : null;
- }
- function remove(element) {
- toNodes(element).map(function(element) {
- return element.parentNode && element.parentNode.removeChild(element);
- });
- }
- function wrapAll(element, structure) {
- structure = toNode(before(element, structure));
- while (structure.firstChild) {
- structure = structure.firstChild;
- }
- append(structure, element);
- return structure;
- }
- function wrapInner(element, structure) {
- return toNodes(toNodes(element).map(function(element) {
- return element.hasChildNodes ? wrapAll(toNodes(element.childNodes), structure) : append(element, structure);
- }));
- }
- function unwrap(element) {
- toNodes(element).map(function(element) {
- return element.parentNode;
- }).filter(function(value, index, self) {
- return self.indexOf(value) === index;
- }).forEach(function(parent) {
- before(parent, parent.childNodes);
- remove(parent);
- });
- }
- var fragmentRE = /^\s*<(\w+|!)[^>]*>/;
- var singleTagRE = /^<(\w+)\s*\/?>(?:<\/\1>)?$/;
- function fragment(html) {
- var matches = singleTagRE.exec(html);
- if (matches) {
- return document.createElement(matches[1]);
- }
- var container = document.createElement("div");
- if (fragmentRE.test(html)) {
- container.insertAdjacentHTML("beforeend", html.trim());
- } else {
- container.textContent = html;
- }
- return container.childNodes.length > 1 ? toNodes(container.childNodes) : container.firstChild;
- }
- function apply(node, fn) {
- if (!node || node.nodeType !== 1) {
- return;
- }
- fn(node);
- node = node.firstElementChild;
- while (node) {
- apply(node, fn);
- node = node.nextElementSibling;
- }
- }
- function addClass(element) {
- var args = [], len = arguments.length - 1;
- while (len-- > 0) args[len] = arguments[len + 1];
- apply$1(element, args, "add");
- }
- function removeClass(element) {
- var args = [], len = arguments.length - 1;
- while (len-- > 0) args[len] = arguments[len + 1];
- apply$1(element, args, "remove");
- }
- function removeClasses(element, cls) {
- filterAttr(element, "class", new RegExp("(^|\\s)" + cls + "(?!\\S)", "g"), "");
- }
- function replaceClass(element) {
- var args = [], len = arguments.length - 1;
- while (len-- > 0) args[len] = arguments[len + 1];
- args[0] && removeClass(element, args[0]);
- args[1] && addClass(element, args[1]);
- }
- function hasClass(element, cls) {
- return toNodes(element).some(function(element) {
- return element.classList.contains(cls);
- });
- }
- function toggleClass(element) {
- var args = [], len = arguments.length - 1;
- while (len-- > 0) args[len] = arguments[len + 1];
- if (!args.length) {
- return;
- }
- args = getArgs$1(args);
- var force = !isString(args[args.length - 1]) ? args.pop() : [];
- args = args.filter(Boolean);
- toNodes(element).forEach(function(ref) {
- var classList = ref.classList;
- for (var i = 0; i < args.length; i++) {
- supports.Force ? classList.toggle.apply(classList, [ args[i] ].concat(force)) : classList[(!isUndefined(force) ? force : !classList.contains(args[i])) ? "add" : "remove"](args[i]);
- }
- });
- }
- function apply$1(element, args, fn) {
- args = getArgs$1(args).filter(Boolean);
- args.length && toNodes(element).forEach(function(ref) {
- var classList = ref.classList;
- supports.Multiple ? classList[fn].apply(classList, args) : args.forEach(function(cls) {
- return classList[fn](cls);
- });
- });
- }
- function getArgs$1(args) {
- return args.reduce(function(args, arg) {
- return args.concat.call(args, isString(arg) && includes(arg, " ") ? arg.trim().split(" ") : arg);
- }, []);
- }
- var supports = {};
- (function() {
- var list = document.createElement("_").classList;
- if (list) {
- list.add("a", "b");
- list.toggle("c", false);
- supports.Multiple = list.contains("b");
- supports.Force = !list.contains("c");
- }
- list = null;
- })();
- var cssNumber = {
- "animation-iteration-count": true,
- "column-count": true,
- "fill-opacity": true,
- "flex-grow": true,
- "flex-shrink": true,
- "font-weight": true,
- "line-height": true,
- opacity: true,
- order: true,
- orphans: true,
- widows: true,
- "z-index": true,
- zoom: true
- };
- function css(element, property, value) {
- return toNodes(element).map(function(element) {
- if (isString(property)) {
- property = propName(property);
- if (isUndefined(value)) {
- return getStyle(element, property);
- } else if (!value && value !== 0) {
- element.style.removeProperty(property);
- } else {
- element.style[property] = isNumeric(value) && !cssNumber[property] ? value + "px" : value;
- }
- } else if (isArray(property)) {
- var styles = getStyles(element);
- return property.reduce(function(props, property) {
- props[property] = styles[propName(property)];
- return props;
- }, {});
- } else if (isObject(property)) {
- each(property, function(value, property) {
- return css(element, property, value);
- });
- }
- return element;
- })[0];
- }
- function getStyles(element, pseudoElt) {
- element = toNode(element);
- return element.ownerDocument.defaultView.getComputedStyle(element, pseudoElt);
- }
- function getStyle(element, property, pseudoElt) {
- return getStyles(element, pseudoElt)[property];
- }
- var vars = {};
- function getCssVar(name) {
- if (!(name in vars)) {
- var element = append(document.documentElement, document.createElement("div"));
- addClass(element, "var-" + name);
- try {
- vars[name] = getStyle(element, "content", ":before").replace(/^["'](.*)["']$/, "$1");
- vars[name] = JSON.parse(vars[name]);
- } catch (e) {}
- document.documentElement.removeChild(element);
- }
- return vars[name];
- }
- var cssProps = {};
- function propName(name) {
- var ret = cssProps[name];
- if (!ret) {
- ret = cssProps[name] = vendorPropName(name) || name;
- }
- return ret;
- }
- var cssPrefixes = [ "webkit", "moz", "ms" ];
- var ref$1 = document.createElement("_");
- var style = ref$1.style;
- function vendorPropName(name) {
- name = hyphenate(name);
- if (name in style) {
- return name;
- }
- var i = cssPrefixes.length, prefixedName;
- while (i--) {
- prefixedName = "-" + cssPrefixes[i] + "-" + name;
- if (prefixedName in style) {
- return prefixedName;
- }
- }
- }
- function transition(element, props, duration, timing) {
- if (duration === void 0) duration = 400;
- if (timing === void 0) timing = "linear";
- return Promise.all(toNodes(element).map(function(element) {
- return new Promise(function(resolve, reject) {
- for (var name in props) {
- var value = css(element, name);
- if (value === "") {
- css(element, name, value);
- }
- }
- var timer = setTimeout(function() {
- return trigger(element, "transitionend");
- }, duration);
- once(element, "transitionend transitioncanceled", function(ref) {
- var type = ref.type;
- clearTimeout(timer);
- removeClass(element, "uk-transition");
- css(element, {
- "transition-property": "",
- "transition-duration": "",
- "transition-timing-function": ""
- });
- type === "transitioncanceled" ? reject() : resolve();
- }, false, function(ref) {
- var target = ref.target;
- return element === target;
- });
- addClass(element, "uk-transition");
- css(element, assign({
- "transition-property": Object.keys(props).map(propName).join(","),
- "transition-duration": duration + "ms",
- "transition-timing-function": timing
- }, props));
- });
- }));
- }
- var Transition = {
- start: transition,
- stop: function stop(element) {
- trigger(element, "transitionend");
- return Promise.resolve();
- },
- cancel: function cancel(element) {
- trigger(element, "transitioncanceled");
- },
- inProgress: function inProgress(element) {
- return hasClass(element, "uk-transition");
- }
- };
- var animationPrefix = "uk-animation-";
- var clsCancelAnimation = "uk-cancel-animation";
- function animate(element, animation, duration, origin, out) {
- var arguments$1 = arguments;
- if (duration === void 0) duration = 200;
- return Promise.all(toNodes(element).map(function(element) {
- return new Promise(function(resolve, reject) {
- if (hasClass(element, clsCancelAnimation)) {
- requestAnimationFrame(function() {
- return Promise.resolve().then(function() {
- return animate.apply(void 0, arguments$1).then(resolve, reject);
- });
- });
- return;
- }
- var cls = animation + " " + animationPrefix + (out ? "leave" : "enter");
- if (startsWith(animation, animationPrefix)) {
- if (origin) {
- cls += " uk-transform-origin-" + origin;
- }
- if (out) {
- cls += " " + animationPrefix + "reverse";
- }
- }
- reset();
- once(element, "animationend animationcancel", function(ref) {
- var type = ref.type;
- var hasReset = false;
- if (type === "animationcancel") {
- reject();
- reset();
- } else {
- resolve();
- Promise.resolve().then(function() {
- hasReset = true;
- reset();
- });
- }
- requestAnimationFrame(function() {
- if (!hasReset) {
- addClass(element, clsCancelAnimation);
- requestAnimationFrame(function() {
- return removeClass(element, clsCancelAnimation);
- });
- }
- });
- }, false, function(ref) {
- var target = ref.target;
- return element === target;
- });
- css(element, "animationDuration", duration + "ms");
- addClass(element, cls);
- function reset() {
- css(element, "animationDuration", "");
- removeClasses(element, animationPrefix + "\\S*");
- }
- });
- }));
- }
- var inProgress = new RegExp(animationPrefix + "(enter|leave)");
- var Animation = {
- in: function in$1(element, animation, duration, origin) {
- return animate(element, animation, duration, origin, false);
- },
- out: function out(element, animation, duration, origin) {
- return animate(element, animation, duration, origin, true);
- },
- inProgress: function inProgress$1(element) {
- return inProgress.test(attr(element, "class"));
- },
- cancel: function cancel(element) {
- trigger(element, "animationcancel");
- }
- };
- function $(selector, context) {
- return !isString(selector) ? toNode(selector) : isHtml(selector) ? toNode(fragment(selector)) : find(selector, context);
- }
- function $$(selector, context) {
- return !isString(selector) ? toNodes(selector) : isHtml(selector) ? toNodes(fragment(selector)) : findAll(selector, context);
- }
- function isHtml(str) {
- return str[0] === "<" || str.match(/^\s*);
- }
- var dirs = {
- width: [ "x", "left", "right" ],
- height: [ "y", "top", "bottom" ]
- };
- function positionAt(element, target, elAttach, targetAttach, elOffset, targetOffset, flip, boundary) {
- elAttach = getPos(elAttach);
- targetAttach = getPos(targetAttach);
- var flipped = {
- element: elAttach,
- target: targetAttach
- };
- if (!element || !target) {
- return flipped;
- }
- var dim = getDimensions(element);
- var targetDim = getDimensions(target);
- var position = targetDim;
- moveTo(position, elAttach, dim, -1);
- moveTo(position, targetAttach, targetDim, 1);
- elOffset = getOffsets(elOffset, dim.width, dim.height);
- targetOffset = getOffsets(targetOffset, targetDim.width, targetDim.height);
- elOffset["x"] += targetOffset["x"];
- elOffset["y"] += targetOffset["y"];
- position.left += elOffset["x"];
- position.top += elOffset["y"];
- boundary = getDimensions(boundary || window$1(element));
- if (flip) {
- each(dirs, function(ref, prop) {
- var dir = ref[0];
- var align = ref[1];
- var alignFlip = ref[2];
- if (!(flip === true || includes(flip, dir))) {
- return;
- }
- var elemOffset = elAttach[dir] === align ? -dim[prop] : elAttach[dir] === alignFlip ? dim[prop] : 0;
- var targetOffset = targetAttach[dir] === align ? targetDim[prop] : targetAttach[dir] === alignFlip ? -targetDim[prop] : 0;
- if (position[align] < boundary[align] || position[align] + dim[prop] > boundary[alignFlip]) {
- var centerOffset = dim[prop] / 2;
- var centerTargetOffset = targetAttach[dir] === "center" ? -targetDim[prop] / 2 : 0;
- elAttach[dir] === "center" && (apply(centerOffset, centerTargetOffset) || apply(-centerOffset, -centerTargetOffset)) || apply(elemOffset, targetOffset);
- }
- function apply(elemOffset, targetOffset) {
- var newVal = position[align] + elemOffset + targetOffset - elOffset[dir] * 2;
- if (newVal >= boundary[align] && newVal + dim[prop] <= boundary[alignFlip]) {
- position[align] = newVal;
- [ "element", "target" ].forEach(function(el) {
- flipped[el][dir] = !elemOffset ? flipped[el][dir] : flipped[el][dir] === dirs[prop][1] ? dirs[prop][2] : dirs[prop][1];
- });
- return true;
- }
- }
- });
- }
- offset(element, position);
- return flipped;
- }
- function offset(element, coordinates) {
- element = toNode(element);
- if (coordinates) {
- var currentOffset = offset(element);
- var pos = css(element, "position");
- [ "left", "top" ].forEach(function(prop) {
- if (prop in coordinates) {
- var value = css(element, prop);
- element.style[prop] = coordinates[prop] - currentOffset[prop] + toFloat(pos === "absolute" && value === "auto" ? position(element)[prop] : value) + "px";
- }
- });
- return;
- }
- return getDimensions(element);
- }
- function getDimensions(element) {
- element = toNode(element);
- var ref = window$1(element);
- var top = ref.pageYOffset;
- var left = ref.pageXOffset;
- if (isWindow(element)) {
- var height = element.innerHeight;
- var width = element.innerWidth;
- return {
- top: top,
- left: left,
- height: height,
- width: width,
- bottom: top + height,
- right: left + width
- };
- }
- var display = false;
- if (!isVisible(element)) {
- display = element.style.display;
- element.style.display = "block";
- }
- var rect = element.getBoundingClientRect();
- if (display !== false) {
- element.style.display = display;
- }
- return {
- height: rect.height,
- width: rect.width,
- top: rect.top + top,
- left: rect.left + left,
- bottom: rect.bottom + top,
- right: rect.right + left
- };
- }
- function position(element) {
- element = toNode(element);
- var parent = offsetParent(element);
- var parentOffset = parent === docEl(element) ? {
- top: 0,
- left: 0
- } : offset(parent);
- var ref = [ "top", "left" ].reduce(function(props, prop) {
- var propName$$1 = ucfirst(prop);
- props[prop] -= parentOffset[prop] + (toFloat(css(element, "margin" + propName$$1)) || 0) + (toFloat(css(parent, "border" + propName$$1 + "Width")) || 0);
- return props;
- }, offset(element));
- var top = ref.top;
- var left = ref.left;
- return {
- top: top,
- left: left
- };
- }
- function offsetParent(element) {
- var parent = toNode(element).offsetParent;
- while (parent && css(parent, "position") === "static") {
- parent = parent.offsetParent;
- }
- return parent || docEl(element);
- }
- var height = dimension("height");
- var width = dimension("width");
- function dimension(prop) {
- var propName$$1 = ucfirst(prop);
- return function(element, value) {
- element = toNode(element);
- if (isUndefined(value)) {
- if (isWindow(element)) {
- return element["inner" + propName$$1];
- }
- if (isDocument(element)) {
- var doc = element.documentElement;
- return Math.max(doc["offset" + propName$$1], doc["scroll" + propName$$1]);
- }
- value = css(element, prop);
- value = value === "auto" ? element["offset" + propName$$1] : toFloat(value) || 0;
- return value - boxModelAdjust(prop, element);
- } else {
- css(element, prop, !value && value !== 0 ? "" : +value + boxModelAdjust(prop, element) + "px");
- }
- };
- }
- function boxModelAdjust(prop, element) {
- return css(element, "boxSizing") === "border-box" ? dirs[prop].slice(1).map(ucfirst).reduce(function(value, prop) {
- return value + toFloat(css(element, "padding" + prop)) + toFloat(css(element, "border" + prop + "Width"));
- }, 0) : 0;
- }
- function moveTo(position, attach, dim, factor) {
- each(dirs, function(ref, prop) {
- var dir = ref[0];
- var align = ref[1];
- var alignFlip = ref[2];
- if (attach[dir] === alignFlip) {
- position[align] += dim[prop] * factor;
- } else if (attach[dir] === "center") {
- position[align] += dim[prop] * factor / 2;
- }
- });
- }
- function getPos(pos) {
- var x = /left|center|right/;
- var y = /top|center|bottom/;
- pos = (pos || "").split(" ");
- if (pos.length === 1) {
- pos = x.test(pos[0]) ? pos.concat([ "center" ]) : y.test(pos[0]) ? [ "center" ].concat(pos) : [ "center", "center" ];
- }
- return {
- x: x.test(pos[0]) ? pos[0] : "center",
- y: y.test(pos[1]) ? pos[1] : "center"
- };
- }
- function getOffsets(offsets, width, height) {
- var ref = (offsets || "").split(" ");
- var x = ref[0];
- var y = ref[1];
- return {
- x: x ? toFloat(x) * (endsWith(x, "%") ? width / 100 : 1) : 0,
- y: y ? toFloat(y) * (endsWith(y, "%") ? height / 100 : 1) : 0
- };
- }
- function flipPosition(pos) {
- switch (pos) {
- case "left":
- return "right";
-
- case "right":
- return "left";
-
- case "top":
- return "bottom";
-
- case "bottom":
- return "top";
-
- default:
- return pos;
- }
- }
- function isInView(element, top, left) {
- if (top === void 0) top = 0;
- if (left === void 0) left = 0;
- element = toNode(element);
- var win = window$1(element);
- return isVisible(element) && intersectRect(element.getBoundingClientRect(), {
- top: top,
- left: left,
- bottom: top + height(win),
- right: left + width(win)
- });
- }
- function scrolledOver(element) {
- if (!isVisible(element)) {
- return 0;
- }
- element = toNode(element);
- var win = window$1(element);
- var doc = document$1(element);
- var elHeight = element.offsetHeight;
- var top = positionTop(element);
- var vp = height(win);
- var vh = vp + Math.min(0, top - vp);
- var diff = Math.max(0, vp - (height(doc) - (top + elHeight)));
- return clamp((vh + win.pageYOffset - top) / ((vh + (elHeight - (diff < vp ? diff : 0))) / 100) / 100);
- }
- function positionTop(element) {
- var top = 0;
- do {
- top += element.offsetTop;
- } while (element = element.offsetParent);
- return top;
- }
- function window$1(element) {
- return isWindow(element) ? element : document$1(element).defaultView;
- }
- function document$1(element) {
- return toNode(element).ownerDocument;
- }
- function docEl(element) {
- return document$1(element).documentElement;
- }
- var isRtl = attr(document.documentElement, "dir") === "rtl";
- var hasTouchEvents = "ontouchstart" in window;
- var hasPointerEvents = window.PointerEvent;
- var hasTouch = hasTouchEvents || window.DocumentTouch && document instanceof DocumentTouch || navigator.maxTouchPoints;
- var pointerDown = !hasTouch ? "mousedown" : "mousedown " + (hasTouchEvents ? "touchstart" : "pointerdown");
- var pointerMove = !hasTouch ? "mousemove" : "mousemove " + (hasTouchEvents ? "touchmove" : "pointermove");
- var pointerUp = !hasTouch ? "mouseup" : "mouseup " + (hasTouchEvents ? "touchend" : "pointerup");
- var pointerEnter = hasTouch && hasPointerEvents ? "pointerenter" : "mouseenter";
- var pointerLeave = hasTouch && hasPointerEvents ? "pointerleave" : "mouseleave";
- var fastdom = {
- reads: [],
- writes: [],
- read: function read(task) {
- this.reads.push(task);
- scheduleFlush();
- return task;
- },
- write: function write(task) {
- this.writes.push(task);
- scheduleFlush();
- return task;
- },
- clear: function clear(task) {
- return remove$1(this.reads, task) || remove$1(this.writes, task);
- },
- flush: function flush() {
- runTasks(this.reads);
- runTasks(this.writes.splice(0, this.writes.length));
- this.scheduled = false;
- if (this.reads.length || this.writes.length) {
- scheduleFlush();
- }
- }
- };
- function scheduleFlush() {
- if (!fastdom.scheduled) {
- fastdom.scheduled = true;
- requestAnimationFrame(fastdom.flush.bind(fastdom));
- }
- }
- function runTasks(tasks) {
- var task;
- while (task = tasks.shift()) {
- task();
- }
- }
- function remove$1(array, item) {
- var index = array.indexOf(item);
- return !!~index && !!array.splice(index, 1);
- }
- function MouseTracker() {}
- MouseTracker.prototype = {
- positions: [],
- position: null,
- init: function init() {
- var this$1 = this;
- this.positions = [];
- this.position = null;
- var ticking = false;
- this.unbind = on(document, "mousemove", function(e) {
- if (ticking) {
- return;
- }
- setTimeout(function() {
- var time = Date.now();
- var ref = this$1.positions;
- var length = ref.length;
- if (length && time - this$1.positions[length - 1].time > 100) {
- this$1.positions.splice(0, length);
- }
- this$1.positions.push({
- time: time,
- x: e.pageX,
- y: e.pageY
- });
- if (this$1.positions.length > 5) {
- this$1.positions.shift();
- }
- ticking = false;
- }, 5);
- ticking = true;
- });
- },
- cancel: function cancel() {
- if (this.unbind) {
- this.unbind();
- }
- },
- movesTo: function movesTo(target) {
- if (this.positions.length < 2) {
- return false;
- }
- var p = offset(target);
- var position$$1 = this.positions[this.positions.length - 1];
- var ref = this.positions;
- var prevPos = ref[0];
- if (p.left <= position$$1.x && position$$1.x <= p.right && p.top <= position$$1.y && position$$1.y <= p.bottom) {
- return false;
- }
- var points = [ [ {
- x: p.left,
- y: p.top
- }, {
- x: p.right,
- y: p.bottom
- } ], [ {
- x: p.right,
- y: p.top
- }, {
- x: p.left,
- y: p.bottom
- } ] ];
- if (p.right <= position$$1.x) {} else if (p.left >= position$$1.x) {
- points[0].reverse();
- points[1].reverse();
- } else if (p.bottom <= position$$1.y) {
- points[0].reverse();
- } else if (p.top >= position$$1.y) {
- points[1].reverse();
- }
- return !!points.reduce(function(result, point) {
- return result + (slope(prevPos, point[0]) < slope(position$$1, point[0]) && slope(prevPos, point[1]) > slope(position$$1, point[1]));
- }, 0);
- }
- };
- function slope(a, b) {
- return (b.y - a.y) / (b.x - a.x);
- }
- var strats = {};
- strats.args = strats.events = strats.init = strats.created = strats.beforeConnect = strats.connected = strats.ready = strats.beforeDisconnect = strats.disconnected = strats.destroy = function(parentVal, childVal) {
- parentVal = parentVal && !isArray(parentVal) ? [ parentVal ] : parentVal;
- return childVal ? parentVal ? parentVal.concat(childVal) : isArray(childVal) ? childVal : [ childVal ] : parentVal;
- };
- strats.update = function(parentVal, childVal) {
- return strats.args(parentVal, isFunction(childVal) ? {
- read: childVal
- } : childVal);
- };
- strats.props = function(parentVal, childVal) {
- if (isArray(childVal)) {
- childVal = childVal.reduce(function(value, key) {
- value[key] = String;
- return value;
- }, {});
- }
- return strats.methods(parentVal, childVal);
- };
- strats.computed = strats.defaults = strats.methods = function(parentVal, childVal) {
- return childVal ? parentVal ? assign({}, parentVal, childVal) : childVal : parentVal;
- };
- var defaultStrat = function(parentVal, childVal) {
- return isUndefined(childVal) ? parentVal : childVal;
- };
- function mergeOptions(parent, child) {
- var options = {};
- if (child.mixins) {
- for (var i = 0, l = child.mixins.length; i < l; i++) {
- parent = mergeOptions(parent, child.mixins[i]);
- }
- }
- for (var key in parent) {
- mergeKey(key);
- }
- for (var key$1 in child) {
- if (!hasOwn(parent, key$1)) {
- mergeKey(key$1);
- }
- }
- function mergeKey(key) {
- options[key] = (strats[key] || defaultStrat)(parent[key], child[key]);
- }
- return options;
- }
- var id = 0;
- var Player = function Player(el) {
- this.id = ++id;
- this.el = toNode(el);
- };
- Player.prototype.isVideo = function isVideo() {
- return this.isYoutube() || this.isVimeo() || this.isHTML5();
- };
- Player.prototype.isHTML5 = function isHTML5() {
- return this.el.tagName === "VIDEO";
- };
- Player.prototype.isIFrame = function isIFrame() {
- return this.el.tagName === "IFRAME";
- };
- Player.prototype.isYoutube = function isYoutube() {
- return this.isIFrame() && !!this.el.src.match(/\/\/.*?youtube(-nocookie)?\.[a-z]+\/(watch\?v=[^&\s]+|embed)|youtu\.be\/.*/);
- };
- Player.prototype.isVimeo = function isVimeo() {
- return this.isIFrame() && !!this.el.src.match(/vimeo\.com\/video\/.*/);
- };
- Player.prototype.enableApi = function enableApi() {
- var this$1 = this;
- if (this.ready) {
- return this.ready;
- }
- var youtube = this.isYoutube();
- var vimeo = this.isVimeo();
- var poller;
- if (youtube || vimeo) {
- return this.ready = new Promise(function(resolve) {
- once(this$1.el, "load", function() {
- if (youtube) {
- var listener = function() {
- return post(this$1.el, {
- event: "listening",
- id: this$1.id
- });
- };
- poller = setInterval(listener, 100);
- listener();
- }
- });
- listen(function(data$$1) {
- return youtube && data$$1.id === this$1.id && data$$1.event === "onReady" || vimeo && Number(data$$1.player_id) === this$1.id;
- }).then(function() {
- resolve();
- poller && clearInterval(poller);
- });
- attr(this$1.el, "src", "" + this$1.el.src + (includes(this$1.el.src, "?") ? "&" : "?") + (youtube ? "enablejsapi=1" : "api=1&player_id=" + this$1.id));
- });
- }
- return Promise.resolve();
- };
- Player.prototype.play = function play() {
- var this$1 = this;
- if (!this.isVideo()) {
- return;
- }
- if (this.isIFrame()) {
- this.enableApi().then(function() {
- return post(this$1.el, {
- func: "playVideo",
- method: "play"
- });
- });
- } else if (this.isHTML5()) {
- try {
- var promise = this.el.play();
- if (promise) {
- promise.catch(noop);
- }
- } catch (e) {}
- }
- };
- Player.prototype.pause = function pause() {
- var this$1 = this;
- if (!this.isVideo()) {
- return;
- }
- if (this.isIFrame()) {
- this.enableApi().then(function() {
- return post(this$1.el, {
- func: "pauseVideo",
- method: "pause"
- });
- });
- } else if (this.isHTML5()) {
- this.el.pause();
- }
- };
- Player.prototype.mute = function mute() {
- var this$1 = this;
- if (!this.isVideo()) {
- return;
- }
- if (this.isIFrame()) {
- this.enableApi().then(function() {
- return post(this$1.el, {
- func: "mute",
- method: "setVolume",
- value: 0
- });
- });
- } else if (this.isHTML5()) {
- this.el.muted = true;
- attr(this.el, "muted", "");
- }
- };
- function post(el, cmd) {
- try {
- el.contentWindow.postMessage(JSON.stringify(assign({
- event: "command"
- }, cmd)), "*");
- } catch (e) {}
- }
- function listen(cb) {
- return new Promise(function(resolve) {
- once(window, "message", function(_, data$$1) {
- return resolve(data$$1);
- }, false, function(ref) {
- var data$$1 = ref.data;
- if (!data$$1 || !isString(data$$1)) {
- return;
- }
- try {
- data$$1 = JSON.parse(data$$1);
- } catch (e) {
- return;
- }
- return data$$1 && cb(data$$1);
- });
- });
- }
- var touch = {};
- var clickTimeout;
- var swipeTimeout;
- var tapTimeout;
- var clicked;
- function swipeDirection(ref) {
- var x1 = ref.x1;
- var x2 = ref.x2;
- var y1 = ref.y1;
- var y2 = ref.y2;
- return Math.abs(x1 - x2) >= Math.abs(y1 - y2) ? x1 - x2 > 0 ? "Left" : "Right" : y1 - y2 > 0 ? "Up" : "Down";
- }
- function cancelAll() {
- clickTimeout && clearTimeout(clickTimeout);
- swipeTimeout && clearTimeout(swipeTimeout);
- tapTimeout && clearTimeout(tapTimeout);
- clickTimeout = swipeTimeout = tapTimeout = null;
- touch = {};
- }
- ready(function() {
- on(document, "click", function() {
- return clicked = true;
- }, true);
- on(document, pointerDown, function(e) {
- var target = e.target;
- var ref = getPos$1(e);
- var x = ref.x;
- var y = ref.y;
- var now = Date.now();
- var type = getType(e.type);
- if (touch.type && touch.type !== type) {
- return;
- }
- touch.el = "tagName" in target ? target : target.parentNode;
- clickTimeout && clearTimeout(clickTimeout);
- touch.x1 = x;
- touch.y1 = y;
- if (touch.last && now - touch.last <= 250) {
- touch = {};
- }
- touch.type = type;
- touch.last = now;
- clicked = e.button > 0;
- });
- on(document, pointerMove, function(e) {
- if (e.defaultPrevented) {
- return;
- }
- var ref = getPos$1(e);
- var x = ref.x;
- var y = ref.y;
- touch.x2 = x;
- touch.y2 = y;
- });
- on(document, pointerUp, function(ref) {
- var type = ref.type;
- var target = ref.target;
- if (touch.type !== getType(type)) {
- return;
- }
- if (touch.x2 && Math.abs(touch.x1 - touch.x2) > 30 || touch.y2 && Math.abs(touch.y1 - touch.y2) > 30) {
- swipeTimeout = setTimeout(function() {
- if (touch.el) {
- trigger(touch.el, "swipe");
- trigger(touch.el, "swipe" + swipeDirection(touch));
- }
- touch = {};
- });
- } else if ("last" in touch) {
- tapTimeout = setTimeout(function() {
- return trigger(touch.el, "tap");
- });
- if (touch.el && type !== "mouseup" && within(target, touch.el)) {
- clickTimeout = setTimeout(function() {
- clickTimeout = null;
- if (touch.el && !clicked) {
- trigger(touch.el, "click");
- }
- touch = {};
- }, 350);
- }
- } else {
- touch = {};
- }
- });
- on(document, "touchcancel", cancelAll);
- on(window, "scroll", cancelAll);
- });
- var touching = false;
- on(document, "touchstart", function() {
- return touching = true;
- }, true);
- on(document, "click", function() {
- touching = false;
- });
- on(document, "touchcancel", function() {
- return touching = false;
- }, true);
- function isTouch(e) {
- return touching || e.pointerType === "touch";
- }
- function getPos$1(e) {
- var touches = e.touches;
- var changedTouches = e.changedTouches;
- var ref = touches && touches[0] || changedTouches && changedTouches[0] || e;
- var x = ref.pageX;
- var y = ref.pageY;
- return {
- x: x,
- y: y
- };
- }
- function getType(type) {
- return type.slice(0, 5);
- }
- var util = Object.freeze({
- ajax: ajax,
- getImage: getImage,
- transition: transition,
- Transition: Transition,
- animate: animate,
- Animation: Animation,
- attr: attr,
- hasAttr: hasAttr,
- removeAttr: removeAttr,
- filterAttr: filterAttr,
- data: data,
- addClass: addClass,
- removeClass: removeClass,
- removeClasses: removeClasses,
- replaceClass: replaceClass,
- hasClass: hasClass,
- toggleClass: toggleClass,
- $: $,
- $$: $$,
- positionAt: positionAt,
- offset: offset,
- position: position,
- height: height,
- width: width,
- flipPosition: flipPosition,
- isInView: isInView,
- scrolledOver: scrolledOver,
- isReady: isReady,
- ready: ready,
- index: index,
- getIndex: getIndex,
- empty: empty,
- html: html,
- prepend: prepend,
- append: append,
- before: before,
- after: after,
- remove: remove,
- wrapAll: wrapAll,
- wrapInner: wrapInner,
- unwrap: unwrap,
- fragment: fragment,
- apply: apply,
- isRtl: isRtl,
- hasTouch: hasTouch,
- pointerDown: pointerDown,
- pointerMove: pointerMove,
- pointerUp: pointerUp,
- pointerEnter: pointerEnter,
- pointerLeave: pointerLeave,
- on: on,
- off: off,
- once: once,
- trigger: trigger,
- createEvent: createEvent,
- toEventTargets: toEventTargets,
- preventClick: preventClick,
- fastdom: fastdom,
- isVoidElement: isVoidElement,
- isVisible: isVisible,
- selInput: selInput,
- isInput: isInput,
- filter: filter,
- within: within,
- bind: bind,
- hasOwn: hasOwn,
- hyphenate: hyphenate,
- camelize: camelize,
- ucfirst: ucfirst,
- startsWith: startsWith,
- endsWith: endsWith,
- includes: includes,
- isArray: isArray,
- isFunction: isFunction,
- isObject: isObject,
- isPlainObject: isPlainObject,
- isWindow: isWindow,
- isDocument: isDocument,
- isJQuery: isJQuery,
- isNode: isNode,
- isNodeCollection: isNodeCollection,
- isBoolean: isBoolean,
- isString: isString,
- isNumber: isNumber,
- isNumeric: isNumeric,
- isUndefined: isUndefined,
- toBoolean: toBoolean,
- toNumber: toNumber,
- toFloat: toFloat,
- toNode: toNode,
- toNodes: toNodes,
- toList: toList,
- toMs: toMs,
- swap: swap,
- assign: assign,
- each: each,
- sortBy: sortBy,
- clamp: clamp,
- noop: noop,
- intersectRect: intersectRect,
- pointInRect: pointInRect,
- Dimensions: Dimensions,
- MouseTracker: MouseTracker,
- mergeOptions: mergeOptions,
- Player: Player,
- Promise: Promise,
- Deferred: Deferred,
- query: query,
- queryAll: queryAll,
- find: find,
- findAll: findAll,
- matches: matches,
- closest: closest,
- parents: parents,
- escape: escape,
- css: css,
- getStyles: getStyles,
- getStyle: getStyle,
- getCssVar: getCssVar,
- propName: propName,
- isTouch: isTouch,
- getPos: getPos$1
- });
- function componentAPI(UIkit) {
- var DATA = UIkit.data;
- UIkit.components = {};
- UIkit.component = function(id, options) {
- var name = camelize(id);
- if (isPlainObject(options)) {
- options.name = name;
- options = UIkit.extend(options);
- } else if (isUndefined(options)) {
- return UIkit.components[name];
- } else {
- options.options.name = name;
- }
- UIkit.components[name] = options;
- UIkit[name] = function(element, data) {
- var i = arguments.length, argsArray = Array(i);
- while (i--) argsArray[i] = arguments[i];
- if (isPlainObject(element)) {
- return new UIkit.components[name]({
- data: element
- });
- }
- if (UIkit.components[name].options.functional) {
- return new UIkit.components[name]({
- data: [].concat(argsArray)
- });
- }
- return element && element.nodeType ? init(element) : $$(element).map(init)[0];
- function init(element) {
- var cmp = UIkit.getComponent(element, name);
- if (cmp && data) {
- cmp.$reset(data);
- }
- return cmp || new UIkit.components[name]({
- el: element,
- data: data || {}
- });
- }
- };
- if (UIkit._initialized && !options.options.functional) {
- fastdom.read(function() {
- return UIkit[name]("[uk-" + id + "],[data-uk-" + id + "]");
- });
- }
- return UIkit.components[name];
- };
- UIkit.getComponents = function(element) {
- return element && element[DATA] || {};
- };
- UIkit.getComponent = function(element, name) {
- return UIkit.getComponents(element)[name];
- };
- UIkit.connect = function(node) {
- if (node[DATA]) {
- for (var name in node[DATA]) {
- node[DATA][name]._callConnected();
- }
- }
- for (var i = 0; i < node.attributes.length; i++) {
- var name$1 = getComponentName(node.attributes[i].name);
- if (name$1 && name$1 in UIkit.components) {
- UIkit[name$1](node);
- }
- }
- };
- UIkit.disconnect = function(node) {
- for (var name in node[DATA]) {
- node[DATA][name]._callDisconnected();
- }
- };
- }
- function getComponentName(attribute) {
- return startsWith(attribute, "uk-") || startsWith(attribute, "data-uk-") ? camelize(attribute.replace("data-uk-", "").replace("uk-", "")) : false;
- }
- function boot(UIkit) {
- var connect = UIkit.connect;
- var disconnect = UIkit.disconnect;
- if (!("MutationObserver" in window)) {
- return;
- }
- if (document.body) {
- init();
- } else {
- new MutationObserver(function() {
- if (document.body) {
- this.disconnect();
- init();
- }
- }).observe(document, {
- childList: true,
- subtree: true
- });
- }
- function init() {
- apply(document.body, connect);
- fastdom.flush();
- new MutationObserver(function(mutations) {
- return mutations.forEach(applyMutation);
- }).observe(document, {
- childList: true,
- subtree: true,
- characterData: true,
- attributes: true
- });
- UIkit._initialized = true;
- }
- function applyMutation(mutation) {
- var target = mutation.target;
- var type = mutation.type;
- var update = type !== "attributes" ? applyChildList(mutation) : applyAttribute(mutation);
- update && UIkit.update(target);
- }
- function applyAttribute(ref) {
- var target = ref.target;
- var attributeName = ref.attributeName;
- if (attributeName === "href") {
- return true;
- }
- var name = getComponentName(attributeName);
- if (!name || !(name in UIkit.components)) {
- return;
- }
- if (hasAttr(target, attributeName)) {
- UIkit[name](target);
- return true;
- }
- var component = UIkit.getComponent(target, name);
- if (component) {
- component.$destroy();
- return true;
- }
- }
- function applyChildList(ref) {
- var addedNodes = ref.addedNodes;
- var removedNodes = ref.removedNodes;
- for (var i = 0; i < addedNodes.length; i++) {
- apply(addedNodes[i], connect);
- }
- for (var i$1 = 0; i$1 < removedNodes.length; i$1++) {
- apply(removedNodes[i$1], disconnect);
- }
- return true;
- }
- function apply(node, fn) {
- if (node.nodeType !== 1 || hasAttr(node, "uk-no-boot")) {
- return;
- }
- fn(node);
- node = node.firstElementChild;
- while (node) {
- var next = node.nextElementSibling;
- apply(node, fn);
- node = next;
- }
- }
- }
- function globalAPI(UIkit) {
- var DATA = UIkit.data;
- UIkit.use = function(plugin) {
- if (plugin.installed) {
- return;
- }
- plugin.call(null, this);
- plugin.installed = true;
- return this;
- };
- UIkit.mixin = function(mixin, component) {
- component = (isString(component) ? UIkit.components[component] : component) || this;
- mixin = mergeOptions({}, mixin);
- mixin.mixins = component.options.mixins;
- delete component.options.mixins;
- component.options = mergeOptions(mixin, component.options);
- };
- UIkit.extend = function(options) {
- options = options || {};
- var Super = this;
- var Sub = function UIkitComponent(options) {
- this._init(options);
- };
- Sub.prototype = Object.create(Super.prototype);
- Sub.prototype.constructor = Sub;
- Sub.options = mergeOptions(Super.options, options);
- Sub["super"] = Super;
- Sub.extend = Super.extend;
- return Sub;
- };
- UIkit.update = function(element, e) {
- e = createEvent(e || "update");
- element = element ? toNode(element) : document.body;
- apply(element, function(element) {
- return update(element[DATA], e);
- });
- while (element && element.parentNode) {
- update(element.parentNode[DATA], e);
- element = element.parentNode;
- }
- };
- var container;
- Object.defineProperty(UIkit, "container", {
- get: function get() {
- return container || document.body;
- },
- set: function set(element) {
- container = $(element);
- }
- });
- function update(data, e) {
- if (!data) {
- return;
- }
- for (var name in data) {
- if (data[name]._isReady) {
- data[name]._callUpdate(e);
- }
- }
- }
- }
- function hooksAPI(UIkit) {
- UIkit.prototype._callHook = function(hook) {
- var this$1 = this;
- var handlers = this.$options[hook];
- if (handlers) {
- handlers.forEach(function(handler) {
- return handler.call(this$1);
- });
- }
- };
- UIkit.prototype._callConnected = function() {
- var this$1 = this;
- if (this._connected) {
- return;
- }
- this._data = {};
- this._callHook("beforeConnect");
- this._connected = true;
- this._initEvents();
- this._initObserver();
- this._callHook("connected");
- if (!this._isReady) {
- ready(function() {
- return this$1._callReady();
- });
- }
- this._callUpdate();
- };
- UIkit.prototype._callDisconnected = function() {
- if (!this._connected) {
- return;
- }
- this._callHook("beforeDisconnect");
- if (this._observer) {
- this._observer.disconnect();
- this._observer = null;
- }
- this._unbindEvents();
- this._callHook("disconnected");
- this._connected = false;
- };
- UIkit.prototype._callReady = function() {
- if (this._isReady) {
- return;
- }
- this._isReady = true;
- this._callHook("ready");
- this._resetComputeds();
- this._callUpdate();
- };
- UIkit.prototype._callUpdate = function(e) {
- var this$1 = this;
- e = createEvent(e || "update");
- var type = e.type;
- if (includes([ "update", "load", "resize" ], type)) {
- this._resetComputeds();
- }
- var updates = this.$options.update;
- var ref = this._frames;
- var reads = ref.reads;
- var writes = ref.writes;
- if (!updates) {
- return;
- }
- updates.forEach(function(ref, i) {
- var read = ref.read;
- var write = ref.write;
- var events = ref.events;
- if (type !== "update" && !includes(events, type)) {
- return;
- }
- if (read && !includes(fastdom.reads, reads[i])) {
- reads[i] = fastdom.read(function() {
- var result = read.call(this$1, this$1._data, e);
- if (result === false && write) {
- fastdom.clear(writes[i]);
- delete writes[i];
- } else if (isPlainObject(result)) {
- assign(this$1._data, result);
- }
- delete reads[i];
- });
- }
- if (write && !includes(fastdom.writes, writes[i])) {
- writes[i] = fastdom.write(function() {
- write.call(this$1, this$1._data, e);
- delete writes[i];
- });
- }
- });
- };
- }
- function stateAPI(UIkit) {
- var uid = 0;
- UIkit.prototype.props = {};
- UIkit.prototype._init = function(options) {
- options = options || {};
- options = this.$options = mergeOptions(this.constructor.options, options, this);
- this.$el = null;
- this.$name = UIkit.prefix + hyphenate(this.$options.name);
- this.$props = {};
- this._frames = {
- reads: {},
- writes: {}
- };
- this._events = [];
- this._uid = uid++;
- this._initData();
- this._initMethods();
- this._initComputeds();
- this._callHook("created");
- if (options.el) {
- this.$mount(options.el);
- }
- };
- UIkit.prototype._initData = function() {
- var this$1 = this;
- var ref = this.$options;
- var defaults = ref.defaults;
- var data$$1 = ref.data;
- if (data$$1 === void 0) data$$1 = {};
- var args = ref.args;
- if (args === void 0) args = [];
- var props = ref.props;
- if (props === void 0) props = {};
- var el = ref.el;
- if (args.length && isArray(data$$1)) {
- data$$1 = data$$1.slice(0, args.length).reduce(function(data$$1, value, index) {
- if (isPlainObject(value)) {
- assign(data$$1, value);
- } else {
- data$$1[args[index]] = value;
- }
- return data$$1;
- }, {});
- }
- for (var key in assign({}, defaults, props)) {
- this$1.$props[key] = this$1[key] = hasOwn(data$$1, key) && !isUndefined(data$$1[key]) ? coerce(props[key], data$$1[key], el) : defaults ? defaults[key] && isArray(defaults[key]) ? defaults[key].concat() : defaults[key] : null;
- }
- };
- UIkit.prototype._initMethods = function() {
- var this$1 = this;
- var ref = this.$options;
- var methods = ref.methods;
- if (methods) {
- for (var key in methods) {
- this$1[key] = bind(methods[key], this$1);
- }
- }
- };
- UIkit.prototype._initComputeds = function() {
- var this$1 = this;
- var ref = this.$options;
- var computed = ref.computed;
- this._resetComputeds();
- if (computed) {
- for (var key in computed) {
- registerComputed(this$1, key, computed[key]);
- }
- }
- };
- UIkit.prototype._resetComputeds = function() {
- this._computeds = {};
- };
- UIkit.prototype._initProps = function(props) {
- var this$1 = this;
- var key;
- this._resetComputeds();
- props = props || getProps(this.$options, this.$name);
- for (key in props) {
- if (!isUndefined(props[key])) {
- this$1.$props[key] = props[key];
- }
- }
- var exclude = [ this.$options.computed, this.$options.methods ];
- for (key in this$1.$props) {
- if (key in props && notIn(exclude, key)) {
- this$1[key] = this$1.$props[key];
- }
- }
- };
- UIkit.prototype._initEvents = function() {
- var this$1 = this;
- var ref = this.$options;
- var events = ref.events;
- if (events) {
- events.forEach(function(event) {
- if (!hasOwn(event, "handler")) {
- for (var key in event) {
- registerEvent(this$1, event[key], key);
- }
- } else {
- registerEvent(this$1, event);
- }
- });
- }
- };
- UIkit.prototype._unbindEvents = function() {
- this._events.forEach(function(unbind) {
- return unbind();
- });
- this._events = [];
- };
- UIkit.prototype._initObserver = function() {
- var this$1 = this;
- var ref = this.$options;
- var attrs = ref.attrs;
- var props = ref.props;
- var el = ref.el;
- if (this._observer || !props || !attrs) {
- return;
- }
- attrs = isArray(attrs) ? attrs : Object.keys(props).map(function(key) {
- return hyphenate(key);
- });
- this._observer = new MutationObserver(function() {
- var data$$1 = getProps(this$1.$options, this$1.$name);
- if (attrs.some(function(key) {
- return !isUndefined(data$$1[key]) && data$$1[key] !== this$1.$props[key];
- })) {
- this$1.$reset(data$$1);
- }
- });
- this._observer.observe(el, {
- attributes: true,
- attributeFilter: attrs.concat([ this.$name, "data-" + this.$name ])
- });
- };
- function getProps(opts, name) {
- var data$$1 = {};
- var args = opts.args;
- if (args === void 0) args = [];
- var props = opts.props;
- if (props === void 0) props = {};
- var el = opts.el;
- if (!props) {
- return data$$1;
- }
- for (var key in props) {
- var prop = hyphenate(key);
- if (hasAttr(el, prop)) {
- var value = coerce(props[key], attr(el, prop), el);
- if (prop === "target" && (!value || startsWith(value, "_"))) {
- continue;
- }
- data$$1[key] = value;
- }
- }
- var options = parseOptions(data(el, name), args);
- for (var key$1 in options) {
- var prop$1 = camelize(key$1);
- if (props[prop$1] !== undefined) {
- data$$1[prop$1] = coerce(props[prop$1], options[key$1], el);
- }
- }
- return data$$1;
- }
- function parseOptions(options, args) {
- var obj;
- if (args === void 0) args = [];
- try {
- return !options ? {} : startsWith(options, "{") ? JSON.parse(options) : args.length && !includes(options, ":") ? (obj = {},
- obj[args[0]] = options, obj) : options.split(";").reduce(function(options, option) {
- var ref = option.split(/:(.+)/);
- var key = ref[0];
- var value = ref[1];
- if (key && value) {
- options[key.trim()] = value.trim();
- }
- return options;
- }, {});
- } catch (e) {
- return {};
- }
- }
- function registerComputed(component, key, cb) {
- Object.defineProperty(component, key, {
- enumerable: true,
- get: function get() {
- var _computeds = component._computeds;
- var $props = component.$props;
- var $el = component.$el;
- if (!hasOwn(_computeds, key)) {
- _computeds[key] = cb.call(component, $props, $el);
- }
- return _computeds[key];
- },
- set: function set(value) {
- component._computeds[key] = value;
- }
- });
- }
- function registerEvent(component, event, key) {
- if (!isPlainObject(event)) {
- event = {
- name: key,
- handler: event
- };
- }
- var name = event.name;
- var el = event.el;
- var handler = event.handler;
- var capture = event.capture;
- var delegate = event.delegate;
- var filter = event.filter;
- var self = event.self;
- el = isFunction(el) ? el.call(component) : el || component.$el;
- if (isArray(el)) {
- el.forEach(function(el) {
- return registerEvent(component, assign({}, event, {
- el: el
- }), key);
- });
- return;
- }
- if (!el || filter && !filter.call(component)) {
- return;
- }
- handler = detail(isString(handler) ? component[handler] : bind(handler, component));
- if (self) {
- handler = selfFilter(handler);
- }
- component._events.push(on(el, name, !delegate ? null : isString(delegate) ? delegate : delegate.call(component), handler, capture));
- }
- function selfFilter(handler) {
- return function selfHandler(e) {
- if (e.target === e.currentTarget || e.target === e.current) {
- return handler.call(null, e);
- }
- };
- }
- function notIn(options, key) {
- return options.every(function(arr) {
- return !arr || !hasOwn(arr, key);
- });
- }
- function detail(listener) {
- return function(e) {
- return isArray(e.detail) ? listener.apply(void 0, [ e ].concat(e.detail)) : listener(e);
- };
- }
- function coerce(type, value, context) {
- if (type === Boolean) {
- return toBoolean(value);
- } else if (type === Number) {
- return toNumber(value);
- } else if (type === "query") {
- return query(value, context);
- } else if (type === "list") {
- return toList(value);
- } else if (type === "media") {
- return toMedia(value);
- }
- return type ? type(value) : value;
- }
- function toMedia(value) {
- if (isString(value)) {
- if (value[0] === "@") {
- var name = "media-" + value.substr(1);
- value = toFloat(getCssVar(name));
- } else if (isNaN(value)) {
- return value;
- }
- }
- return value && !isNaN(value) ? "(min-width: " + value + "px)" : false;
- }
- }
- function instanceAPI(UIkit) {
- var DATA = UIkit.data;
- UIkit.prototype.$mount = function(el) {
- var ref = this.$options;
- var name = ref.name;
- if (!el[DATA]) {
- el[DATA] = {};
- }
- if (el[DATA][name]) {
- return;
- }
- el[DATA][name] = this;
- this.$el = this.$options.el = this.$options.el || el;
- this._initProps();
- this._callHook("init");
- if (within(el, document)) {
- this._callConnected();
- }
- };
- UIkit.prototype.$emit = function(e) {
- this._callUpdate(e);
- };
- UIkit.prototype.$reset = function(data) {
- this._callDisconnected();
- this._initProps(data);
- this._callConnected();
- };
- UIkit.prototype.$destroy = function(removeEl) {
- if (removeEl === void 0) removeEl = false;
- var ref = this.$options;
- var el = ref.el;
- var name = ref.name;
- if (el) {
- this._callDisconnected();
- }
- this._callHook("destroy");
- if (!el || !el[DATA]) {
- return;
- }
- delete el[DATA][name];
- if (!Object.keys(el[DATA]).length) {
- delete el[DATA];
- }
- if (removeEl) {
- remove(this.$el);
- }
- };
- }
- var UIkit$2 = function(options) {
- this._init(options);
- };
- UIkit$2.util = util;
- UIkit$2.data = "__uikit__";
- UIkit$2.prefix = "uk-";
- UIkit$2.options = {};
- globalAPI(UIkit$2);
- hooksAPI(UIkit$2);
- stateAPI(UIkit$2);
- instanceAPI(UIkit$2);
- componentAPI(UIkit$2);
- var Class = {
- init: function init() {
- addClass(this.$el, this.$name);
- }
- };
- var Container = {
- props: {
- container: Boolean
- },
- defaults: {
- container: true
- },
- computed: {
- container: function container(ref) {
- var container = ref.container;
- return container === true && UIkit$2.container || container && $(container);
- }
- }
- };
- var Togglable = {
- props: {
- cls: Boolean,
- animation: "list",
- duration: Number,
- origin: String,
- transition: String,
- queued: Boolean
- },
- defaults: {
- cls: false,
- animation: [ false ],
- duration: 200,
- origin: false,
- transition: "linear",
- queued: false,
- initProps: {
- overflow: "",
- height: "",
- paddingTop: "",
- paddingBottom: "",
- marginTop: "",
- marginBottom: ""
- },
- hideProps: {
- overflow: "hidden",
- height: 0,
- paddingTop: 0,
- paddingBottom: 0,
- marginTop: 0,
- marginBottom: 0
- }
- },
- computed: {
- hasAnimation: function hasAnimation(ref) {
- var animation = ref.animation;
- return !!animation[0];
- },
- hasTransition: function hasTransition(ref) {
- var animation = ref.animation;
- return this.hasAnimation && animation[0] === true;
- }
- },
- methods: {
- toggleElement: function toggleElement(targets, show, animate) {
- var this$1 = this;
- return new Promise(function(resolve) {
- targets = toNodes(targets);
- var all = function(targets) {
- return Promise.all(targets.map(function(el) {
- return this$1._toggleElement(el, show, animate);
- }));
- };
- var toggled = targets.filter(function(el) {
- return this$1.isToggled(el);
- });
- var untoggled = targets.filter(function(el) {
- return !includes(toggled, el);
- });
- var p;
- if (!this$1.queued || !isUndefined(animate) || !isUndefined(show) || !this$1.hasAnimation || targets.length < 2) {
- p = all(untoggled.concat(toggled));
- } else {
- var body = document.body;
- var scroll = body.scrollTop;
- var el = toggled[0];
- var inProgress = Animation.inProgress(el) && hasClass(el, "uk-animation-leave") || Transition.inProgress(el) && el.style.height === "0px";
- p = all(toggled);
- if (!inProgress) {
- p = p.then(function() {
- var p = all(untoggled);
- body.scrollTop = scroll;
- return p;
- });
- }
- }
- p.then(resolve, noop);
- });
- },
- toggleNow: function toggleNow(targets, show) {
- var this$1 = this;
- return new Promise(function(resolve) {
- return Promise.all(toNodes(targets).map(function(el) {
- return this$1._toggleElement(el, show, false);
- })).then(resolve, noop);
- });
- },
- isToggled: function isToggled(el) {
- var nodes = toNodes(el || this.$el);
- return this.cls ? hasClass(nodes, this.cls.split(" ")[0]) : !hasAttr(nodes, "hidden");
- },
- updateAria: function updateAria(el) {
- if (this.cls === false) {
- attr(el, "aria-hidden", !this.isToggled(el));
- }
- },
- _toggleElement: function _toggleElement(el, show, animate) {
- var this$1 = this;
- show = isBoolean(show) ? show : Animation.inProgress(el) ? hasClass(el, "uk-animation-leave") : Transition.inProgress(el) ? el.style.height === "0px" : !this.isToggled(el);
- if (!trigger(el, "before" + (show ? "show" : "hide"), [ this ])) {
- return Promise.reject();
- }
- var promise = (animate === false || !this.hasAnimation ? this._toggleImmediate : this.hasTransition ? this._toggleHeight : this._toggleAnimation)(el, show);
- trigger(el, show ? "show" : "hide", [ this ]);
- return promise.then(function() {
- trigger(el, show ? "shown" : "hidden", [ this$1 ]);
- trigger(el, "resize");
- });
- },
- _toggle: function _toggle(el, toggled) {
- if (!el) {
- return;
- }
- var changed;
- if (this.cls) {
- changed = includes(this.cls, " ") || Boolean(toggled) !== hasClass(el, this.cls);
- changed && toggleClass(el, this.cls, includes(this.cls, " ") ? undefined : toggled);
- } else {
- changed = Boolean(toggled) === hasAttr(el, "hidden");
- changed && attr(el, "hidden", !toggled ? "" : null);
- }
- $$("[autofocus]", el).some(function(el) {
- return isVisible(el) && (el.focus() || true);
- });
- this.updateAria(el);
- changed && trigger(el, "resize");
- },
- _toggleImmediate: function _toggleImmediate(el, show) {
- this._toggle(el, show);
- return Promise.resolve();
- },
- _toggleHeight: function _toggleHeight(el, show) {
- var this$1 = this;
- var inProgress = Transition.inProgress(el);
- var inner = el.hasChildNodes ? toFloat(css(el.firstElementChild, "marginTop")) + toFloat(css(el.lastElementChild, "marginBottom")) : 0;
- var currentHeight = isVisible(el) ? height(el) + (inProgress ? 0 : inner) : 0;
- Transition.cancel(el);
- if (!this.isToggled(el)) {
- this._toggle(el, true);
- }
- height(el, "");
- fastdom.flush();
- var endHeight = height(el) + (inProgress ? 0 : inner);
- height(el, currentHeight);
- return (show ? Transition.start(el, assign({}, this.initProps, {
- overflow: "hidden",
- height: endHeight
- }), Math.round(this.duration * (1 - currentHeight / endHeight)), this.transition) : Transition.start(el, this.hideProps, Math.round(this.duration * (currentHeight / endHeight)), this.transition).then(function() {
- return this$1._toggle(el, false);
- })).then(function() {
- return css(el, this$1.initProps);
- });
- },
- _toggleAnimation: function _toggleAnimation(el, show) {
- var this$1 = this;
- Animation.cancel(el);
- if (show) {
- this._toggle(el, true);
- return Animation.in(el, this.animation[0], this.duration, this.origin);
- }
- return Animation.out(el, this.animation[1] || this.animation[0], this.duration, this.origin).then(function() {
- return this$1._toggle(el, false);
- });
- }
- }
- };
- var active;
- var Modal = {
- mixins: [ Class, Container, Togglable ],
- props: {
- selPanel: String,
- selClose: String,
- escClose: Boolean,
- bgClose: Boolean,
- stack: Boolean
- },
- defaults: {
- cls: "uk-open",
- escClose: true,
- bgClose: true,
- overlay: true,
- stack: false
- },
- computed: {
- panel: function panel(ref, $el) {
- var selPanel = ref.selPanel;
- return $(selPanel, $el);
- },
- transitionElement: function transitionElement() {
- return this.panel;
- },
- transitionDuration: function transitionDuration() {
- return toMs(css(this.transitionElement, "transitionDuration"));
- }
- },
- events: [ {
- name: "click",
- delegate: function delegate() {
- return this.selClose;
- },
- handler: function handler(e) {
- e.preventDefault();
- this.hide();
- }
- }, {
- name: "toggle",
- self: true,
- handler: function handler(e) {
- if (e.defaultPrevented) {
- return;
- }
- e.preventDefault();
- this.toggle();
- }
- }, {
- name: "beforeshow",
- self: true,
- handler: function handler(e) {
- var prev = active && active !== this && active;
- active = this;
- if (prev) {
- if (this.stack) {
- this.prev = prev;
- } else {
- prev.hide().then(this.show);
- e.preventDefault();
- return;
- }
- }
- registerEvents();
- }
- }, {
- name: "beforehide",
- self: true,
- handler: function handler() {
- active = active && active !== this && active || this.prev;
- if (!active) {
- deregisterEvents();
- }
- }
- }, {
- name: "show",
- self: true,
- handler: function handler() {
- if (!hasClass(document.documentElement, this.clsPage)) {
- this.scrollbarWidth = width(window) - width(document);
- css(document.body, "overflowY", this.scrollbarWidth && this.overlay ? "scroll" : "");
- }
- addClass(document.documentElement, this.clsPage);
- }
- }, {
- name: "hidden",
- self: true,
- handler: function handler() {
- var this$1 = this;
- var found;
- var ref = this;
- var prev = ref.prev;
- while (prev) {
- if (prev.clsPage === this$1.clsPage) {
- found = true;
- break;
- }
- prev = prev.prev;
- }
- if (!found) {
- removeClass(document.documentElement, this.clsPage);
- }
- !this.prev && css(document.body, "overflowY", "");
- }
- } ],
- methods: {
- toggle: function toggle() {
- return this.isToggled() ? this.hide() : this.show();
- },
- show: function show() {
- if (this.isToggled()) {
- return;
- }
- if (this.container && this.$el.parentNode !== this.container) {
- append(this.container, this.$el);
- this._callConnected();
- }
- return this.toggleNow(this.$el, true);
- },
- hide: function hide() {
- if (this.isToggled()) {
- return this.toggleNow(this.$el, false);
- }
- },
- getActive: function getActive() {
- return active;
- },
- _toggleImmediate: function _toggleImmediate(el, show) {
- var this$1 = this;
- return new Promise(function(resolve) {
- return requestAnimationFrame(function() {
- this$1._toggle(el, show);
- if (this$1.transitionDuration) {
- once(this$1.transitionElement, "transitionend", resolve, false, function(e) {
- return e.target === this$1.transitionElement;
- });
- } else {
- resolve();
- }
- });
- });
- }
- }
- };
- var events;
- function registerEvents() {
- if (events) {
- return;
- }
- events = [ on(document, "click", function(ref) {
- var target = ref.target;
- var defaultPrevented = ref.defaultPrevented;
- if (active && active.bgClose && !defaultPrevented && (!active.overlay || within(target, active.$el)) && (!active.panel || !within(target, active.panel))) {
- active.hide();
- }
- }), on(document, "keydown", function(e) {
- if (e.keyCode === 27 && active && active.escClose) {
- e.preventDefault();
- active.hide();
- }
- }) ];
- }
- function deregisterEvents() {
- events && events.forEach(function(unbind) {
- return unbind();
- });
- events = null;
- }
- var Position = {
- props: {
- pos: String,
- offset: null,
- flip: Boolean,
- clsPos: String
- },
- defaults: {
- pos: "bottom-" + (!isRtl ? "left" : "right"),
- flip: true,
- offset: false,
- clsPos: ""
- },
- computed: {
- pos: function pos(ref) {
- var pos = ref.pos;
- return (pos + (!includes(pos, "-") ? "-center" : "")).split("-");
- },
- dir: function dir() {
- return this.pos[0];
- },
- align: function align() {
- return this.pos[1];
- }
- },
- methods: {
- positionAt: function positionAt$1(element, target, boundary) {
- removeClasses(element, this.clsPos + "-(top|bottom|left|right)(-[a-z]+)?");
- css(element, {
- top: "",
- left: ""
- });
- var node;
- var ref = this;
- var offset$$1 = ref.offset;
- offset$$1 = isNumeric(offset$$1) ? offset$$1 : (node = $(offset$$1)) ? offset(node)[axis === "x" ? "left" : "top"] - offset(target)[axis === "x" ? "right" : "bottom"] : 0;
- var axis = this.getAxis();
- var ref$1 = positionAt(element, target, axis === "x" ? flipPosition(this.dir) + " " + this.align : this.align + " " + flipPosition(this.dir), axis === "x" ? this.dir + " " + this.align : this.align + " " + this.dir, axis === "x" ? "" + (this.dir === "left" ? -offset$$1 : offset$$1) : " " + (this.dir === "top" ? -offset$$1 : offset$$1), null, this.flip, boundary).target;
- var x = ref$1.x;
- var y = ref$1.y;
- this.dir = axis === "x" ? x : y;
- this.align = axis === "x" ? y : x;
- toggleClass(element, this.clsPos + "-" + this.dir + "-" + this.align, this.offset === false);
- },
- getAxis: function getAxis() {
- return this.dir === "top" || this.dir === "bottom" ? "y" : "x";
- }
- }
- };
- function mixin(UIkit) {
- UIkit.mixin.class = Class;
- UIkit.mixin.container = Container;
- UIkit.mixin.modal = Modal;
- UIkit.mixin.position = Position;
- UIkit.mixin.togglable = Togglable;
- }
- function Accordion(UIkit) {
- UIkit.component("accordion", {
- mixins: [ Class, Togglable ],
- props: {
- targets: String,
- active: null,
- collapsible: Boolean,
- multiple: Boolean,
- toggle: String,
- content: String,
- transition: String
- },
- defaults: {
- targets: "> *",
- active: false,
- animation: [ true ],
- collapsible: true,
- multiple: false,
- clsOpen: "uk-open",
- toggle: "> .uk-accordion-title",
- content: "> .uk-accordion-content",
- transition: "ease"
- },
- computed: {
- items: function items(ref, $el) {
- var targets = ref.targets;
- return $$(targets, $el);
- }
- },
- events: [ {
- name: "click",
- delegate: function delegate() {
- return this.targets + " " + this.$props.toggle;
- },
- handler: function handler(e) {
- e.preventDefault();
- this.toggle(index($$(this.targets + " " + this.$props.toggle, this.$el), e.current));
- }
- } ],
- connected: function connected() {
- if (this.active === false) {
- return;
- }
- var active = this.items[Number(this.active)];
- if (active && !hasClass(active, this.clsOpen)) {
- this.toggle(active, false);
- }
- },
- update: function update() {
- var this$1 = this;
- this.items.forEach(function(el) {
- return this$1._toggleImmediate($(this$1.content, el), hasClass(el, this$1.clsOpen));
- });
- var active = !this.collapsible && !hasClass(this.items, this.clsOpen) && this.items[0];
- if (active) {
- this.toggle(active, false);
- }
- },
- methods: {
- toggle: function toggle(item, animate) {
- var this$1 = this;
- var index = getIndex(item, this.items);
- var active = filter(this.items, "." + this.clsOpen);
- item = this.items[index];
- item && [ item ].concat(!this.multiple && !includes(active, item) && active || []).forEach(function(el) {
- var isItem = el === item;
- var state = isItem && !hasClass(el, this$1.clsOpen);
- if (!state && isItem && !this$1.collapsible && active.length < 2) {
- return;
- }
- toggleClass(el, this$1.clsOpen, state);
- var content = el._wrapper ? el._wrapper.firstElementChild : $(this$1.content, el);
- if (!el._wrapper) {
- el._wrapper = wrapAll(content, "
");
- attr(el._wrapper, "hidden", state ? "" : null);
- }
- this$1._toggleImmediate(content, true);
- this$1.toggleElement(el._wrapper, state, animate).then(function() {
- if (hasClass(el, this$1.clsOpen) === state) {
- if (!state) {
- this$1._toggleImmediate(content, false);
- }
- el._wrapper = null;
- unwrap(content);
- }
- });
- });
- }
- }
- });
- }
- function Alert(UIkit) {
- UIkit.component("alert", {
- attrs: true,
- mixins: [ Class, Togglable ],
- args: "animation",
- props: {
- close: String
- },
- defaults: {
- animation: [ true ],
- selClose: ".uk-alert-close",
- duration: 150,
- hideProps: assign({
- opacity: 0
- }, Togglable.defaults.hideProps)
- },
- events: [ {
- name: "click",
- delegate: function delegate() {
- return this.selClose;
- },
- handler: function handler(e) {
- e.preventDefault();
- this.close();
- }
- } ],
- methods: {
- close: function close() {
- var this$1 = this;
- this.toggleElement(this.$el).then(function() {
- return this$1.$destroy(true);
- });
- }
- }
- });
- }
- function Core(UIkit) {
- ready(function() {
- var scroll = 0;
- var started = 0;
- on(window, "load resize", function(e) {
- return UIkit.update(null, e);
- });
- on(window, "scroll", function(e) {
- e.dir = scroll <= window.pageYOffset ? "down" : "up";
- e.scrollY = scroll = window.pageYOffset;
- UIkit.update(null, e);
- });
- on(document, "animationstart", function(ref) {
- var target = ref.target;
- if ((css(target, "animationName") || "").match(/^uk-.*(left|right)/)) {
- started++;
- css(document.body, "overflowX", "hidden");
- setTimeout(function() {
- if (!--started) {
- css(document.body, "overflowX", "");
- }
- }, toMs(css(target, "animationDuration")) + 100);
- }
- }, true);
- if (!hasTouch) {
- return;
- }
- var cls = "uk-hover";
- on(document, "tap", function(ref) {
- var target = ref.target;
- return $$("." + cls).forEach(function(el) {
- return !within(target, el) && removeClass(el, cls);
- });
- });
- Object.defineProperty(UIkit, "hoverSelector", {
- set: function set(selector) {
- on(document, "tap", selector, function(ref) {
- var current = ref.current;
- return addClass(current, cls);
- });
- }
- });
- UIkit.hoverSelector = ".uk-animation-toggle, .uk-transition-toggle, [uk-hover]";
- });
- }
- function Cover(UIkit) {
- UIkit.component("cover", {
- mixins: [ Class, UIkit.components.video.options ],
- props: {
- width: Number,
- height: Number
- },
- defaults: {
- automute: true
- },
- update: {
- write: function write() {
- var el = this.$el;
- if (!isVisible(el)) {
- return;
- }
- var ref = el.parentNode;
- var height = ref.offsetHeight;
- var width = ref.offsetWidth;
- css(css(el, {
- width: "",
- height: ""
- }), Dimensions.cover({
- width: this.width || el.clientWidth,
- height: this.height || el.clientHeight
- }, {
- width: width + (width % 2 ? 1 : 0),
- height: height + (height % 2 ? 1 : 0)
- }));
- },
- events: [ "load", "resize" ]
- },
- events: {
- loadedmetadata: function loadedmetadata() {
- this.$emit();
- }
- }
- });
- }
- function Drop(UIkit) {
- var active;
- UIkit.component("drop", {
- mixins: [ Position, Togglable ],
- args: "pos",
- props: {
- mode: "list",
- toggle: Boolean,
- boundary: "query",
- boundaryAlign: Boolean,
- delayShow: Number,
- delayHide: Number,
- clsDrop: String
- },
- defaults: {
- mode: [ "click", "hover" ],
- toggle: true,
- boundary: window,
- boundaryAlign: false,
- delayShow: 0,
- delayHide: 800,
- clsDrop: false,
- hoverIdle: 200,
- animation: [ "uk-animation-fade" ],
- cls: "uk-open"
- },
- computed: {
- clsDrop: function clsDrop(ref) {
- var clsDrop = ref.clsDrop;
- return clsDrop || "uk-" + this.$options.name;
- },
- clsPos: function clsPos() {
- return this.clsDrop;
- }
- },
- init: function init() {
- this.tracker = new MouseTracker();
- addClass(this.$el, this.clsDrop);
- },
- connected: function connected() {
- var ref = this.$props;
- var toggle = ref.toggle;
- this.toggle = toggle && UIkit.toggle(isString(toggle) ? query(toggle, this.$el) : this.$el.previousElementSibling, {
- target: this.$el,
- mode: this.mode
- });
- this.updateAria(this.$el);
- },
- events: [ {
- name: "click",
- delegate: function delegate() {
- return "." + this.clsDrop + "-close";
- },
- handler: function handler(e) {
- e.preventDefault();
- this.hide(false);
- }
- }, {
- name: "click",
- delegate: function delegate() {
- return 'a[href^="#"]';
- },
- handler: function handler(e) {
- if (e.defaultPrevented) {
- return;
- }
- var id = e.target.hash;
- if (!id) {
- e.preventDefault();
- }
- if (!id || !within(id, this.$el)) {
- this.hide(false);
- }
- }
- }, {
- name: "beforescroll",
- handler: function handler() {
- this.hide(false);
- }
- }, {
- name: "toggle",
- self: true,
- handler: function handler(e, toggle) {
- e.preventDefault();
- if (this.isToggled()) {
- this.hide(false);
- } else {
- this.show(toggle, false);
- }
- }
- }, {
- name: pointerEnter,
- filter: function filter() {
- return includes(this.mode, "hover");
- },
- handler: function handler(e) {
- if (isTouch(e)) {
- return;
- }
- if (active && active !== this && active.toggle && includes(active.toggle.mode, "hover") && !within(e.target, active.toggle.$el) && !pointInRect({
- x: e.pageX,
- y: e.pageY
- }, offset(active.$el))) {
- active.hide(false);
- }
- e.preventDefault();
- this.show(this.toggle);
- }
- }, {
- name: "toggleshow",
- handler: function handler(e, toggle) {
- if (toggle && !includes(toggle.target, this.$el)) {
- return;
- }
- e.preventDefault();
- this.show(toggle || this.toggle);
- }
- }, {
- name: "togglehide " + pointerLeave,
- handler: function handler(e, toggle) {
- if (isTouch(e) || toggle && !includes(toggle.target, this.$el)) {
- return;
- }
- e.preventDefault();
- if (this.toggle && includes(this.toggle.mode, "hover")) {
- this.hide();
- }
- }
- }, {
- name: "beforeshow",
- self: true,
- handler: function handler() {
- this.clearTimers();
- Animation.cancel(this.$el);
- this.position();
- }
- }, {
- name: "show",
- self: true,
- handler: function handler() {
- this.tracker.init();
- if (this.toggle) {
- addClass(this.toggle.$el, this.cls);
- attr(this.toggle.$el, "aria-expanded", "true");
- }
- registerEvent();
- }
- }, {
- name: "beforehide",
- self: true,
- handler: function handler() {
- this.clearTimers();
- }
- }, {
- name: "hide",
- handler: function handler(ref) {
- var target = ref.target;
- if (this.$el !== target) {
- active = active === null && within(target, this.$el) && this.isToggled() ? this : active;
- return;
- }
- active = this.isActive() ? null : active;
- if (this.toggle) {
- removeClass(this.toggle.$el, this.cls);
- attr(this.toggle.$el, "aria-expanded", "false");
- this.toggle.$el.blur();
- $$("a, button", this.toggle.$el).forEach(function(el) {
- return el.blur();
- });
- }
- this.tracker.cancel();
- }
- } ],
- update: {
- write: function write() {
- if (this.isToggled() && !Animation.inProgress(this.$el)) {
- this.position();
- }
- },
- events: [ "resize" ]
- },
- methods: {
- show: function show(toggle, delay) {
- var this$1 = this;
- if (delay === void 0) delay = true;
- var show = function() {
- return !this$1.isToggled() && this$1.toggleElement(this$1.$el, true);
- };
- var tryShow = function() {
- this$1.toggle = toggle || this$1.toggle;
- this$1.clearTimers();
- if (this$1.isActive()) {
- return;
- } else if (delay && active && active !== this$1 && active.isDelaying) {
- this$1.showTimer = setTimeout(this$1.show, 10);
- return;
- } else if (this$1.isParentOf(active)) {
- if (active.hideTimer) {
- active.hide(false);
- } else {
- return;
- }
- } else if (active && !this$1.isChildOf(active) && !this$1.isParentOf(active)) {
- var prev;
- while (active && active !== prev && !this$1.isChildOf(active)) {
- prev = active;
- active.hide(false);
- }
- }
- if (delay && this$1.delayShow) {
- this$1.showTimer = setTimeout(show, this$1.delayShow);
- } else {
- show();
- }
- active = this$1;
- };
- if (toggle && this.toggle && toggle.$el !== this.toggle.$el) {
- once(this.$el, "hide", tryShow);
- this.hide(false);
- } else {
- tryShow();
- }
- },
- hide: function hide(delay) {
- var this$1 = this;
- if (delay === void 0) delay = true;
- var hide = function() {
- return this$1.toggleNow(this$1.$el, false);
- };
- this.clearTimers();
- this.isDelaying = this.tracker.movesTo(this.$el);
- if (delay && this.isDelaying) {
- this.hideTimer = setTimeout(this.hide, this.hoverIdle);
- } else if (delay && this.delayHide) {
- this.hideTimer = setTimeout(hide, this.delayHide);
- } else {
- hide();
- }
- },
- clearTimers: function clearTimers() {
- clearTimeout(this.showTimer);
- clearTimeout(this.hideTimer);
- this.showTimer = null;
- this.hideTimer = null;
- this.isDelaying = false;
- },
- isActive: function isActive() {
- return active === this;
- },
- isChildOf: function isChildOf(drop) {
- return drop && drop !== this && within(this.$el, drop.$el);
- },
- isParentOf: function isParentOf(drop) {
- return drop && drop !== this && within(drop.$el, this.$el);
- },
- position: function position() {
- removeClasses(this.$el, this.clsDrop + "-(stack|boundary)");
- css(this.$el, {
- top: "",
- left: "",
- display: "block"
- });
- toggleClass(this.$el, this.clsDrop + "-boundary", this.boundaryAlign);
- var boundary = offset(this.boundary);
- var alignTo = this.boundaryAlign ? boundary : offset(this.toggle.$el);
- if (this.align === "justify") {
- var prop = this.getAxis() === "y" ? "width" : "height";
- css(this.$el, prop, alignTo[prop]);
- } else if (this.$el.offsetWidth > Math.max(boundary.right - alignTo.left, alignTo.right - boundary.left)) {
- addClass(this.$el, this.clsDrop + "-stack");
- }
- this.positionAt(this.$el, this.boundaryAlign ? this.boundary : this.toggle.$el, this.boundary);
- css(this.$el, "display", "");
- }
- }
- });
- UIkit.drop.getActive = function() {
- return active;
- };
- var registered;
- function registerEvent() {
- if (registered) {
- return;
- }
- registered = true;
- on(document, "click", function(ref) {
- var target = ref.target;
- var defaultPrevented = ref.defaultPrevented;
- var prev;
- if (defaultPrevented) {
- return;
- }
- while (active && active !== prev && !within(target, active.$el) && !(active.toggle && within(target, active.toggle.$el))) {
- prev = active;
- active.hide(false);
- }
- });
- }
- }
- function Dropdown(UIkit) {
- UIkit.component("dropdown", UIkit.components.drop.extend({
- name: "dropdown"
- }));
- }
- function FormCustom(UIkit) {
- UIkit.component("form-custom", {
- mixins: [ Class ],
- args: "target",
- props: {
- target: Boolean
- },
- defaults: {
- target: false
- },
- computed: {
- input: function input(_, $el) {
- return $(selInput, $el);
- },
- state: function state() {
- return this.input.nextElementSibling;
- },
- target: function target(ref, $el) {
- var target = ref.target;
- return target && (target === true && this.input.parentNode === $el && this.input.nextElementSibling || query(target, $el));
- }
- },
- update: function update() {
- var ref = this;
- var target = ref.target;
- var input = ref.input;
- if (!target) {
- return;
- }
- var option;
- target[isInput(target) ? "value" : "textContent"] = input.files && input.files[0] ? input.files[0].name : matches(input, "select") && (option = $$("option", input).filter(function(el) {
- return el.selected;
- })[0]) ? option.textContent : input.value;
- },
- events: [ {
- name: "focusin focusout mouseenter mouseleave",
- delegate: selInput,
- handler: function handler(ref) {
- var type = ref.type;
- var current = ref.current;
- if (current === this.input) {
- toggleClass(this.state, "uk-" + (includes(type, "focus") ? "focus" : "hover"), includes([ "focusin", "mouseenter" ], type));
- }
- }
- }, {
- name: "change",
- handler: function handler() {
- this.$emit();
- }
- } ]
- });
- }
- function Gif(UIkit) {
- UIkit.component("gif", {
- update: {
- read: function read(data) {
- var inview = isInView(this.$el);
- if (!inview || data.isInView === inview) {
- return false;
- }
- data.isInView = inview;
- },
- write: function write() {
- this.$el.src = this.$el.src;
- },
- events: [ "scroll", "load", "resize" ]
- }
- });
- }
- function Grid(UIkit) {
- UIkit.component("grid", UIkit.components.margin.extend({
- mixins: [ Class ],
- name: "grid",
- defaults: {
- margin: "uk-grid-margin",
- clsStack: "uk-grid-stack"
- },
- update: {
- write: function write(ref) {
- var stacks = ref.stacks;
- toggleClass(this.$el, this.clsStack, stacks);
- },
- events: [ "load", "resize" ]
- }
- }));
- }
- function HeightMatch(UIkit) {
- UIkit.component("height-match", {
- args: "target",
- props: {
- target: String,
- row: Boolean
- },
- defaults: {
- target: "> *",
- row: true
- },
- computed: {
- elements: function elements(ref, $el) {
- var target = ref.target;
- return $$(target, $el);
- }
- },
- update: {
- read: function read() {
- var this$1 = this;
- var lastOffset = false;
- css(this.elements, "minHeight", "");
- return {
- rows: !this.row ? [ this.match(this.elements) ] : this.elements.reduce(function(rows, el) {
- if (lastOffset !== el.offsetTop) {
- rows.push([ el ]);
- } else {
- rows[rows.length - 1].push(el);
- }
- lastOffset = el.offsetTop;
- return rows;
- }, []).map(function(elements) {
- return this$1.match(elements);
- })
- };
- },
- write: function write(ref) {
- var rows = ref.rows;
- rows.forEach(function(ref) {
- var height = ref.height;
- var elements = ref.elements;
- return css(elements, "minHeight", height);
- });
- },
- events: [ "load", "resize" ]
- },
- methods: {
- match: function match(elements) {
- if (elements.length < 2) {
- return {};
- }
- var heights = [];
- var max = 0;
- elements.forEach(function(el) {
- var style, hidden;
- if (!isVisible(el)) {
- style = attr(el, "style");
- hidden = attr(el, "hidden");
- attr(el, {
- style: (style || "") + ";display:block !important;",
- hidden: null
- });
- }
- max = Math.max(max, el.offsetHeight);
- heights.push(el.offsetHeight);
- if (!isUndefined(style)) {
- attr(el, {
- style: style,
- hidden: hidden
- });
- }
- });
- elements = elements.filter(function(el, i) {
- return heights[i] < max;
- });
- return {
- height: max,
- elements: elements
- };
- }
- }
- });
- }
- function HeightViewport(UIkit) {
- UIkit.component("height-viewport", {
- props: {
- expand: Boolean,
- offsetTop: Boolean,
- offsetBottom: Boolean,
- minHeight: Number
- },
- defaults: {
- expand: false,
- offsetTop: false,
- offsetBottom: false,
- minHeight: 0
- },
- update: {
- write: function write() {
- css(this.$el, "boxSizing", "border-box");
- var viewport = height(window);
- var minHeight, offsetTop = 0;
- if (this.expand) {
- css(this.$el, {
- height: "",
- minHeight: ""
- });
- var diff = viewport - offsetHeight(document.documentElement);
- if (diff > 0) {
- minHeight = offsetHeight(this.$el) + diff;
- }
- } else {
- var ref = offset(this.$el);
- var top = ref.top;
- if (top < viewport / 2 && this.offsetTop) {
- offsetTop += top;
- }
- if (this.offsetBottom === true) {
- offsetTop += offsetHeight(this.$el.nextElementSibling);
- } else if (isNumeric(this.offsetBottom)) {
- offsetTop += viewport / 100 * this.offsetBottom;
- } else if (this.offsetBottom && endsWith(this.offsetBottom, "px")) {
- offsetTop += toFloat(this.offsetBottom);
- } else if (isString(this.offsetBottom)) {
- offsetTop += offsetHeight(query(this.offsetBottom, this.$el));
- }
- minHeight = offsetTop ? "calc(100vh - " + offsetTop + "px)" : "100vh";
- }
- if (!minHeight) {
- return;
- }
- css(this.$el, {
- height: "",
- minHeight: minHeight
- });
- var elHeight = this.$el.offsetHeight;
- if (this.minHeight && this.minHeight > elHeight) {
- css(this.$el, "minHeight", this.minHeight);
- }
- if (viewport - offsetTop >= elHeight) {
- css(this.$el, "height", minHeight);
- }
- },
- events: [ "load", "resize" ]
- }
- });
- function offsetHeight(el) {
- return el && el.offsetHeight || 0;
- }
- }
- var closeIcon = '
';
- var closeLarge = '
';
- var marker = '
';
- var navbarToggleIcon = '
';
- var overlayIcon = '
';
- var paginationNext = '
';
- var paginationPrevious = '
';
- var searchIcon = '
';
- var searchLarge = '
';
- var searchNavbar = '
';
- var slidenavNext = '
';
- var slidenavNextLarge = '
';
- var slidenavPrevious = '
';
- var slidenavPreviousLarge = '
';
- var spinner = '
';
- var totop = '
';
- function Icon(UIkit) {
- var parsed = {};
- var icons = {
- spinner: spinner,
- totop: totop,
- marker: marker,
- "close-icon": closeIcon,
- "close-large": closeLarge,
- "navbar-toggle-icon": navbarToggleIcon,
- "overlay-icon": overlayIcon,
- "pagination-next": paginationNext,
- "pagination-previous": paginationPrevious,
- "search-icon": searchIcon,
- "search-large": searchLarge,
- "search-navbar": searchNavbar,
- "slidenav-next": slidenavNext,
- "slidenav-next-large": slidenavNextLarge,
- "slidenav-previous": slidenavPrevious,
- "slidenav-previous-large": slidenavPreviousLarge
- };
- UIkit.component("icon", UIkit.components.svg.extend({
- attrs: [ "icon", "ratio" ],
- mixins: [ Class ],
- name: "icon",
- args: "icon",
- props: [ "icon" ],
- defaults: {
- exclude: [ "id", "style", "class", "src", "icon" ]
- },
- init: function init() {
- addClass(this.$el, "uk-icon");
- if (isRtl) {
- this.icon = swap(swap(this.icon, "left", "right"), "previous", "next");
- }
- },
- methods: {
- getSvg: function getSvg() {
- var icon = getIcon(this.icon);
- if (!icon) {
- return Promise.reject("Icon not found.");
- }
- return Promise.resolve(icon);
- }
- }
- }));
- [ "marker", "navbar-toggle-icon", "overlay-icon", "pagination-previous", "pagination-next", "totop" ].forEach(function(name) {
- return registerComponent(name);
- });
- [ "slidenav-previous", "slidenav-next" ].forEach(function(name) {
- return registerComponent(name, {
- init: function init() {
- addClass(this.$el, "uk-slidenav");
- if (hasClass(this.$el, "uk-slidenav-large")) {
- this.icon += "-large";
- }
- }
- });
- });
- registerComponent("search-icon", {
- init: function init() {
- if (hasClass(this.$el, "uk-search-icon") && parents(this.$el, ".uk-search-large").length) {
- this.icon = "search-large";
- } else if (parents(this.$el, ".uk-search-navbar").length) {
- this.icon = "search-navbar";
- }
- }
- });
- registerComponent("close", {
- init: function init() {
- this.icon = "close-" + (hasClass(this.$el, "uk-close-large") ? "large" : "icon");
- }
- });
- registerComponent("spinner", {
- connected: function connected() {
- var this$1 = this;
- this.svg.then(function(svg) {
- return this$1.ratio !== 1 && css($("circle", svg), "stroke-width", 1 / this$1.ratio);
- }, noop);
- }
- });
- UIkit.icon.add = function(added) {
- Object.keys(added).forEach(function(name) {
- icons[name] = added[name];
- delete parsed[name];
- });
- if (UIkit._initialized) {
- apply(document.body, function(el) {
- var icon = UIkit.getComponent(el, "icon");
- if (icon) {
- icon.$reset();
- }
- });
- }
- };
- function registerComponent(name, mixin$$1) {
- UIkit.component(name, UIkit.components.icon.extend({
- name: name,
- mixins: mixin$$1 ? [ mixin$$1 ] : [],
- defaults: {
- icon: name
- }
- }));
- }
- function getIcon(icon) {
- if (!icons[icon]) {
- return null;
- }
- if (!parsed[icon]) {
- parsed[icon] = $(icons[icon].trim());
- }
- return parsed[icon];
- }
- }
- function Leader(UIkit) {
- UIkit.component("leader", {
- mixins: [ Class ],
- props: {
- fill: String,
- media: "media"
- },
- defaults: {
- fill: "",
- media: false,
- clsWrapper: "uk-leader-fill",
- clsHide: "uk-leader-hide",
- attrFill: "data-fill"
- },
- computed: {
- fill: function fill(ref) {
- var fill = ref.fill;
- return fill || getCssVar("leader-fill");
- }
- },
- connected: function connected() {
- var assign;
- assign = wrapInner(this.$el, '
'), this.wrapper = assign[0];
- },
- disconnected: function disconnected() {
- unwrap(this.wrapper.childNodes);
- },
- update: [ {
- read: function read(ref) {
- var changed = ref.changed;
- var width = ref.width;
- var prev = width;
- width = Math.floor(this.$el.offsetWidth / 2);
- return {
- width: width,
- changed: changed || prev !== width,
- hide: this.media && !window.matchMedia(this.media).matches
- };
- },
- write: function write(data) {
- toggleClass(this.wrapper, this.clsHide, data.hide);
- if (data.changed) {
- data.changed = false;
- attr(this.wrapper, this.attrFill, new Array(data.width).join(this.fill));
- }
- },
- events: [ "load", "resize" ]
- } ]
- });
- }
- function Margin(UIkit) {
- UIkit.component("margin", {
- props: {
- margin: String,
- firstColumn: Boolean
- },
- defaults: {
- margin: "uk-margin-small-top",
- firstColumn: "uk-first-column"
- },
- update: {
- read: function read(data) {
- var items = this.$el.children;
- if (!items.length || !isVisible(this.$el)) {
- return data.rows = false;
- }
- data.stacks = true;
- var rows = [ [] ];
- for (var i = 0; i < items.length; i++) {
- var el = items[i];
- var dim = el.getBoundingClientRect();
- if (!dim.height) {
- continue;
- }
- for (var j = rows.length - 1; j >= 0; j--) {
- var row = rows[j];
- if (!row[0]) {
- row.push(el);
- break;
- }
- var leftDim = row[0].getBoundingClientRect();
- if (dim.top >= Math.floor(leftDim.bottom)) {
- rows.push([ el ]);
- break;
- }
- if (Math.floor(dim.bottom) > leftDim.top) {
- data.stacks = false;
- if (dim.left < leftDim.left && !isRtl) {
- row.unshift(el);
- break;
- }
- row.push(el);
- break;
- }
- if (j === 0) {
- rows.unshift([ el ]);
- break;
- }
- }
- }
- data.rows = rows;
- },
- write: function write(ref) {
- var this$1 = this;
- var rows = ref.rows;
- rows.forEach(function(row, i) {
- return row.forEach(function(el, j) {
- toggleClass(el, this$1.margin, i !== 0);
- toggleClass(el, this$1.firstColumn, j === 0);
- });
- });
- },
- events: [ "load", "resize" ]
- }
- });
- }
- function Modal$1(UIkit) {
- UIkit.component("modal", {
- mixins: [ Modal ],
- defaults: {
- clsPage: "uk-modal-page",
- selPanel: ".uk-modal-dialog",
- selClose: ".uk-modal-close, .uk-modal-close-default, .uk-modal-close-outside, .uk-modal-close-full"
- },
- events: [ {
- name: "show",
- self: true,
- handler: function handler() {
- if (hasClass(this.panel, "uk-margin-auto-vertical")) {
- addClass(this.$el, "uk-flex");
- } else {
- css(this.$el, "display", "block");
- }
- height(this.$el);
- }
- }, {
- name: "hidden",
- self: true,
- handler: function handler() {
- css(this.$el, "display", "");
- removeClass(this.$el, "uk-flex");
- }
- } ]
- });
- UIkit.component("overflow-auto", {
- mixins: [ Class ],
- computed: {
- modal: function modal(_, $el) {
- return closest($el, ".uk-modal");
- },
- panel: function panel(_, $el) {
- return closest($el, ".uk-modal-dialog");
- }
- },
- connected: function connected() {
- css(this.$el, "minHeight", 150);
- },
- update: {
- write: function write() {
- if (!this.panel || !this.modal) {
- return;
- }
- var current = css(this.$el, "maxHeight");
- css(css(this.$el, "maxHeight", 150), "maxHeight", Math.max(150, 150 + height(this.modal) - this.panel.offsetHeight));
- if (current !== css(this.$el, "maxHeight")) {
- trigger(this.$el, "resize");
- }
- },
- events: [ "load", "resize" ]
- }
- });
- UIkit.modal.dialog = function(content, options) {
- var dialog = UIkit.modal(' ", options);
- dialog.show();
- on(dialog.$el, "hidden", function(ref) {
- var target = ref.target;
- var currentTarget = ref.currentTarget;
- if (target === currentTarget) {
- dialog.$destroy(true);
- }
- });
- return dialog;
- };
- UIkit.modal.alert = function(message, options) {
- options = assign({
- bgClose: false,
- escClose: false,
- labels: UIkit.modal.labels
- }, options);
- return new Promise(function(resolve) {
- return on(UIkit.modal.dialog(' ' + (isString(message) ? message : html(message)) + '
", options).$el, "hide", resolve);
- });
- };
- UIkit.modal.confirm = function(message, options) {
- options = assign({
- bgClose: false,
- escClose: true,
- labels: UIkit.modal.labels
- }, options);
- return new Promise(function(resolve, reject) {
- var confirm = UIkit.modal.dialog(' ", options);
- var resolved = false;
- on(confirm.$el, "submit", "form", function(e) {
- e.preventDefault();
- resolve();
- resolved = true;
- confirm.hide();
- });
- on(confirm.$el, "hide", function() {
- if (!resolved) {
- reject();
- }
- });
- });
- };
- UIkit.modal.prompt = function(message, value, options) {
- options = assign({
- bgClose: false,
- escClose: true,
- labels: UIkit.modal.labels
- }, options);
- return new Promise(function(resolve) {
- var prompt = UIkit.modal.dialog(' ", options), input = $("input", prompt.$el);
- input.value = value;
- var resolved = false;
- on(prompt.$el, "submit", "form", function(e) {
- e.preventDefault();
- resolve(input.value);
- resolved = true;
- prompt.hide();
- });
- on(prompt.$el, "hide", function() {
- if (!resolved) {
- resolve(null);
- }
- });
- });
- };
- UIkit.modal.labels = {
- ok: "Ok",
- cancel: "Cancel"
- };
- }
- function Nav(UIkit) {
- UIkit.component("nav", UIkit.components.accordion.extend({
- name: "nav",
- defaults: {
- targets: "> .uk-parent",
- toggle: "> a",
- content: "> ul"
- }
- }));
- }
- function Navbar(UIkit) {
- UIkit.component("navbar", {
- mixins: [ Class ],
- props: {
- dropdown: String,
- mode: "list",
- align: String,
- offset: Number,
- boundary: Boolean,
- boundaryAlign: Boolean,
- clsDrop: String,
- delayShow: Number,
- delayHide: Number,
- dropbar: Boolean,
- dropbarMode: String,
- dropbarAnchor: "query",
- duration: Number
- },
- defaults: {
- dropdown: ".uk-navbar-nav > li",
- align: !isRtl ? "left" : "right",
- clsDrop: "uk-navbar-dropdown",
- mode: undefined,
- offset: undefined,
- delayShow: undefined,
- delayHide: undefined,
- boundaryAlign: undefined,
- flip: "x",
- boundary: true,
- dropbar: false,
- dropbarMode: "slide",
- dropbarAnchor: false,
- duration: 200
- },
- computed: {
- boundary: function boundary(ref, $el) {
- var boundary = ref.boundary;
- var boundaryAlign = ref.boundaryAlign;
- return boundary === true || boundaryAlign ? $el : boundary;
- },
- pos: function pos(ref) {
- var align = ref.align;
- return "bottom-" + align;
- }
- },
- beforeConnect: function beforeConnect() {
- var ref = this.$props;
- var dropbar = ref.dropbar;
- this.dropbar = dropbar && (isString(dropbar) && query(dropbar, this.$el) || $("
"));
- if (this.dropbar) {
- addClass(this.dropbar, "uk-navbar-dropbar");
- if (this.dropbarMode === "slide") {
- addClass(this.dropbar, "uk-navbar-dropbar-slide");
- }
- }
- },
- disconnected: function disconnected() {
- this.dropbar && remove(this.dropbar);
- },
- update: function update() {
- UIkit.drop($$(this.dropdown + " ." + this.clsDrop, this.$el).filter(function(el) {
- return !UIkit.getComponent(el, "drop") && !UIkit.getComponent(el, "dropdown");
- }), assign({}, this.$props, {
- boundary: this.boundary,
- pos: this.pos,
- offset: this.dropbar || this.offset
- }));
- },
- events: [ {
- name: "mouseover",
- delegate: function delegate() {
- return this.dropdown;
- },
- handler: function handler(ref) {
- var current = ref.current;
- var active = this.getActive();
- if (active && active.toggle && !within(active.toggle.$el, current) && !active.tracker.movesTo(active.$el)) {
- active.hide(false);
- }
- }
- }, {
- name: "mouseleave",
- el: function el() {
- return this.dropbar;
- },
- handler: function handler() {
- var active = this.getActive();
- if (active && !matches(this.dropbar, ":hover")) {
- active.hide();
- }
- }
- }, {
- name: "beforeshow",
- capture: true,
- filter: function filter() {
- return this.dropbar;
- },
- handler: function handler() {
- if (!this.dropbar.parentNode) {
- after(this.dropbarAnchor || this.$el, this.dropbar);
- }
- }
- }, {
- name: "show",
- capture: true,
- filter: function filter() {
- return this.dropbar;
- },
- handler: function handler(_, drop) {
- var $el = drop.$el;
- var dir = drop.dir;
- this.clsDrop && addClass($el, this.clsDrop + "-dropbar");
- if (dir === "bottom") {
- this.transitionTo($el.offsetHeight + toFloat(css($el, "marginTop")) + toFloat(css($el, "marginBottom")), $el);
- }
- }
- }, {
- name: "beforehide",
- filter: function filter() {
- return this.dropbar;
- },
- handler: function handler(e, ref) {
- var $el = ref.$el;
- var active = this.getActive();
- if (matches(this.dropbar, ":hover") && active && active.$el === $el) {
- e.preventDefault();
- }
- }
- }, {
- name: "hide",
- filter: function filter() {
- return this.dropbar;
- },
- handler: function handler(_, ref) {
- var $el = ref.$el;
- var active = this.getActive();
- if (!active || active && active.$el === $el) {
- this.transitionTo(0);
- }
- }
- } ],
- methods: {
- getActive: function getActive() {
- var active = UIkit.drop.getActive();
- return active && includes(active.mode, "hover") && within(active.toggle.$el, this.$el) && active;
- },
- transitionTo: function transitionTo(newHeight, el) {
- var ref = this;
- var dropbar = ref.dropbar;
- var oldHeight = isVisible(dropbar) ? height(dropbar) : 0;
- el = oldHeight < newHeight && el;
- css(el, {
- height: oldHeight,
- overflow: "hidden"
- });
- height(dropbar, oldHeight);
- Transition.cancel([ el, dropbar ]);
- return Transition.start([ el, dropbar ], {
- height: newHeight
- }, this.duration).catch(noop).then(function() {
- return css(el, {
- height: "",
- overflow: ""
- });
- });
- }
- }
- });
- }
- var scroll;
- function Offcanvas(UIkit) {
- UIkit.component("offcanvas", {
- mixins: [ Modal ],
- args: "mode",
- props: {
- content: String,
- mode: String,
- flip: Boolean,
- overlay: Boolean
- },
- defaults: {
- content: ".uk-offcanvas-content",
- mode: "slide",
- flip: false,
- overlay: false,
- clsPage: "uk-offcanvas-page",
- clsContainer: "uk-offcanvas-container",
- selPanel: ".uk-offcanvas-bar",
- clsFlip: "uk-offcanvas-flip",
- clsContent: "uk-offcanvas-content",
- clsContentAnimation: "uk-offcanvas-content-animation",
- clsSidebarAnimation: "uk-offcanvas-bar-animation",
- clsMode: "uk-offcanvas",
- clsOverlay: "uk-offcanvas-overlay",
- selClose: ".uk-offcanvas-close"
- },
- computed: {
- content: function content(ref) {
- var content = ref.content;
- return $(content) || document.body;
- },
- clsFlip: function clsFlip(ref) {
- var flip = ref.flip;
- var clsFlip = ref.clsFlip;
- return flip ? clsFlip : "";
- },
- clsOverlay: function clsOverlay(ref) {
- var overlay = ref.overlay;
- var clsOverlay = ref.clsOverlay;
- return overlay ? clsOverlay : "";
- },
- clsMode: function clsMode(ref) {
- var mode = ref.mode;
- var clsMode = ref.clsMode;
- return clsMode + "-" + mode;
- },
- clsSidebarAnimation: function clsSidebarAnimation(ref) {
- var mode = ref.mode;
- var clsSidebarAnimation = ref.clsSidebarAnimation;
- return mode === "none" || mode === "reveal" ? "" : clsSidebarAnimation;
- },
- clsContentAnimation: function clsContentAnimation(ref) {
- var mode = ref.mode;
- var clsContentAnimation = ref.clsContentAnimation;
- return mode !== "push" && mode !== "reveal" ? "" : clsContentAnimation;
- },
- transitionElement: function transitionElement(ref) {
- var mode = ref.mode;
- return mode === "reveal" ? this.panel.parentNode : this.panel;
- }
- },
- update: {
- write: function write() {
- if (this.getActive() === this) {
- if (this.overlay || this.clsContentAnimation) {
- width(this.content, width(window) - this.scrollbarWidth);
- }
- if (this.overlay) {
- height(this.content, height(window));
- if (scroll) {
- this.content.scrollTop = scroll.y;
- }
- }
- }
- },
- events: [ "resize" ]
- },
- events: [ {
- name: "click",
- delegate: function delegate() {
- return 'a[href^="#"]';
- },
- handler: function handler(ref) {
- var current = ref.current;
- if (current.hash && $(current.hash, this.content)) {
- scroll = null;
- this.hide();
- }
- }
- }, {
- name: "beforescroll",
- filter: function filter() {
- return this.overlay;
- },
- handler: function handler(e, scroll, target) {
- if (scroll && target && this.isToggled() && $(target, this.content)) {
- once(this.$el, "hidden", function() {
- return scroll.scrollTo(target);
- });
- e.preventDefault();
- }
- }
- }, {
- name: "show",
- self: true,
- handler: function handler() {
- scroll = scroll || {
- x: window.pageXOffset,
- y: window.pageYOffset
- };
- if (this.mode === "reveal" && !hasClass(this.panel, this.clsMode)) {
- wrapAll(this.panel, "");
- addClass(this.panel.parentNode, this.clsMode);
- }
- css(document.documentElement, "overflowY", (!this.clsContentAnimation || this.flip) && this.scrollbarWidth && this.overlay ? "scroll" : "");
- addClass(document.body, this.clsContainer, this.clsFlip, this.clsOverlay);
- height(document.body);
- addClass(this.content, this.clsContentAnimation);
- addClass(this.panel, this.clsSidebarAnimation, this.mode !== "reveal" ? this.clsMode : "");
- addClass(this.$el, this.clsOverlay);
- css(this.$el, "display", "block");
- height(this.$el);
- }
- }, {
- name: "hide",
- self: true,
- handler: function handler() {
- removeClass(this.content, this.clsContentAnimation);
- var active = this.getActive();
- if (this.mode === "none" || active && active !== this && active !== this.prev) {
- trigger(this.panel, "transitionend");
- }
- }
- }, {
- name: "hidden",
- self: true,
- handler: function handler() {
- if (this.mode === "reveal") {
- unwrap(this.panel);
- }
- if (!this.overlay) {
- scroll = {
- x: window.pageXOffset,
- y: window.pageYOffset
- };
- } else if (!scroll) {
- var ref = this.content;
- var x = ref.scrollLeft;
- var y = ref.scrollTop;
- scroll = {
- x: x,
- y: y
- };
- }
- removeClass(this.panel, this.clsSidebarAnimation, this.clsMode);
- removeClass(this.$el, this.clsOverlay);
- css(this.$el, "display", "");
- removeClass(document.body, this.clsContainer, this.clsFlip, this.clsOverlay);
- document.body.scrollTop = scroll.y;
- css(document.documentElement, "overflowY", "");
- width(this.content, "");
- height(this.content, "");
- window.scrollTo(scroll.x, scroll.y);
- scroll = null;
- }
- }, {
- name: "swipeLeft swipeRight",
- handler: function handler(e) {
- if (this.isToggled() && isTouch(e) && (e.type === "swipeLeft" && !this.flip || e.type === "swipeRight" && this.flip)) {
- this.hide();
- }
- }
- } ]
- });
- }
- function Responsive(UIkit) {
- UIkit.component("responsive", {
- props: [ "width", "height" ],
- init: function init() {
- addClass(this.$el, "uk-responsive-width");
- },
- update: {
- read: function read() {
- return isVisible(this.$el) && this.width && this.height ? {
- width: width(this.$el.parentNode),
- height: this.height
- } : false;
- },
- write: function write(dim) {
- height(this.$el, Dimensions.contain({
- height: this.height,
- width: this.width
- }, dim).height);
- },
- events: [ "load", "resize" ]
- }
- });
- }
- function Scroll(UIkit) {
- UIkit.component("scroll", {
- props: {
- duration: Number,
- offset: Number
- },
- defaults: {
- duration: 1e3,
- offset: 0
- },
- methods: {
- scrollTo: function scrollTo(el) {
- var this$1 = this;
- el = el && $(el) || document.body;
- var docHeight = height(document);
- var winHeight = height(window);
- var target = offset(el).top - this.offset;
- if (target + winHeight > docHeight) {
- target = docHeight - winHeight;
- }
- if (!trigger(this.$el, "beforescroll", [ this, el ])) {
- return;
- }
- var start = Date.now();
- var startY = window.pageYOffset;
- var step = function() {
- var currentY = startY + (target - startY) * ease(clamp((Date.now() - start) / this$1.duration));
- window.scrollTo(window.pageXOffset, currentY);
- if (currentY !== target) {
- requestAnimationFrame(step);
- } else {
- trigger(this$1.$el, "scrolled", [ this$1, el ]);
- }
- };
- step();
- }
- },
- events: {
- click: function click(e) {
- if (e.defaultPrevented) {
- return;
- }
- e.preventDefault();
- this.scrollTo(escape(this.$el.hash).substr(1));
- }
- }
- });
- function ease(k) {
- return .5 * (1 - Math.cos(Math.PI * k));
- }
- }
- function Scrollspy(UIkit) {
- UIkit.component("scrollspy", {
- args: "cls",
- props: {
- cls: "list",
- target: String,
- hidden: Boolean,
- offsetTop: Number,
- offsetLeft: Number,
- repeat: Boolean,
- delay: Number
- },
- defaults: {
- cls: [],
- target: false,
- hidden: true,
- offsetTop: 0,
- offsetLeft: 0,
- repeat: false,
- delay: 0,
- inViewClass: "uk-scrollspy-inview"
- },
- computed: {
- elements: function elements(ref, $el) {
- var target = ref.target;
- return target ? $$(target, $el) : [ $el ];
- }
- },
- update: [ {
- write: function write() {
- if (this.hidden) {
- css(filter(this.elements, ":not(." + this.inViewClass + ")"), "visibility", "hidden");
- }
- }
- }, {
- read: function read(els) {
- var this$1 = this;
- if (!UIkit._initialized) {
- if (document.readyState === "complete") {
- requestAnimationFrame(function() {
- return this$1.$emit();
- });
- }
- return false;
- }
- this.elements.forEach(function(el, i) {
- var elData = els[i];
- if (!elData || elData.el !== el) {
- var cls = data(el, "uk-scrollspy-class");
- elData = {
- el: el,
- toggles: cls && cls.split(",") || this$1.cls
- };
- }
- elData.show = isInView(el, this$1.offsetTop, this$1.offsetLeft);
- els[i] = elData;
- });
- },
- write: function write(els) {
- var this$1 = this;
- var index = this.elements.length === 1 ? 1 : 0;
- this.elements.forEach(function(el, i) {
- var elData = els[i];
- var cls = elData.toggles[i] || elData.toggles[0];
- if (elData.show && !elData.inview && !elData.timer) {
- var show = function() {
- css(el, "visibility", "");
- addClass(el, this$1.inViewClass);
- toggleClass(el, cls);
- trigger(el, "inview");
- UIkit.update(el);
- elData.inview = true;
- delete elData.timer;
- };
- if (this$1.delay && index) {
- elData.timer = setTimeout(show, this$1.delay * index);
- } else {
- show();
- }
- index++;
- } else if (!elData.show && elData.inview && this$1.repeat) {
- if (elData.timer) {
- clearTimeout(elData.timer);
- delete elData.timer;
- }
- css(el, "visibility", this$1.hidden ? "hidden" : "");
- removeClass(el, this$1.inViewClass);
- toggleClass(el, cls);
- trigger(el, "outview");
- UIkit.update(el);
- elData.inview = false;
- }
- });
- },
- events: [ "scroll", "load", "resize" ]
- } ]
- });
- }
- function ScrollspyNav(UIkit) {
- UIkit.component("scrollspy-nav", {
- props: {
- cls: String,
- closest: String,
- scroll: Boolean,
- overflow: Boolean,
- offset: Number
- },
- defaults: {
- cls: "uk-active",
- closest: false,
- scroll: false,
- overflow: true,
- offset: 0
- },
- computed: {
- links: function links(_, $el) {
- return $$('a[href^="#"]', $el).filter(function(el) {
- return el.hash;
- });
- },
- elements: function elements() {
- return this.closest ? closest(this.links, this.closest) : this.links;
- },
- targets: function targets() {
- return $$(this.links.map(function(el) {
- return el.hash;
- }).join(","));
- }
- },
- update: [ {
- read: function read() {
- if (this.scroll) {
- UIkit.scroll(this.links, {
- offset: this.offset || 0
- });
- }
- }
- }, {
- read: function read(data) {
- var this$1 = this;
- var scroll = window.pageYOffset + this.offset + 1;
- var max = height(document) - height(window) + this.offset;
- data.active = false;
- this.targets.every(function(el, i) {
- var ref = offset(el);
- var top = ref.top;
- var last = i + 1 === this$1.targets.length;
- if (!this$1.overflow && (i === 0 && top > scroll || last && top + el.offsetTop < scroll)) {
- return false;
- }
- if (!last && offset(this$1.targets[i + 1]).top <= scroll) {
- return true;
- }
- if (scroll >= max) {
- for (var j = this$1.targets.length - 1; j > i; j--) {
- if (isInView(this$1.targets[j])) {
- el = this$1.targets[j];
- break;
- }
- }
- }
- return !(data.active = $(filter(this$1.links, '[href="#' + el.id + '"]')));
- });
- },
- write: function write(ref) {
- var active = ref.active;
- this.links.forEach(function(el) {
- return el.blur();
- });
- removeClass(this.elements, this.cls);
- if (active) {
- trigger(this.$el, "active", [ active, addClass(this.closest ? closest(active, this.closest) : active, this.cls) ]);
- }
- },
- events: [ "scroll", "load", "resize" ]
- } ]
- });
- }
- function Sticky(UIkit) {
- UIkit.component("sticky", {
- mixins: [ Class ],
- attrs: true,
- props: {
- top: null,
- bottom: Boolean,
- offset: Number,
- animation: String,
- clsActive: String,
- clsInactive: String,
- clsFixed: String,
- clsBelow: String,
- selTarget: String,
- widthElement: "query",
- showOnUp: Boolean,
- media: "media",
- target: Number
- },
- defaults: {
- top: 0,
- bottom: false,
- offset: 0,
- animation: "",
- clsActive: "uk-active",
- clsInactive: "",
- clsFixed: "uk-sticky-fixed",
- clsBelow: "uk-sticky-below",
- selTarget: "",
- widthElement: false,
- showOnUp: false,
- media: false,
- target: false
- },
- computed: {
- selTarget: function selTarget(ref, $el) {
- var selTarget = ref.selTarget;
- return selTarget && $(selTarget, $el) || $el;
- }
- },
- connected: function connected() {
- this.placeholder = $('
');
- this.widthElement = this.$props.widthElement || this.placeholder;
- if (!this.isActive) {
- this.hide();
- }
- },
- disconnected: function disconnected() {
- if (this.isActive) {
- this.isActive = false;
- this.hide();
- removeClass(this.selTarget, this.clsInactive);
- }
- remove(this.placeholder);
- this.placeholder = null;
- this.widthElement = null;
- },
- ready: function ready() {
- var this$1 = this;
- if (!(this.target && location.hash && window.pageYOffset > 0)) {
- return;
- }
- var target = $(location.hash);
- if (target) {
- fastdom.read(function() {
- var ref = offset(target);
- var top = ref.top;
- var elTop = offset(this$1.$el).top;
- var elHeight = this$1.$el.offsetHeight;
- if (elTop + elHeight >= top && elTop <= top + target.offsetHeight) {
- window.scrollTo(0, top - elHeight - this$1.target - this$1.offset);
- }
- });
- }
- },
- events: [ {
- name: "active",
- self: true,
- handler: function handler() {
- replaceClass(this.selTarget, this.clsInactive, this.clsActive);
- }
- }, {
- name: "inactive",
- self: true,
- handler: function handler() {
- replaceClass(this.selTarget, this.clsActive, this.clsInactive);
- }
- } ],
- update: [ {
- write: function write() {
- var ref = this;
- var placeholder = ref.placeholder;
- var outerHeight = (this.isActive ? placeholder : this.$el).offsetHeight;
- css(placeholder, assign({
- height: css(this.$el, "position") !== "absolute" ? outerHeight : ""
- }, css(this.$el, [ "marginTop", "marginBottom", "marginLeft", "marginRight" ])));
- if (!within(placeholder, document)) {
- after(this.$el, placeholder);
- attr(placeholder, "hidden", "");
- }
- attr(this.widthElement, "hidden", null);
- this.width = this.widthElement.offsetWidth;
- attr(this.widthElement, "hidden", this.isActive ? null : "");
- this.topOffset = offset(this.isActive ? placeholder : this.$el).top;
- this.bottomOffset = this.topOffset + outerHeight;
- var bottom = parseProp("bottom", this);
- this.top = Math.max(toFloat(parseProp("top", this)), this.topOffset) - this.offset;
- this.bottom = bottom && bottom - outerHeight;
- this.inactive = this.media && !window.matchMedia(this.media).matches;
- if (this.isActive) {
- this.update();
- }
- },
- events: [ "load", "resize" ]
- }, {
- read: function read(_, ref) {
- var scrollY = ref.scrollY;
- if (scrollY === void 0) scrollY = window.pageYOffset;
- return {
- scroll: this.scroll = scrollY,
- visible: isVisible(this.$el)
- };
- },
- write: function write(ref, ref$1) {
- var this$1 = this;
- var visible = ref.visible;
- var scroll = ref.scroll;
- if (ref$1 === void 0) ref$1 = {};
- var dir = ref$1.dir;
- if (scroll < 0 || !visible || this.disabled || this.showOnUp && !dir) {
- return;
- }
- if (this.inactive || scroll < this.top || this.showOnUp && (scroll <= this.top || dir === "down" || dir === "up" && !this.isActive && scroll <= this.bottomOffset)) {
- if (!this.isActive) {
- return;
- }
- this.isActive = false;
- if (this.animation && scroll > this.topOffset) {
- Animation.cancel(this.$el);
- Animation.out(this.$el, this.animation).then(function() {
- return this$1.hide();
- }, noop);
- } else {
- this.hide();
- }
- } else if (this.isActive) {
- this.update();
- } else if (this.animation) {
- Animation.cancel(this.$el);
- this.show();
- Animation.in(this.$el, this.animation).catch(noop);
- } else {
- this.show();
- }
- },
- events: [ "scroll" ]
- } ],
- methods: {
- show: function show() {
- this.isActive = true;
- this.update();
- attr(this.placeholder, "hidden", null);
- },
- hide: function hide() {
- if (!this.isActive || hasClass(this.selTarget, this.clsActive)) {
- trigger(this.$el, "inactive");
- }
- removeClass(this.$el, this.clsFixed, this.clsBelow);
- css(this.$el, {
- position: "",
- top: "",
- width: ""
- });
- attr(this.placeholder, "hidden", "");
- },
- update: function update() {
- var active = this.top !== 0 || this.scroll > this.top;
- var top = Math.max(0, this.offset);
- if (this.bottom && this.scroll > this.bottom - this.offset) {
- top = this.bottom - this.scroll;
- }
- css(this.$el, {
- position: "fixed",
- top: top + "px",
- width: this.width
- });
- if (hasClass(this.selTarget, this.clsActive)) {
- if (!active) {
- trigger(this.$el, "inactive");
- }
- } else if (active) {
- trigger(this.$el, "active");
- }
- toggleClass(this.$el, this.clsBelow, this.scroll > this.bottomOffset);
- addClass(this.$el, this.clsFixed);
- }
- }
- });
- function parseProp(prop, ref) {
- var $props = ref.$props;
- var $el = ref.$el;
- var propOffset = ref[prop + "Offset"];
- var value = $props[prop];
- if (!value) {
- return;
- }
- if (isNumeric(value)) {
- return propOffset + toFloat(value);
- } else if (isString(value) && value.match(/^-?\d+vh$/)) {
- return height(window) * toFloat(value) / 100;
- } else {
- var el = value === true ? $el.parentNode : query(value, $el);
- if (el) {
- return offset(el).top + el.offsetHeight;
- }
- }
- }
- }
- var svgs = {};
- function Svg(UIkit) {
- UIkit.component("svg", {
- attrs: true,
- props: {
- id: String,
- icon: String,
- src: String,
- style: String,
- width: Number,
- height: Number,
- ratio: Number,
- class: String
- },
- defaults: {
- ratio: 1,
- id: false,
- exclude: [ "src" ],
- class: ""
- },
- init: function init() {
- this.class += " uk-svg";
- },
- connected: function connected() {
- var this$1 = this;
- if (!this.icon && includes(this.src, "#")) {
- var parts = this.src.split("#");
- if (parts.length > 1) {
- var assign;
- assign = parts, this.src = assign[0], this.icon = assign[1];
- }
- }
- this.svg = this.getSvg().then(function(svg) {
- var el;
- if (isString(svg)) {
- if (this$1.icon && includes(svg, "
/g;
- var symbols = {};
- function parseSymbols(svg, icon) {
- if (!symbols[svg]) {
- symbols[svg] = {};
- var match;
- while (match = symbolRe.exec(svg)) {
- symbols[svg][match[3]] = '";
- }
- }
- return symbols[svg][icon];
- }
- }
- function Switcher(UIkit) {
- UIkit.component("switcher", {
- mixins: [ Togglable ],
- args: "connect",
- props: {
- connect: String,
- toggle: String,
- active: Number,
- swiping: Boolean
- },
- defaults: {
- connect: "~.uk-switcher",
- toggle: "> *",
- active: 0,
- swiping: true,
- cls: "uk-active",
- clsContainer: "uk-switcher",
- attrItem: "uk-switcher-item",
- queued: true
- },
- computed: {
- connects: function connects(ref, $el) {
- var connect = ref.connect;
- return queryAll(connect, $el);
- },
- toggles: function toggles(ref, $el) {
- var toggle = ref.toggle;
- return $$(toggle, $el);
- }
- },
- events: [ {
- name: "click",
- delegate: function delegate() {
- return this.toggle + ":not(.uk-disabled)";
- },
- handler: function handler(e) {
- e.preventDefault();
- this.show(e.current);
- }
- }, {
- name: "click",
- el: function el() {
- return this.connects;
- },
- delegate: function delegate() {
- return "[" + this.attrItem + "],[data-" + this.attrItem + "]";
- },
- handler: function handler(e) {
- e.preventDefault();
- this.show(data(e.current, this.attrItem));
- }
- }, {
- name: "swipeRight swipeLeft",
- filter: function filter() {
- return this.swiping;
- },
- el: function el() {
- return this.connects;
- },
- handler: function handler(e) {
- if (!isTouch(e)) {
- return;
- }
- e.preventDefault();
- if (!window.getSelection().toString()) {
- this.show(e.type === "swipeLeft" ? "next" : "previous");
- }
- }
- } ],
- update: function update() {
- var this$1 = this;
- this.connects.forEach(function(list) {
- return this$1.updateAria(list.children);
- });
- this.show(filter(this.toggles, "." + this.cls)[0] || this.toggles[this.active] || this.toggles[0]);
- },
- methods: {
- show: function show(item) {
- var this$1 = this;
- var ref = this.toggles;
- var length = ref.length;
- var prev = !!this.connects.length && index(filter(this.connects[0].children, "." + this.cls)[0]);
- var hasPrev = prev >= 0;
- var dir = item === "previous" ? -1 : 1;
- var toggle, next = getIndex(item, this.toggles, prev);
- for (var i = 0; i < length; i++, next = (next + dir + length) % length) {
- if (!matches(this$1.toggles[next], ".uk-disabled, [disabled]")) {
- toggle = this$1.toggles[next];
- break;
- }
- }
- if (!toggle || prev >= 0 && hasClass(toggle, this.cls) || prev === next) {
- return;
- }
- removeClass(this.toggles, this.cls);
- attr(this.toggles, "aria-expanded", false);
- addClass(toggle, this.cls);
- attr(toggle, "aria-expanded", true);
- this.connects.forEach(function(list) {
- if (!hasPrev) {
- this$1.toggleNow(list.children[next]);
- } else {
- this$1.toggleElement([ list.children[prev], list.children[next] ]);
- }
- });
- }
- }
- });
- }
- function Tab(UIkit) {
- UIkit.component("tab", UIkit.components.switcher.extend({
- mixins: [ Class ],
- name: "tab",
- props: {
- media: "media"
- },
- defaults: {
- media: 960,
- attrItem: "uk-tab-item"
- },
- init: function init() {
- var cls = hasClass(this.$el, "uk-tab-left") ? "uk-tab-left" : hasClass(this.$el, "uk-tab-right") ? "uk-tab-right" : false;
- if (cls) {
- UIkit.toggle(this.$el, {
- cls: cls,
- mode: "media",
- media: this.media
- });
- }
- }
- }));
- }
- function Toggle(UIkit) {
- UIkit.component("toggle", {
- mixins: [ UIkit.mixin.togglable ],
- args: "target",
- props: {
- href: String,
- target: null,
- mode: "list",
- media: "media"
- },
- defaults: {
- href: false,
- target: false,
- mode: "click",
- queued: true,
- media: false
- },
- computed: {
- target: function target(ref, $el) {
- var href = ref.href;
- var target = ref.target;
- target = queryAll(target || href, $el);
- return target.length && target || [ $el ];
- }
- },
- events: [ {
- name: pointerEnter + " " + pointerLeave,
- filter: function filter() {
- return includes(this.mode, "hover");
- },
- handler: function handler(e) {
- if (!isTouch(e)) {
- this.toggle("toggle" + (e.type === pointerEnter ? "show" : "hide"));
- }
- }
- }, {
- name: "click",
- filter: function filter() {
- return includes(this.mode, "click") || hasTouch;
- },
- handler: function handler(e) {
- if (!isTouch(e) && !includes(this.mode, "click")) {
- return;
- }
- var link;
- if (closest(e.target, 'a[href="#"], button') || (link = closest(e.target, "a[href]")) && (this.cls || !isVisible(this.target) || link.hash && matches(this.target, link.hash))) {
- once(document, "click", function(e) {
- return e.preventDefault();
- });
- }
- this.toggle();
- }
- } ],
- update: {
- write: function write() {
- if (!includes(this.mode, "media") || !this.media) {
- return;
- }
- var toggled = this.isToggled(this.target);
- if (window.matchMedia(this.media).matches ? !toggled : toggled) {
- this.toggle();
- }
- },
- events: [ "load", "resize" ]
- },
- methods: {
- toggle: function toggle(type) {
- if (trigger(this.target, type || "toggle", [ this ])) {
- this.toggleElement(this.target);
- }
- }
- }
- });
- }
- function Video(UIkit) {
- UIkit.component("video", {
- args: "autoplay",
- props: {
- automute: Boolean,
- autoplay: Boolean
- },
- defaults: {
- automute: false,
- autoplay: true
- },
- computed: {
- inView: function inView(ref) {
- var autoplay = ref.autoplay;
- return autoplay === "inview";
- }
- },
- connected: function connected() {
- if (this.inView && !hasAttr(this.$el, "preload")) {
- this.$el.preload = "none";
- }
- },
- ready: function ready() {
- this.player = new Player(this.$el);
- if (this.automute) {
- this.player.mute();
- }
- },
- update: [ {
- read: function read(_, ref) {
- var type = ref.type;
- return !this.player || (type === "scroll" || type === "resize") && !this.inView ? false : {
- visible: isVisible(this.$el) && css(this.$el, "visibility") !== "hidden",
- inView: this.inView && isInView(this.$el)
- };
- },
- write: function write(ref) {
- var visible = ref.visible;
- var inView = ref.inView;
- if (!visible || this.inView && !inView) {
- this.player.pause();
- } else if (this.autoplay === true || this.inView && inView) {
- this.player.play();
- }
- },
- events: [ "load", "resize", "scroll" ]
- } ]
- });
- }
- function core(UIkit) {
- UIkit.use(Toggle);
- UIkit.use(Accordion);
- UIkit.use(Alert);
- UIkit.use(Video);
- UIkit.use(Cover);
- UIkit.use(Drop);
- UIkit.use(Dropdown);
- UIkit.use(FormCustom);
- UIkit.use(HeightMatch);
- UIkit.use(HeightViewport);
- UIkit.use(Margin);
- UIkit.use(Gif);
- UIkit.use(Grid);
- UIkit.use(Leader);
- UIkit.use(Modal$1);
- UIkit.use(Nav);
- UIkit.use(Navbar);
- UIkit.use(Offcanvas);
- UIkit.use(Responsive);
- UIkit.use(Scroll);
- UIkit.use(Scrollspy);
- UIkit.use(ScrollspyNav);
- UIkit.use(Sticky);
- UIkit.use(Svg);
- UIkit.use(Icon);
- UIkit.use(Switcher);
- UIkit.use(Tab);
- UIkit.use(Core);
- }
- UIkit$2.version = "3.0.0-beta.42";
- mixin(UIkit$2);
- core(UIkit$2);
- function plugin(UIkit) {
- if (plugin.installed) {
- return;
- }
- var ref = UIkit.util;
- var $ = ref.$;
- var empty = ref.empty;
- var html = ref.html;
- UIkit.component("countdown", {
- mixins: [ UIkit.mixin.class ],
- attrs: true,
- props: {
- date: String,
- clsWrapper: String
- },
- defaults: {
- date: "",
- clsWrapper: ".uk-countdown-%unit%"
- },
- computed: {
- date: function date(ref) {
- var date = ref.date;
- return Date.parse(date);
- },
- days: function days(ref, $el) {
- var clsWrapper = ref.clsWrapper;
- return $(clsWrapper.replace("%unit%", "days"), $el);
- },
- hours: function hours(ref, $el) {
- var clsWrapper = ref.clsWrapper;
- return $(clsWrapper.replace("%unit%", "hours"), $el);
- },
- minutes: function minutes(ref, $el) {
- var clsWrapper = ref.clsWrapper;
- return $(clsWrapper.replace("%unit%", "minutes"), $el);
- },
- seconds: function seconds(ref, $el) {
- var clsWrapper = ref.clsWrapper;
- return $(clsWrapper.replace("%unit%", "seconds"), $el);
- },
- units: function units() {
- var this$1 = this;
- return [ "days", "hours", "minutes", "seconds" ].filter(function(unit) {
- return this$1[unit];
- });
- }
- },
- connected: function connected() {
- this.start();
- },
- disconnected: function disconnected() {
- var this$1 = this;
- this.stop();
- this.units.forEach(function(unit) {
- return empty(this$1[unit]);
- });
- },
- events: [ {
- name: "visibilitychange",
- el: document,
- handler: function handler() {
- if (document.hidden) {
- this.stop();
- } else {
- this.start();
- }
- }
- } ],
- update: {
- write: function write() {
- var this$1 = this;
- var timespan = getTimeSpan(this.date);
- if (timespan.total <= 0) {
- this.stop();
- timespan.days = timespan.hours = timespan.minutes = timespan.seconds = 0;
- }
- this.units.forEach(function(unit) {
- var digits = String(Math.floor(timespan[unit]));
- digits = digits.length < 2 ? "0" + digits : digits;
- var el = this$1[unit];
- if (el.textContent !== digits) {
- digits = digits.split("");
- if (digits.length !== el.children.length) {
- html(el, digits.map(function() {
- return " ";
- }).join(""));
- }
- digits.forEach(function(digit, i) {
- return el.children[i].textContent = digit;
- });
- }
- });
- }
- },
- methods: {
- start: function start() {
- var this$1 = this;
- this.stop();
- if (this.date && this.units.length) {
- this.$emit();
- this.timer = setInterval(function() {
- return this$1.$emit();
- }, 1e3);
- }
- },
- stop: function stop() {
- if (this.timer) {
- clearInterval(this.timer);
- this.timer = null;
- }
- }
- }
- });
- function getTimeSpan(date) {
- var total = date - Date.now();
- return {
- total: total,
- seconds: total / 1e3 % 60,
- minutes: total / 1e3 / 60 % 60,
- hours: total / 1e3 / 60 / 60 % 24,
- days: total / 1e3 / 60 / 60 / 24
- };
- }
- }
- function plugin$1(UIkit) {
- if (plugin$1.installed) {
- return;
- }
- var ref = UIkit.util;
- var addClass = ref.addClass;
- var css = ref.css;
- var scrolledOver = ref.scrolledOver;
- var sortBy = ref.sortBy;
- var toFloat = ref.toFloat;
- UIkit.component("grid-parallax", UIkit.components.grid.extend({
- props: {
- target: String,
- translate: Number
- },
- defaults: {
- target: false,
- translate: 150
- },
- computed: {
- translate: function translate(ref) {
- var translate = ref.translate;
- return Math.abs(translate);
- }
- },
- init: function init() {
- addClass(this.$el, "uk-grid");
- },
- disconnected: function disconnected() {
- this.reset();
- css(this.$el, "marginBottom", "");
- },
- update: [ {
- read: function read(ref) {
- var rows = ref.rows;
- return {
- columns: rows && rows[0] && rows[0].length || 0,
- rows: rows && rows.map(function(elements) {
- return sortBy(elements, "offsetLeft");
- })
- };
- },
- write: function write(ref) {
- var columns = ref.columns;
- css(this.$el, "marginBottom", columns > 1 ? this.translate + toFloat(css(css(this.$el, "marginBottom", ""), "marginBottom")) : "");
- },
- events: [ "load", "resize" ]
- }, {
- read: function read() {
- return {
- scrolled: scrolledOver(this.$el) * this.translate
- };
- },
- write: function write(ref) {
- var rows = ref.rows;
- var columns = ref.columns;
- var scrolled = ref.scrolled;
- if (!rows || columns === 1 || !scrolled) {
- return this.reset();
- }
- rows.forEach(function(row) {
- return row.forEach(function(el, i) {
- return css(el, "transform", "translateY(" + (i % 2 ? scrolled : scrolled / 8) + "px)");
- });
- });
- },
- events: [ "scroll", "load", "resize" ]
- } ],
- methods: {
- reset: function reset() {
- css(this.$el.children, "transform", "");
- }
- }
- }));
- UIkit.components.gridParallax.options.update.unshift({
- read: function read() {
- this.reset();
- },
- events: [ "load", "resize" ]
- });
- }
- function AnimationsPlugin(UIkit) {
- var ref = UIkit.util;
- var css = ref.css;
- var Animations = {
- slide: {
- show: function show(dir) {
- return [ {
- transform: translate(dir * -100)
- }, {
- transform: translate()
- } ];
- },
- percent: function percent(current) {
- return Animations.translated(current);
- },
- translate: function translate$1(percent, dir) {
- return [ {
- transform: translate(dir * -100 * percent)
- }, {
- transform: translate(dir * 100 * (1 - percent))
- } ];
- }
- },
- translated: function translated(el) {
- return Math.abs(css(el, "transform").split(",")[4] / el.offsetWidth) || 0;
- }
- };
- return Animations;
- }
- function translate(value, unit) {
- if (value === void 0) value = 0;
- if (unit === void 0) unit = "%";
- return "translateX(" + value + (value ? unit : "") + ")";
- }
- function scale3d(value) {
- return "scale3d(" + value + ", " + value + ", 1)";
- }
- function TransitionerPlugin(UIkit) {
- var ref = UIkit.util;
- var createEvent = ref.createEvent;
- var clamp = ref.clamp;
- var css = ref.css;
- var Deferred = ref.Deferred;
- var noop = ref.noop;
- var Promise = ref.Promise;
- var Transition = ref.Transition;
- var trigger = ref.trigger;
- function Transitioner(prev, next, dir, ref) {
- var animation = ref.animation;
- var easing = ref.easing;
- var percent = animation.percent;
- var translate = animation.translate;
- var show = animation.show;
- if (show === void 0) show = noop;
- var props = show(dir);
- var deferred = new Deferred();
- return {
- dir: dir,
- show: function show(duration, percent, linear) {
- var this$1 = this;
- if (percent === void 0) percent = 0;
- var timing = linear ? "linear" : easing;
- duration -= Math.round(duration * clamp(percent, -1, 1));
- this.translate(percent);
- triggerUpdate(next, "itemin", {
- percent: percent,
- duration: duration,
- timing: timing,
- dir: dir
- });
- triggerUpdate(prev, "itemout", {
- percent: 1 - percent,
- duration: duration,
- timing: timing,
- dir: dir
- });
- Promise.all([ Transition.start(next, props[1], duration, timing), Transition.start(prev, props[0], duration, timing) ]).then(function() {
- this$1.reset();
- deferred.resolve();
- }, noop);
- return deferred.promise;
- },
- stop: function stop() {
- return Transition.stop([ next, prev ]);
- },
- cancel: function cancel() {
- Transition.cancel([ next, prev ]);
- },
- reset: function reset() {
- for (var prop in props[0]) {
- css([ next, prev ], prop, "");
- }
- },
- forward: function forward(duration, percent) {
- if (percent === void 0) percent = this.percent();
- Transition.cancel([ next, prev ]);
- return this.show(duration, percent, true);
- },
- translate: function translate$1(percent) {
- this.reset();
- var props = translate(percent, dir);
- css(next, props[1]);
- css(prev, props[0]);
- triggerUpdate(next, "itemtranslatein", {
- percent: percent,
- dir: dir
- });
- triggerUpdate(prev, "itemtranslateout", {
- percent: 1 - percent,
- dir: dir
- });
- },
- percent: function percent$1() {
- return percent(prev || next, next, dir);
- },
- getDistance: function getDistance() {
- return prev.offsetWidth;
- }
- };
- }
- function triggerUpdate(el, type, data) {
- trigger(el, createEvent(type, false, false, data));
- }
- return Transitioner;
- }
- function AutoplayMixin(UIkit) {
- var ref = UIkit.util;
- var pointerDown = ref.pointerDown;
- return {
- props: {
- autoplay: Boolean,
- autoplayInterval: Number,
- pauseOnHover: Boolean
- },
- defaults: {
- autoplay: false,
- autoplayInterval: 7e3,
- pauseOnHover: true
- },
- connected: function connected() {
- this.startAutoplay();
- },
- disconnected: function disconnected() {
- this.stopAutoplay();
- },
- events: [ {
- name: "visibilitychange",
- el: document,
- handler: function handler() {
- if (document.hidden) {
- this.stopAutoplay();
- } else {
- this.startAutoplay();
- }
- }
- }, {
- name: pointerDown,
- handler: "stopAutoplay"
- }, {
- name: "mouseenter",
- filter: function filter() {
- return this.autoplay;
- },
- handler: function handler() {
- this.isHovering = true;
- }
- }, {
- name: "mouseleave",
- filter: function filter() {
- return this.autoplay;
- },
- handler: function handler() {
- this.isHovering = false;
- }
- } ],
- methods: {
- startAutoplay: function startAutoplay() {
- var this$1 = this;
- this.stopAutoplay();
- if (this.autoplay) {
- this.interval = setInterval(function() {
- return !(this$1.isHovering && this$1.pauseOnHover) && !this$1.stack.length && this$1.show("next");
- }, this.autoplayInterval);
- }
- },
- stopAutoplay: function stopAutoplay() {
- if (this.interval) {
- clearInterval(this.interval);
- }
- }
- }
- };
- }
- function DragMixin(UIkit) {
- var ref = UIkit.util;
- var getPos = ref.getPos;
- var includes = ref.includes;
- var isRtl = ref.isRtl;
- var isTouch = ref.isTouch;
- var off = ref.off;
- var on = ref.on;
- var pointerDown = ref.pointerDown;
- var pointerMove = ref.pointerMove;
- var pointerUp = ref.pointerUp;
- var preventClick = ref.preventClick;
- var trigger = ref.trigger;
- return {
- defaults: {
- threshold: 10,
- preventCatch: false
- },
- init: function init() {
- var this$1 = this;
- [ "start", "move", "end" ].forEach(function(key) {
- var fn = this$1[key];
- this$1[key] = function(e) {
- var pos = getPos(e).x * (isRtl ? -1 : 1);
- this$1.prevPos = pos !== this$1.pos ? this$1.pos : this$1.prevPos;
- this$1.pos = pos;
- fn(e);
- };
- });
- },
- events: [ {
- name: pointerDown,
- delegate: function delegate() {
- return this.slidesSelector;
- },
- handler: function handler(e) {
- if (!isTouch(e) && hasTextNodesOnly(e.target) || e.button > 0 || this.length < 2 || this.preventCatch) {
- return;
- }
- this.start(e);
- }
- }, {
- name: "dragstart",
- handler: function handler(e) {
- e.preventDefault();
- }
- } ],
- methods: {
- start: function start() {
- this.drag = this.pos;
- if (this._transitioner) {
- this.percent = this._transitioner.percent();
- this.drag += this._transitioner.getDistance() * this.percent * this.dir;
- this._transitioner.translate(this.percent);
- this._transitioner.cancel();
- this.dragging = true;
- this.stack = [];
- } else {
- this.prevIndex = this.index;
- }
- this.unbindMove = on(document, pointerMove, this.move, {
- capture: true,
- passive: false
- });
- on(window, "scroll", this.unbindMove);
- on(document, pointerUp, this.end, true);
- },
- move: function move(e) {
- var this$1 = this;
- var distance = this.pos - this.drag;
- if (distance === 0 || this.prevPos === this.pos || !this.dragging && Math.abs(distance) < this.threshold) {
- return;
- }
- e.cancelable && e.preventDefault();
- this.dragging = true;
- this.dir = distance < 0 ? 1 : -1;
- var ref = this;
- var slides = ref.slides;
- var ref$1 = this;
- var prevIndex = ref$1.prevIndex;
- var dis = Math.abs(distance);
- var nextIndex = this.getIndex(prevIndex + this.dir, prevIndex);
- var width = this._getDistance(prevIndex, nextIndex) || slides[prevIndex].offsetWidth;
- while (nextIndex !== prevIndex && dis > width) {
- this$1.drag -= width * this$1.dir;
- prevIndex = nextIndex;
- dis -= width;
- nextIndex = this$1.getIndex(prevIndex + this$1.dir, prevIndex);
- width = this$1._getDistance(prevIndex, nextIndex) || slides[prevIndex].offsetWidth;
- }
- this.percent = dis / width;
- var prev = slides[prevIndex];
- var next = slides[nextIndex];
- var changed = this.index !== nextIndex;
- var edge = prevIndex === nextIndex;
- var itemShown;
- [ this.index, this.prevIndex ].filter(function(i) {
- return !includes([ nextIndex, prevIndex ], i);
- }).forEach(function(i) {
- trigger(slides[i], "itemhidden", [ this$1 ]);
- if (edge) {
- itemShown = true;
- this$1.prevIndex = prevIndex;
- }
- });
- if (this.index === prevIndex && this.prevIndex !== prevIndex || itemShown) {
- trigger(slides[this.index], "itemshown", [ this ]);
- }
- if (changed) {
- this.prevIndex = prevIndex;
- this.index = nextIndex;
- !edge && trigger(prev, "beforeitemhide", [ this ]);
- trigger(next, "beforeitemshow", [ this ]);
- }
- this._transitioner = this._translate(Math.abs(this.percent), prev, !edge && next);
- if (changed) {
- !edge && trigger(prev, "itemhide", [ this ]);
- trigger(next, "itemshow", [ this ]);
- }
- },
- end: function end() {
- off(window, "scroll", this.unbindMove);
- this.unbindMove();
- off(document, pointerUp, this.end, true);
- if (this.dragging) {
- this.dragging = null;
- if (this.index === this.prevIndex) {
- this.percent = 1 - this.percent;
- this.dir *= -1;
- this._show(false, this.index, true);
- this._transitioner = null;
- } else {
- var dirChange = (isRtl ? this.dir * (isRtl ? 1 : -1) : this.dir) < 0 === this.prevPos > this.pos;
- this.index = dirChange ? this.index : this.prevIndex;
- if (dirChange) {
- this.percent = 1 - this.percent;
- }
- this.show(this.dir > 0 && !dirChange || this.dir < 0 && dirChange ? "next" : "previous", true);
- }
- preventClick();
- }
- this.drag = this.percent = null;
- }
- }
- };
- function hasTextNodesOnly(el) {
- return !el.children.length && el.childNodes.length;
- }
- }
- function NavMixin(UIkit) {
- var ref = UIkit.util;
- var $ = ref.$;
- var $$ = ref.$$;
- var data = ref.data;
- var html = ref.html;
- var toggleClass = ref.toggleClass;
- var toNumber = ref.toNumber;
- return {
- defaults: {
- selNav: false
- },
- computed: {
- nav: function nav(ref, $el) {
- var selNav = ref.selNav;
- return $(selNav, $el);
- },
- navItemSelector: function navItemSelector(ref) {
- var attrItem = ref.attrItem;
- return "[" + attrItem + "],[data-" + attrItem + "]";
- },
- navItems: function navItems(_, $el) {
- return $$(this.navItemSelector, $el);
- }
- },
- update: [ {
- write: function write() {
- var this$1 = this;
- if (this.nav && this.length !== this.nav.children.length) {
- html(this.nav, this.slides.map(function(_, i) {
- return " ';
- }).join(""));
- }
- toggleClass($$(this.navItemSelector, this.$el).concat(this.nav), "uk-hidden", !this.maxIndex);
- this.updateNav();
- },
- events: [ "load", "resize" ]
- } ],
- events: [ {
- name: "click",
- delegate: function delegate() {
- return this.navItemSelector;
- },
- handler: function handler(e) {
- e.preventDefault();
- e.current.blur();
- this.show(data(e.current, this.attrItem));
- }
- }, {
- name: "itemshow",
- handler: "updateNav"
- } ],
- methods: {
- updateNav: function updateNav() {
- var this$1 = this;
- var i = this.getValidIndex();
- this.navItems.forEach(function(el) {
- var cmd = data(el, this$1.attrItem);
- toggleClass(el, this$1.clsActive, toNumber(cmd) === i);
- toggleClass(el, "uk-invisible", this$1.finite && (cmd === "previous" && i === 0 || cmd === "next" && i >= this$1.maxIndex));
- });
- }
- }
- };
- }
- function plugin$5(UIkit) {
- if (plugin$5.installed) {
- return;
- }
- var ref = UIkit.util;
- var $ = ref.$;
- var assign = ref.assign;
- var clamp = ref.clamp;
- var fastdom = ref.fastdom;
- var getIndex = ref.getIndex;
- var hasClass = ref.hasClass;
- var isNumber = ref.isNumber;
- var isRtl = ref.isRtl;
- var Promise = ref.Promise;
- var toNodes = ref.toNodes;
- var trigger = ref.trigger;
- UIkit.mixin.slider = {
- attrs: true,
- mixins: [ AutoplayMixin(UIkit), DragMixin(UIkit), NavMixin(UIkit) ],
- props: {
- clsActivated: Boolean,
- easing: String,
- index: Number,
- finite: Boolean,
- velocity: Number
- },
- defaults: {
- easing: "ease",
- finite: false,
- velocity: 1,
- index: 0,
- stack: [],
- percent: 0,
- clsActive: "uk-active",
- clsActivated: false,
- Transitioner: false,
- transitionOptions: {}
- },
- computed: {
- duration: function duration(ref, $el) {
- var velocity = ref.velocity;
- return speedUp($el.offsetWidth / velocity);
- },
- length: function length() {
- return this.slides.length;
- },
- list: function list(ref, $el) {
- var selList = ref.selList;
- return $(selList, $el);
- },
- maxIndex: function maxIndex() {
- return this.length - 1;
- },
- slidesSelector: function slidesSelector(ref) {
- var selList = ref.selList;
- return selList + " > *";
- },
- slides: function slides() {
- return toNodes(this.list.children);
- }
- },
- methods: {
- show: function show(index, force) {
- var this$1 = this;
- if (force === void 0) force = false;
- if (this.dragging || !this.length) {
- return;
- }
- var ref = this;
- var stack = ref.stack;
- var queueIndex = force ? 0 : stack.length;
- var reset = function() {
- stack.splice(queueIndex, 1);
- if (stack.length) {
- this$1.show(stack.shift(), true);
- }
- };
- stack[force ? "unshift" : "push"](index);
- if (!force && stack.length > 1) {
- if (stack.length === 2) {
- this._transitioner.forward(Math.min(this.duration, 200));
- }
- return;
- }
- var prevIndex = this.index;
- var prev = hasClass(this.slides, this.clsActive) && this.slides[prevIndex];
- var nextIndex = this.getIndex(index, this.index);
- var next = this.slides[nextIndex];
- if (prev === next) {
- reset();
- return;
- }
- this.dir = getDirection(index, prevIndex);
- this.prevIndex = prevIndex;
- this.index = nextIndex;
- prev && trigger(prev, "beforeitemhide", [ this ]);
- if (!trigger(next, "beforeitemshow", [ this, prev ])) {
- this.index = this.prevIndex;
- reset();
- return;
- }
- var promise = this._show(prev, next, force).then(function() {
- prev && trigger(prev, "itemhidden", [ this$1 ]);
- trigger(next, "itemshown", [ this$1 ]);
- return new Promise(function(resolve) {
- fastdom.write(function() {
- stack.shift();
- if (stack.length) {
- this$1.show(stack.shift(), true);
- } else {
- this$1._transitioner = null;
- }
- resolve();
- });
- });
- });
- prev && trigger(prev, "itemhide", [ this ]);
- trigger(next, "itemshow", [ this ]);
- return promise;
- },
- getIndex: function getIndex$1(index, prev) {
- if (index === void 0) index = this.index;
- if (prev === void 0) prev = this.index;
- return clamp(getIndex(index, this.slides, prev, this.finite), 0, this.maxIndex);
- },
- getValidIndex: function getValidIndex(index, prevIndex) {
- if (index === void 0) index = this.index;
- if (prevIndex === void 0) prevIndex = this.prevIndex;
- return this.getIndex(index, prevIndex);
- },
- _show: function _show(prev, next, force) {
- this._transitioner = this._getTransitioner(prev, next, this.dir, assign({
- easing: force ? next.offsetWidth < 600 ? "cubic-bezier(0.25, 0.46, 0.45, 0.94)" : "cubic-bezier(0.165, 0.84, 0.44, 1)" : this.easing
- }, this.transitionOptions));
- if (!force && !prev) {
- this._transitioner.translate(1);
- return Promise.resolve();
- }
- var ref = this.stack;
- var length = ref.length;
- return this._transitioner[length > 1 ? "forward" : "show"](length > 1 ? Math.min(this.duration, 75 + 75 / (length - 1)) : this.duration, this.percent);
- },
- _getDistance: function _getDistance(prev, next) {
- return new this._getTransitioner(prev, prev !== next && next).getDistance();
- },
- _translate: function _translate(percent, prev, next) {
- if (prev === void 0) prev = this.prevIndex;
- if (next === void 0) next = this.index;
- var transitioner = this._getTransitioner(prev !== next ? prev : false, next);
- transitioner.translate(percent);
- return transitioner;
- },
- _getTransitioner: function _getTransitioner(prev, next, dir, options) {
- if (prev === void 0) prev = this.prevIndex;
- if (next === void 0) next = this.index;
- if (dir === void 0) dir = this.dir || 1;
- if (options === void 0) options = this.transitionOptions;
- return new this.Transitioner(isNumber(prev) ? this.slides[prev] : prev, isNumber(next) ? this.slides[next] : next, dir * (isRtl ? -1 : 1), options);
- }
- }
- };
- function getDirection(index, prevIndex) {
- return index === "next" ? 1 : index === "previous" ? -1 : index < prevIndex ? -1 : 1;
- }
- }
- function speedUp(x) {
- return .5 * x + 300;
- }
- function plugin$4(UIkit) {
- if (plugin$4.installed) {
- return;
- }
- UIkit.use(plugin$5);
- var mixin = UIkit.mixin;
- var UIkit_util = UIkit.util;
- var addClass = UIkit_util.addClass;
- var assign = UIkit_util.assign;
- var fastdom = UIkit_util.fastdom;
- var isNumber = UIkit_util.isNumber;
- var removeClass = UIkit_util.removeClass;
- var Animations = AnimationsPlugin(UIkit);
- var Transitioner = TransitionerPlugin(UIkit);
- UIkit.mixin.slideshow = {
- mixins: [ mixin.slider ],
- props: {
- animation: String
- },
- defaults: {
- animation: "slide",
- clsActivated: "uk-transition-active",
- Animations: Animations,
- Transitioner: Transitioner
- },
- computed: {
- animation: function animation(ref) {
- var animation = ref.animation;
- var Animations = ref.Animations;
- return assign(animation in Animations ? Animations[animation] : Animations.slide, {
- name: animation
- });
- },
- transitionOptions: function transitionOptions() {
- return {
- animation: this.animation
- };
- }
- },
- events: {
- "itemshow itemhide itemshown itemhidden": function itemshowitemhideitemshownitemhidden(ref) {
- var target = ref.target;
- UIkit.update(target);
- },
- itemshow: function itemshow() {
- isNumber(this.prevIndex) && fastdom.flush();
- },
- beforeitemshow: function beforeitemshow(ref) {
- var target = ref.target;
- addClass(target, this.clsActive);
- },
- itemshown: function itemshown(ref) {
- var target = ref.target;
- addClass(target, this.clsActivated);
- },
- itemhidden: function itemhidden(ref) {
- var target = ref.target;
- removeClass(target, this.clsActive, this.clsActivated);
- }
- }
- };
- }
- function AnimationsPlugin$1(UIkit) {
- var mixin = UIkit.mixin;
- var UIkit_util = UIkit.util;
- var assign = UIkit_util.assign;
- var css = UIkit_util.css;
- return assign({}, mixin.slideshow.defaults.Animations, {
- fade: {
- show: function show() {
- return [ {
- opacity: 0
- }, {
- opacity: 1
- } ];
- },
- percent: function percent(current) {
- return 1 - css(current, "opacity");
- },
- translate: function translate$$1(percent) {
- return [ {
- opacity: 1 - percent
- }, {
- opacity: percent
- } ];
- }
- },
- scale: {
- show: function show() {
- return [ {
- opacity: 0,
- transform: scale3d(1 - .2)
- }, {
- opacity: 1,
- transform: scale3d(1)
- } ];
- },
- percent: function percent(current) {
- return 1 - css(current, "opacity");
- },
- translate: function translate$$1(percent) {
- return [ {
- opacity: 1 - percent,
- transform: scale3d(1 - .2 * percent)
- }, {
- opacity: percent,
- transform: scale3d(1 - .2 + .2 * percent)
- } ];
- }
- }
- });
- }
- function plugin$3(UIkit) {
- if (plugin$3.installed) {
- return;
- }
- UIkit.use(plugin$4);
- var mixin = UIkit.mixin;
- var util = UIkit.util;
- var $ = util.$;
- var addClass = util.addClass;
- var ajax = util.ajax;
- var append = util.append;
- var assign = util.assign;
- var attr = util.attr;
- var css = util.css;
- var getImage = util.getImage;
- var html = util.html;
- var index = util.index;
- var on = util.on;
- var pointerDown = util.pointerDown;
- var pointerMove = util.pointerMove;
- var removeClass = util.removeClass;
- var Transition = util.Transition;
- var trigger = util.trigger;
- var Animations = AnimationsPlugin$1(UIkit);
- UIkit.component("lightbox-panel", {
- mixins: [ mixin.container, mixin.modal, mixin.togglable, mixin.slideshow ],
- functional: true,
- props: {
- delayControls: Number,
- preload: Number,
- videoAutoplay: Boolean,
- template: String
- },
- defaults: {
- preload: 1,
- videoAutoplay: false,
- delayControls: 3e3,
- items: [],
- cls: "uk-open",
- clsPage: "uk-lightbox-page",
- selList: ".uk-lightbox-items",
- attrItem: "uk-lightbox-item",
- selClose: ".uk-close-large",
- pauseOnHover: false,
- velocity: 2,
- Animations: Animations,
- template: ''
- },
- created: function created() {
- var this$1 = this;
- this.$mount(append(this.container, this.template));
- this.caption = $(".uk-lightbox-caption", this.$el);
- this.items.forEach(function() {
- return append(this$1.list, " ");
- });
- },
- events: [ {
- name: pointerMove + " " + pointerDown + " keydown",
- handler: "showControls"
- }, {
- name: "click",
- self: true,
- delegate: function delegate() {
- return this.slidesSelector;
- },
- handler: function handler(e) {
- e.preventDefault();
- this.hide();
- }
- }, {
- name: "shown",
- self: true,
- handler: "showControls"
- }, {
- name: "hide",
- self: true,
- handler: function handler() {
- this.hideControls();
- removeClass(this.slides, this.clsActive);
- Transition.stop(this.slides);
- }
- }, {
- name: "keyup",
- el: document,
- handler: function handler(e) {
- if (!this.isToggled(this.$el)) {
- return;
- }
- switch (e.keyCode) {
- case 37:
- this.show("previous");
- break;
-
- case 39:
- this.show("next");
- break;
- }
- }
- }, {
- name: "beforeitemshow",
- handler: function handler(e) {
- if (this.isToggled()) {
- return;
- }
- this.preventCatch = true;
- e.preventDefault();
- this.toggleNow(this.$el, true);
- this.animation = Animations["scale"];
- removeClass(e.target, this.clsActive);
- this.stack.splice(1, 0, this.index);
- }
- }, {
- name: "itemshow",
- handler: function handler(ref) {
- var this$1 = this;
- var target = ref.target;
- var i = index(target);
- var ref$1 = this.getItem(i);
- var caption = ref$1.caption;
- css(this.caption, "display", caption ? "" : "none");
- html(this.caption, caption);
- for (var j = 0; j <= this.preload; j++) {
- this$1.loadItem(this$1.getIndex(i + j));
- this$1.loadItem(this$1.getIndex(i - j));
- }
- }
- }, {
- name: "itemshown",
- handler: function handler() {
- this.preventCatch = false;
- }
- }, {
- name: "itemload",
- handler: function handler(_, item) {
- var this$1 = this;
- var source = item.source;
- var type = item.type;
- var alt = item.alt;
- this.setItem(item, " ");
- if (!source) {
- return;
- }
- var matches;
- if (type === "image" || source.match(/\.(jp(e)?g|png|gif|svg)$/i)) {
- getImage(source).then(function(img) {
- return this$1.setItem(item, ' ');
- }, function() {
- return this$1.setError(item);
- });
- } else if (type === "video" || source.match(/\.(mp4|webm|ogv)$/i)) {
- var video = $(" ');
- attr(video, "src", source);
- on(video, "error", function() {
- return this$1.setError(item);
- });
- on(video, "loadedmetadata", function() {
- attr(video, {
- width: video.videoWidth,
- height: video.videoHeight
- });
- this$1.setItem(item, video);
- });
- } else if (type === "iframe") {
- this.setItem(item, '');
- } else if (matches = source.match(/\/\/.*?youtube(-nocookie)?\.[a-z]+\/watch\?v=([^&\s]+)/) || source.match(/()youtu\.be\/(.*)/)) {
- var id = matches[2];
- var setIframe = function(width, height) {
- if (width === void 0) width = 640;
- if (height === void 0) height = 450;
- return this$1.setItem(item, getIframe("//www.youtube" + (matches[1] || "") + ".com/embed/" + id, width, height, this$1.videoAutoplay));
- };
- getImage("//img.youtube.com/vi/" + id + "/maxresdefault.jpg").then(function(ref) {
- var width = ref.width;
- var height = ref.height;
- if (width === 120 && height === 90) {
- getImage("//img.youtube.com/vi/" + id + "/0.jpg").then(function(ref) {
- var width = ref.width;
- var height = ref.height;
- return setIframe(width, height);
- }, setIframe);
- } else {
- setIframe(width, height);
- }
- }, setIframe);
- } else if (matches = source.match(/(\/\/.*?)vimeo\.[a-z]+\/([0-9]+).*?/)) {
- ajax("//vimeo.com/api/oembed.json?maxwidth=1920&url=" + encodeURI(source), {
- responseType: "json"
- }).then(function(ref) {
- var ref_response = ref.response;
- var height = ref_response.height;
- var width = ref_response.width;
- return this$1.setItem(item, getIframe("//player.vimeo.com/video/" + matches[2], width, height, this$1.videoAutoplay));
- });
- }
- }
- } ],
- methods: {
- loadItem: function loadItem(index) {
- if (index === void 0) index = this.index;
- var item = this.getItem(index);
- if (item.content) {
- return;
- }
- trigger(this.$el, "itemload", [ item ]);
- },
- getItem: function getItem(index) {
- if (index === void 0) index = this.index;
- return this.items[index] || {};
- },
- setItem: function setItem(item, content) {
- assign(item, {
- content: content
- });
- var el = html(this.slides[this.items.indexOf(item)], content);
- trigger(this.$el, "itemloaded", [ this, el ]);
- UIkit.update(el);
- },
- setError: function setError(item) {
- this.setItem(item, ' ');
- },
- showControls: function showControls() {
- clearTimeout(this.controlsTimer);
- this.controlsTimer = setTimeout(this.hideControls, this.delayControls);
- addClass(this.$el, "uk-active", "uk-transition-active");
- },
- hideControls: function hideControls() {
- removeClass(this.$el, "uk-active", "uk-transition-active");
- }
- }
- });
- function getIframe(src, width, height, autoplay) {
- return '';
- }
- }
- function plugin$2(UIkit) {
- if (plugin$2.installed) {
- return;
- }
- UIkit.use(plugin$3);
- var util = UIkit.util;
- var $$ = util.$$;
- var assign = util.assign;
- var data = util.data;
- var index = util.index;
- var ref = UIkit.components.lightboxPanel;
- var options = ref.options;
- UIkit.component("lightbox", {
- attrs: true,
- props: assign({
- toggle: String
- }, options.props),
- defaults: assign({
- toggle: "a"
- }, Object.keys(options.props).reduce(function(defaults, key) {
- defaults[key] = options.defaults[key];
- return defaults;
- }, {})),
- computed: {
- toggles: function toggles(ref, $el) {
- var toggle = ref.toggle;
- return $$(toggle, $el);
- }
- },
- disconnected: function disconnected() {
- this._destroy();
- },
- events: [ {
- name: "click",
- delegate: function delegate() {
- return this.toggle + ":not(.uk-disabled)";
- },
- handler: function handler(e) {
- e.preventDefault();
- e.current.blur();
- this.show(index(this.toggles, e.current));
- }
- } ],
- update: function update(data) {
- data.toggles = data.toggles || this.toggles;
- if (this.panel && this.animation) {
- this.panel.$props.animation = this.animation;
- this.panel.$emit();
- }
- if (!this.panel || isEqualList(data.toggles, this.toggles)) {
- return;
- }
- data.toggles = this.toggles;
- this._destroy();
- this._init();
- },
- methods: {
- _init: function _init() {
- return this.panel = this.panel || UIkit.lightboxPanel(assign({}, this.$props, {
- items: this.toggles.reduce(function(items, el) {
- items.push([ "href", "caption", "type", "poster", "alt" ].reduce(function(obj, attr) {
- obj[attr === "href" ? "source" : attr] = data(el, attr);
- return obj;
- }, {}));
- return items;
- }, [])
- }));
- },
- _destroy: function _destroy() {
- if (this.panel) {
- this.panel.$destroy(true);
- this.panel = null;
- }
- },
- show: function show(index) {
- if (!this.panel) {
- this._init();
- }
- return this.panel.show(index);
- },
- hide: function hide() {
- return this.panel && this.panel.hide();
- }
- }
- });
- function isEqualList(listA, listB) {
- return listA.length === listB.length && listA.every(function(el, i) {
- return el === listB[i];
- });
- }
- }
- function plugin$6(UIkit) {
- var obj;
- if (plugin$6.installed) {
- return;
- }
- var ref = UIkit.util;
- var append = ref.append;
- var apply = ref.apply;
- var closest = ref.closest;
- var css = ref.css;
- var pointerEnter = ref.pointerEnter;
- var pointerLeave = ref.pointerLeave;
- var remove = ref.remove;
- var toFloat = ref.toFloat;
- var Transition = ref.Transition;
- var trigger = ref.trigger;
- var containers = {};
- UIkit.component("notification", {
- functional: true,
- args: [ "message", "status" ],
- defaults: {
- message: "",
- status: "",
- timeout: 5e3,
- group: null,
- pos: "top-center",
- clsClose: "uk-notification-close",
- clsMsg: "uk-notification-message"
- },
- created: function created() {
- if (!containers[this.pos]) {
- containers[this.pos] = append(UIkit.container, '
');
- }
- var container = css(containers[this.pos], "display", "block");
- this.$mount(append(container, '"));
- },
- ready: function ready() {
- var this$1 = this;
- var marginBottom = toFloat(css(this.$el, "marginBottom"));
- Transition.start(css(this.$el, {
- opacity: 0,
- marginTop: -this.$el.offsetHeight,
- marginBottom: 0
- }), {
- opacity: 1,
- marginTop: 0,
- marginBottom: marginBottom
- }).then(function() {
- if (this$1.timeout) {
- this$1.timer = setTimeout(this$1.close, this$1.timeout);
- }
- });
- },
- events: (obj = {
- click: function click(e) {
- if (closest(e.target, 'a[href="#"]')) {
- e.preventDefault();
- }
- this.close();
- }
- }, obj[pointerEnter] = function() {
- if (this.timer) {
- clearTimeout(this.timer);
- }
- }, obj[pointerLeave] = function() {
- if (this.timeout) {
- this.timer = setTimeout(this.close, this.timeout);
- }
- }, obj),
- methods: {
- close: function close(immediate) {
- var this$1 = this;
- var removeFn = function() {
- trigger(this$1.$el, "close", [ this$1 ]);
- remove(this$1.$el);
- if (!containers[this$1.pos].children.length) {
- css(containers[this$1.pos], "display", "none");
- }
- };
- if (this.timer) {
- clearTimeout(this.timer);
- }
- if (immediate) {
- removeFn();
- } else {
- Transition.start(this.$el, {
- opacity: 0,
- marginTop: -this.$el.offsetHeight,
- marginBottom: 0
- }).then(removeFn);
- }
- }
- }
- });
- UIkit.notification.closeAll = function(group, immediate) {
- apply(document.body, function(el) {
- var notification = UIkit.getComponent(el, "notification");
- if (notification && (!group || group === notification.group)) {
- notification.close(immediate);
- }
- });
- };
- }
- function plugin$8(UIkit) {
- if (plugin$8.installed) {
- return;
- }
- var mixin = UIkit.mixin;
- var util = UIkit.util;
- var css = util.css;
- var Dimensions = util.Dimensions;
- var each = util.each;
- var getImage = util.getImage;
- var includes = util.includes;
- var isNumber = util.isNumber;
- var isUndefined = util.isUndefined;
- var toFloat = util.toFloat;
- var props = [ "x", "y", "bgx", "bgy", "rotate", "scale", "color", "backgroundColor", "borderColor", "opacity", "blur", "hue", "grayscale", "invert", "saturate", "sepia", "fopacity" ];
- mixin.parallax = {
- props: props.reduce(function(props, prop) {
- props[prop] = "list";
- return props;
- }, {
- media: "media"
- }),
- defaults: props.reduce(function(defaults, prop) {
- defaults[prop] = undefined;
- return defaults;
- }, {
- media: false
- }),
- computed: {
- props: function props$1(properties, $el) {
- var this$1 = this;
- return props.reduce(function(props, prop) {
- if (isUndefined(properties[prop])) {
- return props;
- }
- var isColor = prop.match(/color/i);
- var isCssProp = isColor || prop === "opacity";
- var pos, bgPos, diff;
- var steps = properties[prop].slice(0);
- if (isCssProp) {
- css($el, prop, "");
- }
- if (steps.length < 2) {
- steps.unshift((prop === "scale" ? 1 : isCssProp ? css($el, prop) : 0) || 0);
- }
- var unit = includes(steps.join(""), "%") ? "%" : "px";
- if (isColor) {
- var ref = $el.style;
- var color = ref.color;
- steps = steps.map(function(step) {
- return parseColor($el, step);
- });
- $el.style.color = color;
- } else {
- steps = steps.map(toFloat);
- }
- if (prop.match(/^bg/)) {
- css($el, "background-position-" + prop[2], "");
- bgPos = css($el, "backgroundPosition").split(" ")[prop[2] === "x" ? 0 : 1];
- if (this$1.covers) {
- var min = Math.min.apply(Math, steps);
- var max = Math.max.apply(Math, steps);
- var down = steps.indexOf(min) < steps.indexOf(max);
- diff = max - min;
- steps = steps.map(function(step) {
- return step - (down ? min : max);
- });
- pos = (down ? -diff : 0) + "px";
- } else {
- pos = bgPos;
- }
- }
- props[prop] = {
- steps: steps,
- unit: unit,
- pos: pos,
- bgPos: bgPos,
- diff: diff
- };
- return props;
- }, {});
- },
- bgProps: function bgProps() {
- var this$1 = this;
- return [ "bgx", "bgy" ].filter(function(bg) {
- return bg in this$1.props;
- });
- },
- covers: function covers$1(_, $el) {
- return covers($el);
- }
- },
- disconnected: function disconnected() {
- delete this._image;
- },
- update: [ {
- read: function read(data) {
- var this$1 = this;
- data.active = !this.media || window.matchMedia(this.media).matches;
- if (data.image) {
- data.image.dimEl = {
- width: this.$el.offsetWidth,
- height: this.$el.offsetHeight
- };
- }
- if ("image" in data || !this.covers || !this.bgProps.length) {
- return;
- }
- var src = css(this.$el, "backgroundImage").replace(/^none|url\(["']?(.+?)["']?\)$/, "$1");
- if (!src) {
- return;
- }
- data.image = false;
- getImage(src).then(function(img) {
- data.image = {
- width: img.naturalWidth,
- height: img.naturalHeight
- };
- this$1.$emit();
- });
- },
- write: function write(ref) {
- var this$1 = this;
- var image = ref.image;
- var active = ref.active;
- if (!image) {
- return;
- }
- if (!active) {
- css(this.$el, {
- backgroundSize: "",
- backgroundRepeat: ""
- });
- return;
- }
- var dimEl = image.dimEl;
- var dim = Dimensions.cover(image, dimEl);
- this.bgProps.forEach(function(prop) {
- var ref = this$1.props[prop];
- var diff = ref.diff;
- var bgPos = ref.bgPos;
- var steps = ref.steps;
- var attr = prop === "bgy" ? "height" : "width";
- var span = dim[attr] - dimEl[attr];
- if (!bgPos.match(/%$|0px/)) {
- return;
- }
- if (span < diff) {
- dimEl[attr] = dim[attr] + diff - span;
- } else if (span > diff) {
- var bgPosFloat = parseFloat(bgPos);
- if (bgPosFloat) {
- this$1.props[prop].steps = steps.map(function(step) {
- return step - (span - diff) / (100 / bgPosFloat);
- });
- }
- }
- dim = Dimensions.cover(image, dimEl);
- });
- css(this.$el, {
- backgroundSize: dim.width + "px " + dim.height + "px",
- backgroundRepeat: "no-repeat"
- });
- },
- events: [ "load", "resize" ]
- } ],
- methods: {
- reset: function reset() {
- var this$1 = this;
- each(this.getCss(0), function(_, prop) {
- return css(this$1.$el, prop, "");
- });
- },
- getCss: function getCss(percent) {
- var ref = this;
- var props = ref.props;
- var translated = false;
- return Object.keys(props).reduce(function(css, prop) {
- var ref = props[prop];
- var steps = ref.steps;
- var unit = ref.unit;
- var pos = ref.pos;
- var value = getValue(steps, percent);
- switch (prop) {
- case "x":
- case "y":
- if (translated) {
- break;
- }
- var ref$1 = [ "x", "y" ].map(function(dir) {
- return prop === dir ? value + unit : props[dir] ? getValue(props[dir].steps, percent) + props[dir].unit : 0;
- });
- var x = ref$1[0];
- var y = ref$1[1];
- translated = css.transform += " translate3d(" + x + ", " + y + ", 0)";
- break;
-
- case "rotate":
- css.transform += " rotate(" + value + "deg)";
- break;
-
- case "scale":
- css.transform += " scale(" + value + ")";
- break;
-
- case "bgy":
- case "bgx":
- css["background-position-" + prop[2]] = "calc(" + pos + " + " + (value + unit) + ")";
- break;
-
- case "color":
- case "backgroundColor":
- case "borderColor":
- var ref$2 = getStep(steps, percent);
- var start = ref$2[0];
- var end = ref$2[1];
- var p = ref$2[2];
- css[prop] = "rgba(" + start.map(function(value, i) {
- value = value + p * (end[i] - value);
- return i === 3 ? toFloat(value) : parseInt(value, 10);
- }).join(",") + ")";
- break;
-
- case "blur":
- css.filter += " blur(" + value + "px)";
- break;
-
- case "hue":
- css.filter += " hue-rotate(" + value + "deg)";
- break;
-
- case "fopacity":
- css.filter += " opacity(" + value + "%)";
- break;
-
- case "grayscale":
- case "invert":
- case "saturate":
- case "sepia":
- css.filter += " " + prop + "(" + value + "%)";
- break;
-
- default:
- css[prop] = value;
- }
- return css;
- }, {
- transform: "",
- filter: ""
- });
- }
- }
- };
- function parseColor(el, color) {
- return css(css(el, "color", color), "color").split(/[(),]/g).slice(1, -1).concat(1).slice(0, 4).map(function(n) {
- return toFloat(n);
- });
- }
- function getStep(steps, percent) {
- var count = steps.length - 1;
- var index = Math.min(Math.floor(count * percent), count - 1);
- var step = steps.slice(index, index + 2);
- step.push(percent === 1 ? 1 : percent % (1 / count) * count);
- return step;
- }
- function getValue(steps, percent) {
- var ref = getStep(steps, percent);
- var start = ref[0];
- var end = ref[1];
- var p = ref[2];
- return (isNumber(start) ? start + Math.abs(start - end) * p * (start < end ? 1 : -1) : +end).toFixed(2);
- }
- function covers(el) {
- var ref = el.style;
- var backgroundSize = ref.backgroundSize;
- var covers = css(css(el, "backgroundSize", ""), "backgroundSize") === "cover";
- el.style.backgroundSize = backgroundSize;
- return covers;
- }
- }
- function plugin$7(UIkit) {
- if (plugin$7.installed) {
- return;
- }
- UIkit.use(plugin$8);
- var mixin = UIkit.mixin;
- var util = UIkit.util;
- var clamp = util.clamp;
- var css = util.css;
- var scrolledOver = util.scrolledOver;
- var query = util.query;
- UIkit.component("parallax", {
- mixins: [ mixin.parallax ],
- props: {
- target: String,
- viewport: Number,
- easing: Number
- },
- defaults: {
- target: false,
- viewport: 1,
- easing: 1
- },
- computed: {
- target: function target(ref, $el) {
- var target = ref.target;
- return target && query(target, $el) || $el;
- }
- },
- update: [ {
- read: function read(ref) {
- var percent = ref.percent;
- return {
- prev: percent,
- percent: ease(scrolledOver(this.target) / (this.viewport || 1), this.easing)
- };
- },
- write: function write(ref, ref$1) {
- var prev = ref.prev;
- var percent = ref.percent;
- var active = ref.active;
- var type = ref$1.type;
- if (type !== "scroll") {
- prev = false;
- }
- if (!active) {
- this.reset();
- return;
- }
- if (prev !== percent) {
- css(this.$el, this.getCss(percent));
- }
- },
- events: [ "scroll", "load", "resize" ]
- } ]
- });
- function ease(percent, easing) {
- return clamp(percent * (1 - (easing - easing * percent)));
- }
- }
- function SliderReactive(UIkit) {
- var ref = UIkit.util;
- var removeClass = ref.removeClass;
- return {
- update: [ {
- write: function write() {
- if (this.stack.length || this.dragging) {
- return;
- }
- var index = this.getValidIndex();
- delete this.index;
- removeClass(this.slides, this.clsActive, this.clsActivated);
- this.show(index);
- },
- events: [ "load", "resize" ]
- } ]
- };
- }
- function TransitionerPlugin$1(UIkit) {
- var ref = UIkit.util;
- var assign = ref.assign;
- var clamp = ref.clamp;
- var createEvent = ref.createEvent;
- var css = ref.css;
- var Deferred = ref.Deferred;
- var includes = ref.includes;
- var index = ref.index;
- var isRtl = ref.isRtl;
- var noop = ref.noop;
- var sortBy = ref.sortBy;
- var toNodes = ref.toNodes;
- var Transition = ref.Transition;
- var trigger = ref.trigger;
- var Transitioner = assign(function(prev, next, dir, ref) {
- var center = ref.center;
- var easing = ref.easing;
- var list = ref.list;
- var deferred = new Deferred();
- var from = prev ? Transitioner.getLeft(prev, list, center) : Transitioner.getLeft(next, list, center) + next.offsetWidth * dir, to = next ? Transitioner.getLeft(next, list, center) : from + prev.offsetWidth * dir * (isRtl ? -1 : 1);
- return {
- dir: dir,
- show: function show(duration, percent, linear) {
- if (percent === void 0) percent = 0;
- var timing = linear ? "linear" : easing;
- duration -= Math.round(duration * clamp(percent, -1, 1));
- this.translate(percent);
- prev && this.updateTranslates();
- percent = prev ? percent : clamp(percent, 0, 1);
- triggerUpdate(this.getItemIn(), "itemin", {
- percent: percent,
- duration: duration,
- timing: timing,
- dir: dir
- });
- prev && triggerUpdate(this.getItemIn(true), "itemout", {
- percent: 1 - percent,
- duration: duration,
- timing: timing,
- dir: dir
- });
- Transition.start(list, {
- transform: translate(-to * (isRtl ? -1 : 1), "px")
- }, duration, timing).then(deferred.resolve, noop);
- return deferred.promise;
- },
- stop: function stop() {
- return Transition.stop(list);
- },
- cancel: function cancel() {
- Transition.cancel(list);
- },
- reset: function reset() {
- css(list, "transform", "");
- },
- forward: function forward(duration, percent) {
- if (percent === void 0) percent = this.percent();
- Transition.cancel(list);
- return this.show(duration, percent, true);
- },
- translate: function translate$1(percent) {
- var distance = this.getDistance() * dir * (isRtl ? -1 : 1);
- css(list, "transform", translate(clamp(-to + (distance - distance * percent), -Transitioner.getWidth(list), list.offsetWidth) * (isRtl ? -1 : 1), "px"));
- this.updateTranslates();
- if (prev) {
- percent = clamp(percent, -1, 1);
- triggerUpdate(this.getItemIn(), "itemtranslatein", {
- percent: percent,
- dir: dir
- });
- triggerUpdate(this.getItemIn(true), "itemtranslateout", {
- percent: 1 - percent,
- dir: dir
- });
- }
- },
- percent: function percent() {
- return Math.abs((css(list, "transform").split(",")[4] * (isRtl ? -1 : 1) + from) / (to - from));
- },
- getDistance: function getDistance() {
- return Math.abs(to - from);
- },
- getItemIn: function getItemIn(out) {
- if (out === void 0) out = false;
- var actives = this.getActives();
- var all = sortBy(slides(list), "offsetLeft");
- var i = index(all, actives[dir * (out ? -1 : 1) > 0 ? actives.length - 1 : 0]);
- return ~i && all[i + (prev && !out ? dir : 0)];
- },
- getActives: function getActives() {
- var left = Transitioner.getLeft(prev || next, list, center);
- return sortBy(slides(list).filter(function(slide) {
- var slideLeft = Transitioner.getElLeft(slide, list);
- return slideLeft >= left && slideLeft + slide.offsetWidth <= list.offsetWidth + left;
- }), "offsetLeft");
- },
- updateTranslates: function updateTranslates() {
- var actives = this.getActives();
- slides(list).forEach(function(slide) {
- var isActive = includes(actives, slide);
- triggerUpdate(slide, "itemtranslate" + (isActive ? "in" : "out"), {
- percent: isActive ? 1 : 0,
- dir: slide.offsetLeft <= next.offsetLeft ? 1 : -1
- });
- });
- }
- };
- }, {
- getLeft: function getLeft(el, list, center) {
- var left = this.getElLeft(el, list);
- return center ? left - this.center(el, list) : Math.min(left, this.getMax(list));
- },
- getMax: function getMax(list) {
- return Math.max(0, this.getWidth(list) - list.offsetWidth);
- },
- getWidth: function getWidth(list) {
- return slides(list).reduce(function(right, el) {
- return el.offsetWidth + right;
- }, 0);
- },
- getMaxWidth: function getMaxWidth(list) {
- return slides(list).reduce(function(right, el) {
- return Math.max(right, el.offsetWidth);
- }, 0);
- },
- center: function center(el, list) {
- return list.offsetWidth / 2 - el.offsetWidth / 2;
- },
- getElLeft: function getElLeft(el, list) {
- return (el.offsetLeft + (isRtl ? el.offsetWidth - list.offsetWidth : 0)) * (isRtl ? -1 : 1);
- }
- });
- function triggerUpdate(el, type, data) {
- trigger(el, createEvent(type, false, false, data));
- }
- function slides(list) {
- return toNodes(list.children);
- }
- return Transitioner;
- }
- function ParallaxPlugin(UIkit, parent) {
- UIkit.use(plugin$8);
- var mixin = UIkit.mixin;
- var UIkit_util = UIkit.util;
- var closest = UIkit_util.closest;
- var css = UIkit_util.css;
- var endsWith = UIkit_util.endsWith;
- var noop = UIkit_util.noop;
- var Transition = UIkit_util.Transition;
- return {
- mixins: [ mixin.parallax ],
- computed: {
- item: function item() {
- var slider = UIkit.getComponent(closest(this.$el, ".uk-" + parent), parent);
- return slider && closest(this.$el, slider.slidesSelector);
- }
- },
- events: [ {
- name: "itemshown",
- self: true,
- el: function el() {
- return this.item;
- },
- handler: function handler() {
- css(this.$el, this.getCss(.5));
- }
- }, {
- name: "itemin itemout",
- self: true,
- el: function el() {
- return this.item;
- },
- handler: function handler(ref) {
- var type = ref.type;
- var ref_detail = ref.detail;
- var percent = ref_detail.percent;
- var duration = ref_detail.duration;
- var timing = ref_detail.timing;
- var dir = ref_detail.dir;
- Transition.cancel(this.$el);
- css(this.$el, this.getCss(getCurrent(type, dir, percent)));
- Transition.start(this.$el, this.getCss(isIn(type) ? .5 : dir > 0 ? 1 : 0), duration, timing).catch(noop);
- }
- }, {
- name: "transitioncanceled transitionend",
- self: true,
- el: function el() {
- return this.item;
- },
- handler: function handler() {
- Transition.cancel(this.$el);
- }
- }, {
- name: "itemtranslatein itemtranslateout",
- self: true,
- el: function el() {
- return this.item;
- },
- handler: function handler(ref) {
- var type = ref.type;
- var ref_detail = ref.detail;
- var percent = ref_detail.percent;
- var dir = ref_detail.dir;
- Transition.cancel(this.$el);
- css(this.$el, this.getCss(getCurrent(type, dir, percent)));
- }
- } ]
- };
- function isIn(type) {
- return endsWith(type, "in");
- }
- function getCurrent(type, dir, percent) {
- percent /= 2;
- return !isIn(type) ? dir < 0 ? percent : 1 - percent : dir < 0 ? 1 - percent : percent;
- }
- }
- function plugin$9(UIkit) {
- if (plugin$9.installed) {
- return;
- }
- UIkit.use(plugin$5);
- var mixin = UIkit.mixin;
- var UIkit_util = UIkit.util;
- var $ = UIkit_util.$;
- var $$ = UIkit_util.$$;
- var addClass = UIkit_util.addClass;
- var css = UIkit_util.css;
- var data = UIkit_util.data;
- var includes = UIkit_util.includes;
- var isNumeric = UIkit_util.isNumeric;
- var isUndefined = UIkit_util.isUndefined;
- var offset = UIkit_util.offset;
- var toggleClass = UIkit_util.toggleClass;
- var toFloat = UIkit_util.toFloat;
- var Transitioner = TransitionerPlugin$1(UIkit);
- UIkit.component("slider-parallax", ParallaxPlugin(UIkit, "slider"));
- UIkit.component("slider", {
- mixins: [ mixin.class, mixin.slider, SliderReactive(UIkit) ],
- props: {
- center: Boolean,
- sets: Boolean
- },
- defaults: {
- center: false,
- sets: false,
- attrItem: "uk-slider-item",
- selList: ".uk-slider-items",
- selNav: ".uk-slider-nav",
- clsContainer: "uk-slider-container",
- Transitioner: Transitioner
- },
- computed: {
- avgWidth: function avgWidth() {
- return Transitioner.getWidth(this.list) / this.length;
- },
- finite: function finite(ref) {
- var finite = ref.finite;
- return finite || Transitioner.getWidth(this.list) < this.list.offsetWidth + Transitioner.getMaxWidth(this.list) + this.center;
- },
- maxIndex: function maxIndex() {
- var this$1 = this;
- if (!this.finite || this.center && !this.sets) {
- return this.length - 1;
- }
- if (this.center) {
- return this.sets[this.sets.length - 1];
- }
- css(this.slides, "order", "");
- var max = Transitioner.getMax(this.list);
- var i = this.length;
- while (i--) {
- if (Transitioner.getElLeft(this$1.list.children[i], this$1.list) < max) {
- return Math.min(i + 1, this$1.length - 1);
- }
- }
- return 0;
- },
- sets: function sets(ref) {
- var this$1 = this;
- var sets = ref.sets;
- var width = this.list.offsetWidth / (this.center ? 2 : 1);
- var left = 0;
- var leftCenter = width;
- sets = sets && this.slides.reduce(function(sets, slide, i) {
- var dim = offset(slide);
- if (dim.right > left) {
- if (!this$1.center && i > this$1.maxIndex) {
- i = this$1.maxIndex;
- }
- if (!includes(sets, i)) {
- var cmp = this$1.slides[i + 1];
- if (this$1.center && cmp && dim.width < leftCenter - offset(cmp).width / 2) {
- leftCenter -= dim.width;
- } else {
- leftCenter = width;
- sets.push(i);
- left = dim.left + width + (this$1.center ? dim.width / 2 : 0);
- }
- }
- }
- return sets;
- }, []);
- return sets && sets.length && sets;
- },
- transitionOptions: function transitionOptions() {
- return {
- center: this.center,
- list: this.list
- };
- }
- },
- connected: function connected() {
- toggleClass(this.$el, this.clsContainer, !$("." + this.clsContainer, this.$el));
- },
- update: {
- write: function write() {
- var this$1 = this;
- $$("[" + this.attrItem + "],[data-" + this.attrItem + "]", this.$el).forEach(function(el) {
- var index = data(el, this$1.attrItem);
- this$1.maxIndex && toggleClass(el, "uk-hidden", isNumeric(index) && (this$1.sets && !includes(this$1.sets, toFloat(index)) || index > this$1.maxIndex));
- });
- },
- events: [ "load", "resize" ]
- },
- events: {
- beforeitemshow: function beforeitemshow(e) {
- var this$1 = this;
- if (!this.dragging && this.sets && this.stack.length < 2 && !includes(this.sets, this.index)) {
- this.index = this.getValidIndex();
- }
- var diff = Math.abs(this.index - this.prevIndex + (this.dir > 0 && this.index < this.prevIndex || this.dir < 0 && this.index > this.prevIndex ? (this.maxIndex + 1) * this.dir : 0));
- if (!this.dragging && diff > 1) {
- for (var i = 0; i < diff; i++) {
- this$1.stack.splice(1, 0, this$1.dir > 0 ? "next" : "previous");
- }
- e.preventDefault();
- return;
- }
- this.duration = speedUp(this.avgWidth / this.velocity) * ((this.dir < 0 || !this.slides[this.prevIndex] ? this.slides[this.index] : this.slides[this.prevIndex]).offsetWidth / this.avgWidth);
- this.reorder();
- },
- itemshow: function itemshow() {
- !isUndefined(this.prevIndex) && addClass(this._getTransitioner().getItemIn(), this.clsActive);
- },
- itemshown: function itemshown() {
- var this$1 = this;
- var actives = this._getTransitioner(this.index).getActives();
- this.slides.forEach(function(slide) {
- return toggleClass(slide, this$1.clsActive, includes(actives, slide));
- });
- (!this.sets || includes(this.sets, toFloat(this.index))) && this.slides.forEach(function(slide) {
- return toggleClass(slide, this$1.clsActivated, includes(actives, slide));
- });
- }
- },
- methods: {
- reorder: function reorder() {
- var this$1 = this;
- css(this.slides, "order", "");
- if (this.finite) {
- return;
- }
- var index = this.dir > 0 && this.slides[this.prevIndex] ? this.prevIndex : this.index;
- this.slides.forEach(function(slide, i) {
- return css(slide, "order", this$1.dir > 0 && i < index ? 1 : this$1.dir < 0 && i >= this$1.index ? -1 : "");
- });
- if (!this.center) {
- return;
- }
- var next = this.slides[index];
- var width = this.list.offsetWidth / 2 - next.offsetWidth / 2;
- var j = 0;
- while (width > 0) {
- var slideIndex = this$1.getIndex(--j + index, index);
- var slide = this$1.slides[slideIndex];
- css(slide, "order", slideIndex > index ? -2 : -1);
- width -= slide.offsetWidth;
- }
- },
- getValidIndex: function getValidIndex(index, prevIndex) {
- var this$1 = this;
- if (index === void 0) index = this.index;
- if (prevIndex === void 0) prevIndex = this.prevIndex;
- index = this.getIndex(index, prevIndex);
- if (!this.sets) {
- return index;
- }
- var prev;
- do {
- if (includes(this$1.sets, index)) {
- return index;
- }
- prev = index;
- index = this$1.getIndex(index + this$1.dir, prevIndex);
- } while (index !== prev);
- return index;
- }
- }
- });
- }
- function AnimationsPlugin$2(UIkit) {
- var mixin = UIkit.mixin;
- var UIkit_util = UIkit.util;
- var assign = UIkit_util.assign;
- var css = UIkit_util.css;
- var Animations = assign({}, mixin.slideshow.defaults.Animations, {
- fade: {
- show: function show() {
- return [ {
- opacity: 0,
- zIndex: 0
- }, {
- zIndex: -1
- } ];
- },
- percent: function percent(current) {
- return 1 - css(current, "opacity");
- },
- translate: function translate$$1(percent) {
- return [ {
- opacity: 1 - percent,
- zIndex: 0
- }, {
- zIndex: -1
- } ];
- }
- },
- scale: {
- show: function show() {
- return [ {
- opacity: 0,
- transform: scale3d(1 + .5),
- zIndex: 0
- }, {
- zIndex: -1
- } ];
- },
- percent: function percent(current) {
- return 1 - css(current, "opacity");
- },
- translate: function translate$$1(percent) {
- return [ {
- opacity: 1 - percent,
- transform: scale3d(1 + .5 * percent),
- zIndex: 0
- }, {
- zIndex: -1
- } ];
- }
- },
- pull: {
- show: function show(dir) {
- return dir < 0 ? [ {
- transform: translate(30),
- zIndex: -1
- }, {
- transform: translate(),
- zIndex: 0
- } ] : [ {
- transform: translate(-100),
- zIndex: 0
- }, {
- transform: translate(),
- zIndex: -1
- } ];
- },
- percent: function percent(current, next, dir) {
- return dir < 0 ? 1 - Animations.translated(next) : Animations.translated(current);
- },
- translate: function translate$1(percent, dir) {
- return dir < 0 ? [ {
- transform: translate(30 * percent),
- zIndex: -1
- }, {
- transform: translate(-100 * (1 - percent)),
- zIndex: 0
- } ] : [ {
- transform: translate(-percent * 100),
- zIndex: 0
- }, {
- transform: translate(30 * (1 - percent)),
- zIndex: -1
- } ];
- }
- },
- push: {
- show: function show(dir) {
- return dir < 0 ? [ {
- transform: translate(100),
- zIndex: 0
- }, {
- transform: translate(),
- zIndex: -1
- } ] : [ {
- transform: translate(-30),
- zIndex: -1
- }, {
- transform: translate(),
- zIndex: 0
- } ];
- },
- percent: function percent(current, next, dir) {
- return dir > 0 ? 1 - Animations.translated(next) : Animations.translated(current);
- },
- translate: function translate$2(percent, dir) {
- return dir < 0 ? [ {
- transform: translate(percent * 100),
- zIndex: 0
- }, {
- transform: translate(-30 * (1 - percent)),
- zIndex: -1
- } ] : [ {
- transform: translate(-30 * percent),
- zIndex: -1
- }, {
- transform: translate(100 * (1 - percent)),
- zIndex: 0
- } ];
- }
- }
- });
- return Animations;
- }
- function plugin$10(UIkit) {
- if (plugin$10.installed) {
- return;
- }
- UIkit.use(plugin$4);
- var mixin = UIkit.mixin;
- var height = UIkit.util.height;
- var Animations = AnimationsPlugin$2(UIkit);
- UIkit.component("slideshow-parallax", ParallaxPlugin(UIkit, "slideshow"));
- UIkit.component("slideshow", {
- mixins: [ mixin.class, mixin.slideshow, SliderReactive(UIkit) ],
- props: {
- ratio: String,
- minHeight: Boolean,
- maxHeight: Boolean
- },
- defaults: {
- ratio: "16:9",
- minHeight: false,
- maxHeight: false,
- selList: ".uk-slideshow-items",
- attrItem: "uk-slideshow-item",
- selNav: ".uk-slideshow-nav",
- Animations: Animations
- },
- update: {
- read: function read() {
- var ref = this.ratio.split(":").map(Number);
- var width = ref[0];
- var height = ref[1];
- height = height * this.$el.offsetWidth / width;
- if (this.minHeight) {
- height = Math.max(this.minHeight, height);
- }
- if (this.maxHeight) {
- height = Math.min(this.maxHeight, height);
- }
- return {
- height: height
- };
- },
- write: function write(ref) {
- var hgt = ref.height;
- height(this.list, Math.floor(hgt));
- },
- events: [ "load", "resize" ]
- }
- });
- }
- function plugin$11(UIkit) {
- var obj;
- if (plugin$11.installed) {
- return;
- }
- var mixin = UIkit.mixin;
- var util = UIkit.util;
- var addClass = util.addClass;
- var after = util.after;
- var assign = util.assign;
- var append = util.append;
- var attr = util.attr;
- var before = util.before;
- var closest = util.closest;
- var css = util.css;
- var height = util.height;
- var fastdom = util.fastdom;
- var getPos = util.getPos;
- var includes = util.includes;
- var index = util.index;
- var isInput = util.isInput;
- var noop = util.noop;
- var offset = util.offset;
- var off = util.off;
- var on = util.on;
- var pointerDown = util.pointerDown;
- var pointerMove = util.pointerMove;
- var pointerUp = util.pointerUp;
- var position = util.position;
- var preventClick = util.preventClick;
- var Promise = util.Promise;
- var remove = util.remove;
- var removeClass = util.removeClass;
- var toggleClass = util.toggleClass;
- var toNodes = util.toNodes;
- var Transition = util.Transition;
- var trigger = util.trigger;
- var within = util.within;
- UIkit.component("sortable", {
- mixins: [ mixin.class ],
- props: {
- group: String,
- animation: Number,
- threshold: Number,
- clsItem: String,
- clsPlaceholder: String,
- clsDrag: String,
- clsDragState: String,
- clsBase: String,
- clsNoDrag: String,
- clsEmpty: String,
- clsCustom: String,
- handle: String
- },
- defaults: {
- group: false,
- animation: 150,
- threshold: 5,
- clsItem: "uk-sortable-item",
- clsPlaceholder: "uk-sortable-placeholder",
- clsDrag: "uk-sortable-drag",
- clsDragState: "uk-drag",
- clsBase: "uk-sortable",
- clsNoDrag: "uk-sortable-nodrag",
- clsEmpty: "uk-sortable-empty",
- clsCustom: "",
- handle: false
- },
- init: function init() {
- var this$1 = this;
- [ "init", "start", "move", "end" ].forEach(function(key) {
- var fn = this$1[key];
- this$1[key] = function(e) {
- this$1.scrollY = window.pageYOffset;
- var ref = getPos(e);
- var x = ref.x;
- var y = ref.y;
- this$1.pos = {
- x: x,
- y: y
- };
- fn(e);
- };
- });
- },
- events: (obj = {}, obj[pointerDown] = "init", obj),
- update: {
- write: function write() {
- if (this.clsEmpty) {
- toggleClass(this.$el, this.clsEmpty, !this.$el.children.length);
- }
- if (!this.drag) {
- return;
- }
- offset(this.drag, {
- top: this.pos.y + this.origin.top,
- left: this.pos.x + this.origin.left
- });
- var ref = offset(this.drag);
- var top = ref.top;
- var bottom = top + this.drag.offsetHeight;
- var scroll;
- if (top > 0 && top < this.scrollY) {
- scroll = this.scrollY - 5;
- } else if (bottom < height(document) && bottom > height(window) + this.scrollY) {
- scroll = this.scrollY + 5;
- }
- scroll && setTimeout(function() {
- return window.scrollTo(window.scrollX, scroll);
- }, 5);
- }
- },
- methods: {
- init: function init(e) {
- var target = e.target;
- var button = e.button;
- var defaultPrevented = e.defaultPrevented;
- var ref = toNodes(this.$el.children).filter(function(el) {
- return within(target, el);
- });
- var placeholder = ref[0];
- if (!placeholder || isInput(e.target) || this.handle && !within(target, this.handle) || button > 0 || within(target, "." + this.clsNoDrag) || defaultPrevented) {
- return;
- }
- e.preventDefault();
- this.touched = [ this ];
- this.placeholder = placeholder;
- this.origin = assign({
- target: target,
- index: index(placeholder)
- }, this.pos);
- on(document, pointerMove, this.move);
- on(document, pointerUp, this.end);
- on(window, "scroll", this.scroll);
- if (!this.threshold) {
- this.start(e);
- }
- },
- start: function start(e) {
- this.drag = append(UIkit.container, this.placeholder.outerHTML.replace(/^$/i, "div>"));
- css(this.drag, assign({
- boxSizing: "border-box",
- width: this.placeholder.offsetWidth,
- height: this.placeholder.offsetHeight
- }, css(this.placeholder, [ "paddingLeft", "paddingRight", "paddingTop", "paddingBottom" ])));
- attr(this.drag, "uk-no-boot", "");
- addClass(this.drag, this.clsDrag, this.clsCustom);
- height(this.drag.firstElementChild, height(this.placeholder.firstElementChild));
- var ref = offset(this.placeholder);
- var left = ref.left;
- var top = ref.top;
- assign(this.origin, {
- left: left - this.pos.x,
- top: top - this.pos.y
- });
- addClass(this.placeholder, this.clsPlaceholder);
- addClass(this.$el.children, this.clsItem);
- addClass(document.documentElement, this.clsDragState);
- trigger(this.$el, "start", [ this, this.placeholder, this.drag ]);
- this.move(e);
- },
- move: function move(e) {
- if (!this.drag) {
- if (Math.abs(this.pos.x - this.origin.x) > this.threshold || Math.abs(this.pos.y - this.origin.y) > this.threshold) {
- this.start(e);
- }
- return;
- }
- this.$emit();
- var target = e.type === "mousemove" ? e.target : document.elementFromPoint(this.pos.x - document.body.scrollLeft, this.pos.y - document.body.scrollTop);
- var sortable = getSortable(target);
- var previous = getSortable(this.placeholder);
- var move = sortable !== previous;
- if (!sortable || within(target, this.placeholder) || move && (!sortable.group || sortable.group !== previous.group)) {
- return;
- }
- target = sortable.$el === target.parentNode && target || toNodes(sortable.$el.children).filter(function(element) {
- return within(target, element);
- })[0];
- if (move) {
- previous.remove(this.placeholder);
- } else if (!target) {
- return;
- }
- sortable.insert(this.placeholder, target);
- if (!includes(this.touched, sortable)) {
- this.touched.push(sortable);
- }
- },
- scroll: function scroll() {
- var scroll = window.pageYOffset;
- if (scroll !== this.scrollY) {
- this.pos.y += scroll - this.scrollY;
- this.scrollY = scroll;
- this.$emit();
- }
- },
- end: function end(e) {
- off(document, pointerMove, this.move);
- off(document, pointerUp, this.end);
- off(window, "scroll", this.scroll);
- if (!this.drag) {
- if (e.type !== "mouseup" && within(e.target, "a[href]")) {
- location.href = closest(e.target, "a[href]").href;
- }
- return;
- }
- preventClick();
- var sortable = getSortable(this.placeholder);
- if (this === sortable) {
- if (this.origin.index !== index(this.placeholder)) {
- trigger(this.$el, "moved", [ this, this.placeholder ]);
- }
- } else {
- trigger(sortable.$el, "added", [ sortable, this.placeholder ]);
- trigger(this.$el, "removed", [ this, this.placeholder ]);
- }
- trigger(this.$el, "stop", [ this ]);
- remove(this.drag);
- this.drag = null;
- var classes = this.touched.map(function(sortable) {
- return sortable.clsPlaceholder + " " + sortable.clsItem;
- }).join(" ");
- this.touched.forEach(function(sortable) {
- return removeClass(sortable.$el.children, classes);
- });
- removeClass(document.documentElement, this.clsDragState);
- },
- insert: function insert(element, target) {
- var this$1 = this;
- addClass(this.$el.children, this.clsItem);
- var insert = function() {
- if (target) {
- if (!within(element, this$1.$el) || isPredecessor(element, target)) {
- before(target, element);
- } else {
- after(target, element);
- }
- } else {
- append(this$1.$el, element);
- }
- };
- if (this.animation) {
- this.animate(insert);
- } else {
- insert();
- }
- },
- remove: function remove$1(element) {
- if (!within(element, this.$el)) {
- return;
- }
- if (this.animation) {
- this.animate(function() {
- return remove(element);
- });
- } else {
- remove(element);
- }
- },
- animate: function animate(action) {
- var this$1 = this;
- var props = [];
- var children = toNodes(this.$el.children);
- var reset = {
- position: "",
- width: "",
- height: "",
- pointerEvents: "",
- top: "",
- left: "",
- bottom: "",
- right: ""
- };
- children.forEach(function(el) {
- props.push(assign({
- position: "absolute",
- pointerEvents: "none",
- width: el.offsetWidth,
- height: el.offsetHeight
- }, position(el)));
- });
- action();
- children.forEach(Transition.cancel);
- css(this.$el.children, reset);
- UIkit.update(this.$el);
- fastdom.flush();
- css(this.$el, "minHeight", height(this.$el));
- var positions = children.map(function(el) {
- return position(el);
- });
- Promise.all(children.map(function(el, i) {
- return Transition.start(css(el, props[i]), positions[i], this$1.animation);
- })).then(function() {
- css(this$1.$el, "minHeight", "");
- css(children, reset);
- UIkit.update(this$1.$el);
- fastdom.flush();
- }, noop);
- }
- }
- });
- function getSortable(element) {
- return element && (UIkit.getComponent(element, "sortable") || getSortable(element.parentNode));
- }
- function isPredecessor(element, target) {
- return element.parentNode === target.parentNode && index(element) > index(target);
- }
- }
- function plugin$12(UIkit) {
- var obj;
- if (plugin$12.installed) {
- return;
- }
- var util = UIkit.util;
- var mixin = UIkit.mixin;
- var append = util.append;
- var attr = util.attr;
- var flipPosition = util.flipPosition;
- var hasAttr = util.hasAttr;
- var includes = util.includes;
- var isTouch = util.isTouch;
- var isVisible = util.isVisible;
- var matches = util.matches;
- var on = util.on;
- var pointerDown = util.pointerDown;
- var pointerEnter = util.pointerEnter;
- var pointerLeave = util.pointerLeave;
- var remove = util.remove;
- var within = util.within;
- var actives = [];
- UIkit.component("tooltip", {
- attrs: true,
- args: "title",
- mixins: [ mixin.container, mixin.togglable, mixin.position ],
- props: {
- delay: Number,
- title: String
- },
- defaults: {
- pos: "top",
- title: "",
- delay: 0,
- animation: [ "uk-animation-scale-up" ],
- duration: 100,
- cls: "uk-active",
- clsPos: "uk-tooltip"
- },
- beforeConnect: function beforeConnect() {
- this._hasTitle = hasAttr(this.$el, "title");
- attr(this.$el, {
- title: "",
- "aria-expanded": false
- });
- },
- disconnected: function disconnected() {
- this.hide();
- attr(this.$el, {
- title: this._hasTitle ? this.title : null,
- "aria-expanded": null
- });
- },
- methods: {
- show: function show() {
- var this$1 = this;
- if (includes(actives, this)) {
- return;
- }
- actives.forEach(function(active) {
- return active.hide();
- });
- actives.push(this);
- this._unbind = on(document, "click", function(e) {
- return !within(e.target, this$1.$el) && this$1.hide();
- });
- clearTimeout(this.showTimer);
- this.tooltip = append(this.container, '");
- attr(this.$el, "aria-expanded", true);
- this.positionAt(this.tooltip, this.$el);
- this.origin = this.getAxis() === "y" ? flipPosition(this.dir) + "-" + this.align : this.align + "-" + flipPosition(this.dir);
- this.showTimer = setTimeout(function() {
- this$1.toggleElement(this$1.tooltip, true);
- this$1.hideTimer = setInterval(function() {
- if (!isVisible(this$1.$el)) {
- this$1.hide();
- }
- }, 150);
- }, this.delay);
- },
- hide: function hide() {
- var index = actives.indexOf(this);
- if (!~index || matches(this.$el, "input") && this.$el === document.activeElement) {
- return;
- }
- actives.splice(index, 1);
- clearTimeout(this.showTimer);
- clearInterval(this.hideTimer);
- attr(this.$el, "aria-expanded", false);
- this.toggleElement(this.tooltip, false);
- this.tooltip && remove(this.tooltip);
- this.tooltip = false;
- this._unbind();
- }
- },
- events: (obj = {}, obj["focus " + pointerEnter + " " + pointerDown] = function(e) {
- if (e.type !== pointerDown || !isTouch(e)) {
- this.show();
- }
- }, obj.blur = "hide", obj[pointerLeave] = function(e) {
- if (!isTouch(e)) {
- this.hide();
- }
- }, obj)
- });
- }
- function plugin$13(UIkit) {
- if (plugin$13.installed) {
- return;
- }
- var ref = UIkit.util;
- var addClass = ref.addClass;
- var ajax = ref.ajax;
- var matches = ref.matches;
- var noop = ref.noop;
- var on = ref.on;
- var removeClass = ref.removeClass;
- var trigger = ref.trigger;
- UIkit.component("upload", {
- props: {
- allow: String,
- clsDragover: String,
- concurrent: Number,
- maxSize: Number,
- method: String,
- mime: String,
- msgInvalidMime: String,
- msgInvalidName: String,
- msgInvalidSize: String,
- multiple: Boolean,
- name: String,
- params: Object,
- type: String,
- url: String
- },
- defaults: {
- allow: false,
- clsDragover: "uk-dragover",
- concurrent: 1,
- maxSize: 0,
- method: "POST",
- mime: false,
- msgInvalidMime: "Invalid File Type: %s",
- msgInvalidName: "Invalid File Name: %s",
- msgInvalidSize: "Invalid File Size: %s Bytes Max",
- multiple: false,
- name: "files[]",
- params: {},
- type: "",
- url: "",
- abort: noop,
- beforeAll: noop,
- beforeSend: noop,
- complete: noop,
- completeAll: noop,
- error: noop,
- fail: noop,
- load: noop,
- loadEnd: noop,
- loadStart: noop,
- progress: noop
- },
- events: {
- change: function change(e) {
- if (!matches(e.target, 'input[type="file"]')) {
- return;
- }
- e.preventDefault();
- if (e.target.files) {
- this.upload(e.target.files);
- }
- e.target.value = "";
- },
- drop: function drop(e) {
- stop(e);
- var transfer = e.dataTransfer;
- if (!transfer || !transfer.files) {
- return;
- }
- removeClass(this.$el, this.clsDragover);
- this.upload(transfer.files);
- },
- dragenter: function dragenter(e) {
- stop(e);
- },
- dragover: function dragover(e) {
- stop(e);
- addClass(this.$el, this.clsDragover);
- },
- dragleave: function dragleave(e) {
- stop(e);
- removeClass(this.$el, this.clsDragover);
- }
- },
- methods: {
- upload: function upload(files) {
- var this$1 = this;
- if (!files.length) {
- return;
- }
- trigger(this.$el, "upload", [ files ]);
- for (var i = 0; i < files.length; i++) {
- if (this$1.maxSize && this$1.maxSize * 1e3 < files[i].size) {
- this$1.fail(this$1.msgInvalidSize.replace("%s", this$1.allow));
- return;
- }
- if (this$1.allow && !match(this$1.allow, files[i].name)) {
- this$1.fail(this$1.msgInvalidName.replace("%s", this$1.allow));
- return;
- }
- if (this$1.mime && !match(this$1.mime, files[i].type)) {
- this$1.fail(this$1.msgInvalidMime.replace("%s", this$1.mime));
- return;
- }
- }
- if (!this.multiple) {
- files = [ files[0] ];
- }
- this.beforeAll(this, files);
- var chunks = chunk(files, this.concurrent);
- var upload = function(files) {
- var data = new FormData();
- files.forEach(function(file) {
- return data.append(this$1.name, file);
- });
- for (var key in this$1.params) {
- data.append(key, this$1.params[key]);
- }
- ajax(this$1.url, {
- data: data,
- method: this$1.method,
- responseType: this$1.type,
- beforeSend: function(env) {
- var xhr = env.xhr;
- xhr.upload && on(xhr.upload, "progress", this$1.progress);
- [ "loadStart", "load", "loadEnd", "abort" ].forEach(function(type) {
- return on(xhr, type.toLowerCase(), this$1[type]);
- });
- this$1.beforeSend(env);
- }
- }).then(function(xhr) {
- this$1.complete(xhr);
- if (chunks.length) {
- upload(chunks.shift());
- } else {
- this$1.completeAll(xhr);
- }
- }, function(e) {
- return this$1.error(e.message);
- });
- };
- upload(chunks.shift());
- }
- }
- });
- function match(pattern, path) {
- return path.match(new RegExp("^" + pattern.replace(/\//g, "\\/").replace(/\*\*/g, "(\\/[^\\/]+)*").replace(/\*/g, "[^\\/]+").replace(/((?!\\))\?/g, "$1.") + "$", "i"));
- }
- function chunk(files, size) {
- var chunks = [];
- for (var i = 0; i < files.length; i += size) {
- var chunk = [];
- for (var j = 0; j < size; j++) {
- chunk.push(files[i + j]);
- }
- chunks.push(chunk);
- }
- return chunks;
- }
- function stop(e) {
- e.preventDefault();
- e.stopPropagation();
- }
- }
- UIkit$2.use(plugin);
- UIkit$2.use(plugin$1);
- UIkit$2.use(plugin$2);
- UIkit$2.use(plugin$6);
- UIkit$2.use(plugin$7);
- UIkit$2.use(plugin$9);
- UIkit$2.use(plugin$10);
- UIkit$2.use(plugin$11);
- UIkit$2.use(plugin$12);
- UIkit$2.use(plugin$13);
- {
- boot(UIkit$2);
- }
- return UIkit$2;
-});
-
-(function(global, factory) {
- typeof exports === "object" && typeof module !== "undefined" ? module.exports = factory() : typeof define === "function" && define.amd ? define("uikiticons", factory) : global.UIkitIcons = factory();
-})(this, function() {
- "use strict";
- var album = ' ';
- var ban = ' ';
- var behance = ' ';
- var bell = ' ';
- var bold = ' ';
- var bolt = ' ';
- var bookmark = ' ';
- var calendar = ' ';
- var camera = ' ';
- var cart = ' ';
- var check = ' ';
- var clock = ' ';
- var close = ' ';
- var code = ' ';
- var cog = ' ';
- var comment = ' ';
- var commenting = ' ';
- var comments = ' ';
- var copy = ' ';
- var database = ' ';
- var desktop = ' ';
- var download = ' ';
- var dribbble = ' ';
- var expand = ' ';
- var facebook = ' ';
- var file = ' ';
- var flickr = ' ';
- var folder = ' ';
- var forward = ' ';
- var foursquare = ' ';
- var future = ' ';
- var github = ' ';
- var gitter = ' ';
- var google = ' ';
- var grid = ' ';
- var happy = ' ';
- var hashtag = ' ';
- var heart = ' ';
- var history = ' ';
- var home = ' ';
- var image = ' ';
- var info = ' ';
- var instagram = ' ';
- var italic = ' ';
- var joomla = ' ';
- var laptop = ' ';
- var lifesaver = ' ';
- var link = ' ';
- var linkedin = ' ';
- var list = ' ';
- var location = ' ';
- var lock = ' ';
- var mail = ' ';
- var menu = ' ';
- var minus = ' ';
- var more = ' ';
- var move = ' ';
- var nut = ' ';
- var pagekit = ' ';
- var pencil = ' ';
- var phone = ' ';
- var pinterest = ' ';
- var play = ' ';
- var plus = ' ';
- var pull = ' ';
- var push = ' ';
- var question = ' ';
- var receiver = ' ';
- var refresh = ' ';
- var reply = ' ';
- var rss = ' ';
- var search = ' ';
- var server = ' ';
- var settings = ' ';
- var shrink = ' ';
- var social = ' ';
- var soundcloud = ' ';
- var star = ' ';
- var strikethrough = ' ';
- var table = ' ';
- var tablet = ' ';
- var tag = ' ';
- var thumbnails = ' ';
- var trash = ' ';
- var tripadvisor = ' ';
- var tumblr = ' ';
- var tv = ' ';
- var twitter = ' ';
- var uikit = ' ';
- var unlock = ' ';
- var upload = ' ';
- var user = ' ';
- var users = ' ';
- var vimeo = ' ';
- var warning = ' ';
- var whatsapp = ' ';
- var wordpress = ' ';
- var world = ' ';
- var xing = ' ';
- var yelp = ' ';
- var youtube = ' ';
- var Icons = {
- album: album,
- ban: ban,
- behance: behance,
- bell: bell,
- bold: bold,
- bolt: bolt,
- bookmark: bookmark,
- calendar: calendar,
- camera: camera,
- cart: cart,
- check: check,
- clock: clock,
- close: close,
- code: code,
- cog: cog,
- comment: comment,
- commenting: commenting,
- comments: comments,
- copy: copy,
- database: database,
- desktop: desktop,
- download: download,
- dribbble: dribbble,
- expand: expand,
- facebook: facebook,
- file: file,
- flickr: flickr,
- folder: folder,
- forward: forward,
- foursquare: foursquare,
- future: future,
- github: github,
- gitter: gitter,
- google: google,
- grid: grid,
- happy: happy,
- hashtag: hashtag,
- heart: heart,
- history: history,
- home: home,
- image: image,
- info: info,
- instagram: instagram,
- italic: italic,
- joomla: joomla,
- laptop: laptop,
- lifesaver: lifesaver,
- link: link,
- linkedin: linkedin,
- list: list,
- location: location,
- lock: lock,
- mail: mail,
- menu: menu,
- minus: minus,
- more: more,
- move: move,
- nut: nut,
- pagekit: pagekit,
- pencil: pencil,
- phone: phone,
- pinterest: pinterest,
- play: play,
- plus: plus,
- pull: pull,
- push: push,
- question: question,
- receiver: receiver,
- refresh: refresh,
- reply: reply,
- rss: rss,
- search: search,
- server: server,
- settings: settings,
- shrink: shrink,
- social: social,
- soundcloud: soundcloud,
- star: star,
- strikethrough: strikethrough,
- table: table,
- tablet: tablet,
- tag: tag,
- thumbnails: thumbnails,
- trash: trash,
- tripadvisor: tripadvisor,
- tumblr: tumblr,
- tv: tv,
- twitter: twitter,
- uikit: uikit,
- unlock: unlock,
- upload: upload,
- user: user,
- users: users,
- vimeo: vimeo,
- warning: warning,
- whatsapp: whatsapp,
- wordpress: wordpress,
- world: world,
- xing: xing,
- yelp: yelp,
- youtube: youtube,
- "500px": ' ',
- "arrow-down": ' ',
- "arrow-left": ' ',
- "arrow-right": ' ',
- "arrow-up": ' ',
- "chevron-down": ' ',
- "chevron-left": ' ',
- "chevron-right": ' ',
- "chevron-up": ' ',
- "cloud-download": ' ',
- "cloud-upload": ' ',
- "credit-card": ' ',
- "file-edit": ' ',
- "git-branch": ' ',
- "git-fork": ' ',
- "github-alt": ' ',
- "google-plus": ' ',
- "minus-circle": ' ',
- "more-vertical": ' ',
- "paint-bucket": ' ',
- "phone-landscape": ' ',
- "play-circle": ' ',
- "plus-circle": ' ',
- "quote-right": ' ',
- "sign-in": ' ',
- "sign-out": ' ',
- "tablet-landscape": ' ',
- "triangle-down": ' ',
- "triangle-left": ' ',
- "triangle-right": ' ',
- "triangle-up": ' ',
- "video-camera": ' '
- };
- function plugin(UIkit) {
- if (plugin.installed) {
- return;
- }
- UIkit.icon.add(Icons);
- }
- if (typeof window !== "undefined" && window.UIkit) {
- window.UIkit.use(plugin);
- }
- return plugin;
-});
-
-(function() {
- "use strict";
- var _$JSONLoader_2 = {
- load: load
- };
- function load(location, callback) {
- var xhr = getXHR();
- xhr.open("GET", location, true);
- xhr.onreadystatechange = createStateChangeListener(xhr, callback);
- xhr.send();
- }
- function createStateChangeListener(xhr, callback) {
- return function() {
- if (xhr.readyState === 4 && xhr.status === 200) {
- try {
- callback(null, JSON.parse(xhr.responseText));
- } catch (err) {
- callback(err, null);
- }
- }
- };
- }
- function getXHR() {
- return window.XMLHttpRequest ? new window.XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");
- }
- "use strict";
- var _$OptionsValidator_3 = function OptionsValidator(params) {
- if (!validateParams(params)) {
- throw new Error("-- OptionsValidator: required options missing");
- }
- if (!(this instanceof OptionsValidator)) {
- return new OptionsValidator(params);
- }
- var requiredOptions = params.required;
- this.getRequiredOptions = function() {
- return requiredOptions;
- };
- this.validate = function(parameters) {
- var errors = [];
- requiredOptions.forEach(function(requiredOptionName) {
- if (typeof parameters[requiredOptionName] === "undefined") {
- errors.push(requiredOptionName);
- }
- });
- return errors;
- };
- function validateParams(params) {
- if (!params) {
- return false;
- }
- return typeof params.required !== "undefined" && params.required instanceof Array;
- }
- };
- "use strict";
- function fuzzysearch(needle, haystack) {
- var tlen = haystack.length;
- var qlen = needle.length;
- if (qlen > tlen) {
- return false;
- }
- if (qlen === tlen) {
- return needle === haystack;
- }
- outer: for (var i = 0, j = 0; i < qlen; i++) {
- var nch = needle.charCodeAt(i);
- while (j < tlen) {
- if (haystack.charCodeAt(j++) === nch) {
- continue outer;
- }
- }
- return false;
- }
- return true;
- }
- var _$fuzzysearch_1 = fuzzysearch;
- "use strict";
- var _$FuzzySearchStrategy_5 = new FuzzySearchStrategy();
- function FuzzySearchStrategy() {
- this.matches = function(string, crit) {
- return _$fuzzysearch_1(crit.toLowerCase(), string.toLowerCase());
- };
- }
- "use strict";
- var _$LiteralSearchStrategy_6 = new LiteralSearchStrategy();
- function LiteralSearchStrategy() {
- this.matches = function(str, crit) {
- if (typeof str !== "string") {
- return false;
- }
- str = str.trim();
- return str.toLowerCase().indexOf(crit.toLowerCase()) >= 0;
- };
- }
- "use strict";
- var _$Repository_4 = {
- put: put,
- clear: clear,
- search: search,
- setOptions: setOptions
- };
- function NoSort() {
- return 0;
- }
- var data = [];
- var opt = {};
- opt.fuzzy = false;
- opt.limit = 10;
- opt.searchStrategy = opt.fuzzy ? _$FuzzySearchStrategy_5 : _$LiteralSearchStrategy_6;
- opt.sort = NoSort;
- function put(data) {
- if (isObject(data)) {
- return addObject(data);
- }
- if (isArray(data)) {
- return addArray(data);
- }
- return undefined;
- }
- function clear() {
- data.length = 0;
- return data;
- }
- function isObject(obj) {
- return Boolean(obj) && Object.prototype.toString.call(obj) === "[object Object]";
- }
- function isArray(obj) {
- return Boolean(obj) && Object.prototype.toString.call(obj) === "[object Array]";
- }
- function addObject(_data) {
- data.push(_data);
- return data;
- }
- function addArray(_data) {
- var added = [];
- clear();
- for (var i = 0, len = _data.length; i < len; i++) {
- if (isObject(_data[i])) {
- added.push(addObject(_data[i]));
- }
- }
- return added;
- }
- function search(crit) {
- if (!crit) {
- return [];
- }
- return findMatches(data, crit, opt.searchStrategy, opt).sort(opt.sort);
- }
- function setOptions(_opt) {
- opt = _opt || {};
- opt.fuzzy = _opt.fuzzy || false;
- opt.limit = _opt.limit || 10;
- opt.searchStrategy = _opt.fuzzy ? _$FuzzySearchStrategy_5 : _$LiteralSearchStrategy_6;
- opt.sort = _opt.sort || NoSort;
- }
- function findMatches(data, crit, strategy, opt) {
- var matches = [];
- for (var i = 0; i < data.length && matches.length < opt.limit; i++) {
- var match = findMatchesInObject(data[i], crit, strategy, opt);
- if (match) {
- matches.push(match);
- }
- }
- return matches;
- }
- function findMatchesInObject(obj, crit, strategy, opt) {
- for (var key in obj) {
- if (!isExcluded(obj[key], opt.exclude) && strategy.matches(obj[key], crit)) {
- return obj;
- }
- }
- }
- function isExcluded(term, excludedTerms) {
- var excluded = false;
- excludedTerms = excludedTerms || [];
- for (var i = 0, len = excludedTerms.length; i < len; i++) {
- var excludedTerm = excludedTerms[i];
- if (!excluded && new RegExp(term).test(excludedTerm)) {
- excluded = true;
- }
- }
- return excluded;
- }
- "use strict";
- var _$Templater_7 = {
- compile: compile,
- setOptions: __setOptions_7
- };
- var options = {};
- options.pattern = /\{(.*?)\}/g;
- options.template = "";
- options.middleware = function() {};
- function __setOptions_7(_options) {
- options.pattern = _options.pattern || options.pattern;
- options.template = _options.template || options.template;
- if (typeof _options.middleware === "function") {
- options.middleware = _options.middleware;
- }
- }
- function compile(data) {
- return options.template.replace(options.pattern, function(match, prop) {
- var value = options.middleware(prop, data[prop], options.template);
- if (typeof value !== "undefined") {
- return value;
- }
- return data[prop] || match;
- });
- }
- "use strict";
- var _$utils_9 = {
- merge: merge,
- isJSON: isJSON
- };
- function merge(defaultParams, mergeParams) {
- var mergedOptions = {};
- for (var option in defaultParams) {
- if (Object.prototype.hasOwnProperty.call(defaultParams, option)) {
- mergedOptions[option] = defaultParams[option];
- if (typeof mergeParams[option] !== "undefined") {
- mergedOptions[option] = mergeParams[option];
- }
- }
- }
- return mergedOptions;
- }
- function isJSON(json) {
- try {
- if (json instanceof Object && JSON.parse(JSON.stringify(json))) {
- return true;
- }
- return false;
- } catch (err) {
- return false;
- }
- }
- var _$src_8 = {};
- (function(window) {
- "use strict";
- var options = {
- searchInput: null,
- resultsContainer: null,
- json: [],
- searchResultTemplate: ' {title} ',
- templateMiddleware: function() {},
- sortMiddleware: function() {
- return 0;
- },
- noResultsText: "No results found",
- limit: 10,
- fuzzy: false,
- exclude: []
- };
- var requiredOptions = [ "searchInput", "resultsContainer", "json" ];
- var optionsValidator = _$OptionsValidator_3({
- required: requiredOptions
- });
- window.SimpleJekyllSearch = function(_options) {
- var errors = optionsValidator.validate(_options);
- if (errors.length > 0) {
- throwError("You must specify the following required options: " + requiredOptions);
- }
- options = _$utils_9.merge(options, _options);
- _$Templater_7.setOptions({
- template: options.searchResultTemplate,
- middleware: options.templateMiddleware
- });
- _$Repository_4.setOptions({
- fuzzy: options.fuzzy,
- limit: options.limit,
- sort: options.sortMiddleware
- });
- if (_$utils_9.isJSON(options.json)) {
- initWithJSON(options.json);
- } else {
- initWithURL(options.json);
- }
- return {
- search: search
- };
- };
- window.SimpleJekyllSearch.init = window.SimpleJekyllSearch;
- if (typeof window.SimpleJekyllSearchInit === "function") {
- window.SimpleJekyllSearchInit.call(this, window.SimpleJekyllSearch);
- }
- function initWithJSON(json) {
- _$Repository_4.put(json);
- registerInput();
- }
- function initWithURL(url) {
- _$JSONLoader_2.load(url, function(err, json) {
- if (err) {
- throwError("failed to get JSON (" + url + ")");
- }
- initWithJSON(json);
- });
- }
- function emptyResultsContainer() {
- options.resultsContainer.innerHTML = "";
- }
- function appendToResultsContainer(text) {
- options.resultsContainer.innerHTML += text;
- }
- function registerInput() {
- options.searchInput.addEventListener("keyup", function(e) {
- if (isWhitelistedKey(e.which)) {
- emptyResultsContainer();
- search(e.target.value);
- }
- });
- }
- function search(query) {
- if (isValidQuery(query)) {
- emptyResultsContainer();
- render(_$Repository_4.search(query));
- }
- }
- function render(results) {
- var len = results.length;
- if (len === 0) {
- return appendToResultsContainer(options.noResultsText);
- }
- for (var i = 0; i < len; i++) {
- appendToResultsContainer(_$Templater_7.compile(results[i]));
- }
- }
- function isValidQuery(query) {
- return query && query.length > 0;
- }
- function isWhitelistedKey(key) {
- return [ 13, 16, 20, 37, 38, 39, 40, 91 ].indexOf(key) === -1;
- }
- function throwError(message) {
- throw new Error("SimpleJekyllSearch --- " + message);
- }
- })(window);
-})();
\ No newline at end of file
diff --git a/_site/assets/posts/7C04AAA0EE9E3886.png b/_site/assets/posts/7C04AAA0EE9E3886.png
deleted file mode 100644
index 8af764e0b5..0000000000
Binary files a/_site/assets/posts/7C04AAA0EE9E3886.png and /dev/null differ
diff --git a/_site/assets/posts/SVG/logo.svg b/_site/assets/posts/SVG/logo.svg
deleted file mode 100644
index 886b00f891..0000000000
--- a/_site/assets/posts/SVG/logo.svg
+++ /dev/null
@@ -1 +0,0 @@
-logo
\ No newline at end of file
diff --git a/_site/assets/posts/books.svg b/_site/assets/posts/books.svg
deleted file mode 100644
index 6e5638ac37..0000000000
--- a/_site/assets/posts/books.svg
+++ /dev/null
@@ -1,51 +0,0 @@
-
-
-
- Books
- Created with Sketch.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/_site/assets/posts/box.svg b/_site/assets/posts/box.svg
deleted file mode 100644
index 625e607a25..0000000000
--- a/_site/assets/posts/box.svg
+++ /dev/null
@@ -1,100 +0,0 @@
-
-
-
- Box
- Created with Sketch.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/_site/assets/posts/city.svg b/_site/assets/posts/city.svg
deleted file mode 100644
index 337229f80d..0000000000
--- a/_site/assets/posts/city.svg
+++ /dev/null
@@ -1,188 +0,0 @@
-
-
-
- Style 9
- Created with Sketch.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/_site/assets/posts/imac.svg b/_site/assets/posts/imac.svg
deleted file mode 100644
index 881398574d..0000000000
--- a/_site/assets/posts/imac.svg
+++ /dev/null
@@ -1,47 +0,0 @@
-
-
-
- iMac
- Created with Sketch.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/_site/assets/posts/image1.png b/_site/assets/posts/image1.png
deleted file mode 100644
index a7125c3140..0000000000
Binary files a/_site/assets/posts/image1.png and /dev/null differ
diff --git a/_site/assets/posts/logo.png b/_site/assets/posts/logo.png
deleted file mode 100644
index 4b1793c8b5..0000000000
Binary files a/_site/assets/posts/logo.png and /dev/null differ
diff --git a/_site/assets/posts/logo.svg b/_site/assets/posts/logo.svg
deleted file mode 100644
index 4cf1acadf5..0000000000
--- a/_site/assets/posts/logo.svg
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-logo
-
-
-
diff --git a/_site/assets/posts/old.logo.svg b/_site/assets/posts/old.logo.svg
deleted file mode 100755
index c12f862550..0000000000
--- a/_site/assets/posts/old.logo.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/_site/assets/posts/safe.svg b/_site/assets/posts/safe.svg
deleted file mode 100644
index 4ece36002d..0000000000
--- a/_site/assets/posts/safe.svg
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-
- Safe
- Created with Sketch.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/_site/assets/posts/sky.svg b/_site/assets/posts/sky.svg
deleted file mode 100644
index 3913866cb0..0000000000
--- a/_site/assets/posts/sky.svg
+++ /dev/null
@@ -1,113 +0,0 @@
-
-
-
- Style 1
- Created with Sketch.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/_site/assets/posts/slideshow-1/image1.png b/_site/assets/posts/slideshow-1/image1.png
deleted file mode 100644
index a7125c3140..0000000000
Binary files a/_site/assets/posts/slideshow-1/image1.png and /dev/null differ
diff --git a/_site/assets/posts/teacup.svg b/_site/assets/posts/teacup.svg
deleted file mode 100644
index 729cf60ed3..0000000000
--- a/_site/assets/posts/teacup.svg
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
- Teacup
- Created with Sketch.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/_site/assets/posts/touch-icon.png b/_site/assets/posts/touch-icon.png
deleted file mode 100644
index 243615bb9f..0000000000
Binary files a/_site/assets/posts/touch-icon.png and /dev/null differ
diff --git a/_site/assets/posts/touch-icon.svg b/_site/assets/posts/touch-icon.svg
deleted file mode 100644
index cc1205e398..0000000000
--- a/_site/assets/posts/touch-icon.svg
+++ /dev/null
@@ -1 +0,0 @@
-Asset 1
\ No newline at end of file
diff --git a/_site/changelog/index.html b/_site/changelog/index.html
deleted file mode 100644
index 26f5ef7cc4..0000000000
--- a/_site/changelog/index.html
+++ /dev/null
@@ -1,349 +0,0 @@
-
-
-
-
-
-
-
-
-Changelog | Blockstack
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Changelog
-
-
-
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.
-
-
-
-
-
-
-
-
Oct 21, 2017
-
-
-
Version 1.0.0 STABLE
-
-
- Added Slideshow component
-
- Added style support for radio and minusbox in Firefox
-
- Removed class from Section component
-
- Allow fullscreen mode for videos in Lightbox
-
- Fixed responsive images in modal for IE11
-
- Fix Grid and Margin component for cells with no height
-
- Larger horizontal padding for form input and textarea
-
-
-
-
-
-
-
-
Sep 01, 2017
-
-
-
Version 1.0.0 BETA 1
-
-
- Allow fullscreen mode for YouTube videos in Lightbox
-
- Fix icons not displaying if connected in rapid succession
-
- Fix scrollbar jumping in Switcher
-
-
-
-
-
-
-
-
Aug 15, 2017
-
-
-
Version 0.6.0
-
-
- Added style support for radio and checkbox in Firefox
-
- Removed class from Section component
-
- Add workaround to mitigate the duplicating icons issue
-
- Fixed responsive images in modal for IE11
-
-
-
-
-
-
-
-
Oct 21, 2017
-
-
-
Version 0.5.0
-
-
- Media options now support any valid media query syntax
-
- Added style support for radio and checkbox in Firefox
-
- Fix whitespace trimming in dist
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Blockstack
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/_site/contact/index.html b/_site/contact/index.html
deleted file mode 100644
index ca5b200e7a..0000000000
--- a/_site/contact/index.html
+++ /dev/null
@@ -1,343 +0,0 @@
-
-
-
-
-
-
-
-
-Got Any Questions | Blockstack
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Got Any Questions
-
-
-
Morbi varius in accumsan blandit, elit ligula velit, luctus mattis ante nulla nulla.
-
-
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt.
-
-
-
-
-
-
-
-
-
-
-
-
-
Contact Form
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Blockstack
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/_site/core/README.md b/_site/core/README.md
deleted file mode 100644
index 8f6f0c78c3..0000000000
--- a/_site/core/README.md
+++ /dev/null
@@ -1,36 +0,0 @@
-# Documentation
-
-All Blockstack software documentation is either in this directory, or linked
-from this file.
-
-## FAQs
-
-* [General FAQ](https://blockstack.org/faq)
-* [Technical FAQ](faq_technical.md)
-
-## System Design and Implementation
-
-* [Blockstack Naming Service](blockstack_naming_service.md) (start here)
-* [Atlas Peer Network](atlas_network.md)
-* [Gaia Storage System](https://github.com/blockstack/gaia)
-* [Transaction Formats](wire-format.md)
-* [Glossary](glossary.md)
-
-## Command-line Documentation
-
-* [CLI walkthrough](basic_usage.md)
-* [CLI reference](cli.md)
-
-## Developer Documentation
-
-* [blockstack.js](https://github.com/blockstack/blockstack.js)
-* [Blockstack Browser](https://github.com/blockstack/blockstack-browser)
-* [Blockstack Core API](https://core.blockstack.org)
-* [Integration Test Framework](../integration_tests/README.md)
-
-## Advanced Topics
-
-* [How to Create a Namespace](namespace_creation.md)
-* [How to link your OpenBazaar Store to your Blockstack ID](openbazaar.md)
-* [How to build a Profile Search Index](search.md)
-* [How to Run a Blockstack Subdomain Registrar](subdomains.md)
diff --git a/_site/core/advanced_usage.md b/_site/core/advanced_usage.md
deleted file mode 100644
index 2f9db4c2de..0000000000
--- a/_site/core/advanced_usage.md
+++ /dev/null
@@ -1,4 +0,0 @@
-# Advanced Usage
-
-This document is deprecated, and contains references to commands that are no
-longer valid. It has been moved to the [attic](attic/advanced_usage.md).
diff --git a/_site/core/aglio_templates/core.jade b/_site/core/aglio_templates/core.jade
deleted file mode 100644
index de87cfe99d..0000000000
--- a/_site/core/aglio_templates/core.jade
+++ /dev/null
@@ -1,36 +0,0 @@
-doctype
-
-include mixins.jade
-
-html
- head
- meta(charset="utf-8")
- title= self.api.name || 'API Documentation'
- link(rel="stylesheet", href="https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css")
- style!= self.css
- body.preload
- #nav-background
- div.container-fluid.triple
- .row
- block nav
- +Nav(false)
-
- .content
- #right-panel-background
-
- block content
- +ContentTriple(false)
-
- .middle
- p.text-muted(style="text-align: center;")
-
- script: include scripts.js
-
- if self.livePreview
- script(src="/socket.io/socket.io.js")
- script.
- var socket = io();
- socket.on('refresh', refresh);
- socket.on('reconnect', function () {
- socket.emit('request-refresh');
- });
diff --git a/_site/core/aglio_templates/mixins.jade b/_site/core/aglio_templates/mixins.jade
deleted file mode 100644
index ddc54690a2..0000000000
--- a/_site/core/aglio_templates/mixins.jade
+++ /dev/null
@@ -1,357 +0,0 @@
-mixin TryMe(action)
- //- Give a "try-me" link for the public api endpoint
- - var myUri = action.uriTemplate
- - action.parameters.forEach( function (x) { myUri = myUri.replace( "{" + x.name + "}", x.example) } )
- .title
- strong
- h4
- div
- div
- span.method(class="badge get",style="float:left")
- a.method(href=myUri, style="color:rgb(51, 122, 183);font-size:12pt")
- = "Try It!"
- |
- p
- div
- |
-
-mixin Badge(method)
- //- Draw a badge for a given HTTP method
- case method
- when 'GET'
- span.badge.get: i.fa.fa-arrow-down
- when 'HEAD'
- span.badge.head: i.fa.fa-info-circle
- when 'OPTIONS'
- span.badge.options: i.fa.fa-dot-circle-o
- when 'POST'
- span.badge.post: i.fa.fa-plus
- when 'PUT'
- span.badge.put: i.fa.fa-pencil
- when 'PATCH'
- span.badge.patch: i.fa.fa-pencil
- when 'DELETE'
- span.badge.delete: i.fa.fa-times
- default
- span.badge: i.fa.fa-dot-circle-o
-
-mixin Nav(onlyPublic)
- //- Draw a navigation bar, which includes links to individual
- //- resources and actions.
- nav
- if self.api.navItems && self.api.navItems.length
- .resource-group
- .heading
- .chevron
- i.open.fa.fa-angle-down
- a(href='#top') Overview
- .collapse-content
- ul: each item in self.api.navItems
- li
- a(href=item[1])!= item[0]
- - if (onlyPublic){
- - myGroups = self.api.resourceGroups.filter( filter_public_resourcegroups )
- - }else{
- - myGroups = self.api.resourceGroups.filter( filter_core_resourcegroups )
- - }
- each resourceGroup in myGroups || []
- .resource-group
- .heading
- .chevron
- i.open.fa.fa-angle-down
- a(href=resourceGroup.elementLink)!= resourceGroup.name || 'Resource Group'
- .collapse-content
- ul
- each item in resourceGroup.navItems || []
- li
- a(href=item[1])!= item[0]
- - if (onlyPublic){
- - myResources = resourceGroup.resources.filter( filter_public_resources )
- - }else{
- - myResources = resourceGroup.resources.filter( filter_core_resources )
- - }
- each resource in myResources || []
- li
- - if (onlyPublic){
- - myActions = resource.actions.filter( filter_public_actions )
- - }else{
- - myActions = resource.actions.filter( filter_core_actions )
- - }
- if !self.condenseNav || (myActions.length != 1)
- a(href=resource.elementLink)!= resource.name || 'Resource'
- ul: each action in myActions || []
- li: a(href=resource.elementLink)
- +Badge(action.method)
- != action.name || action.method + ' ' + (action.attributes && action.attributes.uriTemplate || resource.uriTemplate)
- else
- - var action = myActions[0]
- a(href=resource.elementLink)
- +Badge(action.method)
- != action.name || resource.name || action.method + ' ' + (action.attributes && action.attributes.uriTemplate || resource.uriTemplate)
- //- Link to the API hostname, e.g. api.yourcompany.com
- each meta in self.api.metadata || {}
- if meta.name == 'HOST'
- p(style="text-align: center; word-wrap: break-word;")
- a(href=meta.value)= meta.value
-
-mixin Parameters(params)
- //- Draw a definition list of parameter names, types, defaults,
- //- examples and descriptions.
- .title
- strong URI Parameters
- .collapse-button.show
- span.close Hide
- span.open Show
- .collapse-content
- dl.inner: each param in params || []
- dt= self.urldec(param.name)
- dd
- code= param.type || 'string'
- |
- if param.required
- span.required (required)
- else
- span (optional)
- |
- if param.default
- span.text-info.default
- strong Default:
- span= param.default
- |
- if param.example
- span.text-muted.example
- strong Example:
- span= param.example
- != self.markdown(param.description)
- if param.values.length
- p.choices
- strong Choices:
- each value in param.values
- code= self.urldec(value.value)
- = ' '
-
-mixin RequestResponse(title, request, collapse)
- .title
- strong
- = title
- if request.name
- |
- code= request.name
- if collapse && request.hasContent
- .collapse-button
- span.close Hide
- span.open Show
- +RequestResponseBody(request, collapse)
-
-mixin RequestResponseBody(request, collapse, showBlank)
- if request.hasContent || showBlank
- div(class=collapse ? 'collapse-content' : ''): .inner
- if request.description
- .description!= self.markdown(request.description)
-
- if Object.keys(request.headers).length
- h5 Headers
- pre: code
- each item, index in request.headers
- != self.highlight(item.name + ': ' + item.value, 'http')
- if index < request.headers.length - 1
- br
- div(style="height: 1px;")
- if request.body
- h5 Body
- pre: code
- != self.highlight(request.body, null, ['json', 'yaml', 'xml', 'javascript'])
- div(style="height: 1px;")
- if request.schema
- h5 Schema
- pre: code
- != self.highlight(request.schema, null, ['json', 'yaml', 'xml'])
- div(style="height: 1px;")
- if !request.hasContent
- .description.text-muted This response has no content.
- div(style="height: 1px;")
-
-mixin Examples(resourceGroup, resource, action)
- each example in action.examples
- each request in example.requests
- +RequestResponse('Request', request, true)
- each response in example.responses
- +RequestResponse('Response', response, true)
-
-mixin Content()
- //- Page header and API description
- header
- h1#top!= self.api.name || 'API Documentation'
-
- if self.api.descriptionHtml
- != self.api.descriptionHtml
-
- //- Loop through and display information about all the resource
- //- groups, resources, and actions.
- each resourceGroup in self.api.resourceGroups || []
- section.resource-group(id=resourceGroup.elementId)
- h2.group-heading
- != resourceGroup.name || 'Resource Group'
- = " "
- a.permalink(href=resourceGroup.elementLink) ¶
- if resourceGroup.descriptionHtml
- != resourceGroup.descriptionHtml
-
- each resource in resourceGroup.resources || []
- .resource(id=resource.elementId)
- h3.resource-heading
- != resource.name || ((resource.actions[0] != null) && resource.actions[0].name) || 'Resource'
- = " "
- a.permalink(href=resource.elementLink) ¶
- if resource.description
- != self.markdown(resource.description)
-
- each action in resource.actions || []
- .action(class=action.methodLower, id=action.elementId)
- h4.action-heading
- .name!= action.name
- a.method(class=action.methodLower, href=action.elementLink)
- = action.method
- code.uri= self.urldec(action.uriTemplate)
- if action.description
- != self.markdown(action.description)
-
- h4 Example URI
- .definition
- span.method(class=action.methodLower)= action.method
- |
- span.uri
- span.hostname= self.api.host
- != action.colorizedUriTemplate
-
- //- A list of sub-sections for parameters, requests
- //- and responses.
- if action.parameters.length
- +Parameters(action.parameters)
- if action.examples
- +Examples(resourceGroup, resource, action)
-
-- function filter_public_actions(x){
-- return (x.description.includes('+ Public Endpoint') || x.description.includes('+ Public Only Endpoint'))
-- }
-- function filter_public_resources(x){
-- return (x.actions.filter( filter_public_actions ).length > 0)
-- }
-- function filter_public_resourcegroups(x){
-- return (x.resources.filter( filter_public_resources ).length > 0)
-- }
-- function filter_core_actions(x){
-- return !(x.description.includes('+ Public Only Endpoint'))
-- }
-- function filter_core_resources(x){
-- return (x.actions.filter( filter_core_actions ).length > 0)
-- }
-- function filter_core_resourcegroups(x){
-- return (x.resources.filter( filter_core_resources ).length > 0)
-- }
-
-mixin ContentTriple(onlyPublic, descriptionHtml)
-
- .right
- h5 API Endpoint
- a(href=self.api.host)= self.api.host
- .middle
- if descriptionHtml
- != descriptionHtml
-
- //- Loop through and display information about all the resource
- //- groups, resources, and actions.
- - if (onlyPublic){
- - myGroups = self.api.resourceGroups.filter( filter_public_resourcegroups )
- - }else{
- - myGroups = self.api.resourceGroups.filter( filter_core_resourcegroups )
- - }
- each resourceGroup in myGroups || []
- .middle
- section.resource-group(id=resourceGroup.elementId)
- h2.group-heading
- != resourceGroup.name || 'Resource Group'
- = " "
- a.permalink(href=resourceGroup.elementLink) ¶
- if resourceGroup.descriptionHtml
- != resourceGroup.descriptionHtml
-
- - if (onlyPublic){
- - myResources = resourceGroup.resources.filter( filter_public_resources )
- - }else{
- - myResources = resourceGroup.resources.filter( filter_core_resources )
- - }
- each resource in myResources || []
- if resource.public != null
- .middle
- .resource(id=resource.elementId)
- a.permalink(href=resource.elementLink)
- h3.resource-heading
- != resource.name || ((resource.actions[0] != null) && resource.actions[0].name) || 'Resource'
- = " "
- ¶
- if resource.description
- != self.markdown(resource.description)
-
- - if (onlyPublic){
- - myActions = resource.actions.filter( filter_public_actions )
- - }else{
- - myActions = resource.actions.filter( filter_core_actions )
- - }
- each action in myActions || []
- if action.examples
- .right
- .definition
- span.method(class=action.methodLower)= action.method
- |
- span.uri
- span.hostname= self.api.host
- != action.colorizedUriTemplate
- .tabs
- if action.hasRequest
- .example-names
- span Requests
- - var requestCount = 0
- each example in action.examples
- each request in example.requests
- - requestCount++
- span.tab-button= request.name || 'example ' + requestCount
- each example in action.examples
- each request in example.requests
- .tab
- +RequestResponseBody(request, false, true)
- .tabs
- .example-names
- span Responses
- each response in example.responses
- span.tab-button= response.name
- each response in example.responses
- .tab
- +RequestResponseBody(response, false, true)
- else
- each example in action.examples
- .tabs
- .example-names
- span Responses
- each response in example.responses
- span.tab-button= response.name
- each response in example.responses
- .tab
- +RequestResponseBody(response, false, true)
- .middle
- .action(class=action.methodLower, id=action.elementId)
- h4.action-heading
- .name!= action.name
- a.method(class=action.methodLower, href=action.elementLink)
- = action.method
- code.uri= self.urldec(action.uriTemplate)
- if action.description
- != self.markdown(action.description)
-
- //- A list of sub-sections for parameters, requests
- //- and responses.
- if action.parameters.length
- +Parameters(action.parameters)
- if onlyPublic
- +TryMe(action)
- hr.split
diff --git a/_site/core/aglio_templates/public.jade b/_site/core/aglio_templates/public.jade
deleted file mode 100644
index b5ae6b1592..0000000000
--- a/_site/core/aglio_templates/public.jade
+++ /dev/null
@@ -1,53 +0,0 @@
-doctype
-
-
-include mixins.jade
-
-html
- head
- meta(charset="utf-8")
- title= 'Blockstack Core'
- link(rel="stylesheet", href="https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css")
- style!= self.css
- body.preload
- #nav-background
- div.container-fluid.triple
- .row
- block nav
- +Nav(true)
-
- .content
- #right-panel-background
- .middle
- header
- h1#top!= 'Getting Started'
- p!= 'Welcome to this deployment of Blockstack Core v{{server_info.server_version}}. You can read the documentation and make RESTful calls to this node.'
- p
- table
- tr
- td!= 'Consensus hash'
- td!= '{{server_info.consensus}}'
- tr
-
- td!= 'Last block seen'
- td!= '{{server_info.last_block_seen}}'
- tr
- td!= 'Last block processed'
- td!= '{{server_info.last_block_processed}}'
- p!= 'Blockstack Core is open-source software released under a GPLv3 license. The code for this API is available on Github and you can deploy your own nodes by following these instructions .'
- block content
- +ContentTriple(true)
-
- .middle
- p.text-muted(style="text-align: center;")
-
- script: include scripts.js
-
- if self.livePreview
- script(src="/socket.io/socket.io.js")
- script.
- var socket = io();
- socket.on('refresh', refresh);
- socket.on('reconnect', function () {
- socket.emit('request-refresh');
- });
diff --git a/_site/core/aglio_templates/scripts.js b/_site/core/aglio_templates/scripts.js
deleted file mode 100644
index d105df6c43..0000000000
--- a/_site/core/aglio_templates/scripts.js
+++ /dev/null
@@ -1,223 +0,0 @@
-/* eslint-env browser */
-/* eslint quotes: [2, "single"] */
-'use strict';
-
-/*
- Determine if a string ends with another string.
-*/
-function endsWith(str, suffix) {
- return str.indexOf(suffix, str.length - suffix.length) !== -1;
-}
-
-/*
- Get a list of direct child elements by class name.
-*/
-function childrenByClass(element, name) {
- var filtered = [];
-
- for (var i = 0; i < element.children.length; i++) {
- var child = element.children[i];
- var classNames = child.className.split(' ');
- if (classNames.indexOf(name) !== -1) {
- filtered.push(child);
- }
- }
-
- return filtered;
-}
-
-/*
- Get an array [width, height] of the window.
-*/
-function getWindowDimensions() {
- var w = window,
- d = document,
- e = d.documentElement,
- g = d.body,
- x = w.innerWidth || e.clientWidth || g.clientWidth,
- y = w.innerHeight || e.clientHeight || g.clientHeight;
-
- return [x, y];
-}
-
-/*
- Collapse or show a request/response example.
-*/
-function toggleCollapseButton(event) {
- var button = event.target.parentNode;
- var content = button.parentNode.nextSibling;
- var inner = content.children[0];
-
- if (button.className.indexOf('collapse-button') === -1) {
- // Clicked without hitting the right element?
- return;
- }
-
- if (content.style.maxHeight && content.style.maxHeight !== '0px') {
- // Currently showing, so let's hide it
- button.className = 'collapse-button';
- content.style.maxHeight = '0px';
- } else {
- // Currently hidden, so let's show it
- button.className = 'collapse-button show';
- content.style.maxHeight = inner.offsetHeight + 12 + 'px';
- }
-}
-
-function toggleTabButton(event) {
- var i, index;
- var button = event.target;
-
- // Get index of the current button.
- var buttons = childrenByClass(button.parentNode, 'tab-button');
- for (i = 0; i < buttons.length; i++) {
- if (buttons[i] === button) {
- index = i;
- button.className = 'tab-button active';
- } else {
- buttons[i].className = 'tab-button';
- }
- }
-
- // Hide other tabs and show this one.
- var tabs = childrenByClass(button.parentNode.parentNode, 'tab');
- for (i = 0; i < tabs.length; i++) {
- if (i === index) {
- tabs[i].style.display = 'block';
- } else {
- tabs[i].style.display = 'none';
- }
- }
-}
-
-/*
- Collapse or show a navigation menu. It will not be hidden unless it
- is currently selected or `force` has been passed.
-*/
-function toggleCollapseNav(event, force) {
- var heading = event.target.parentNode;
- var content = heading.nextSibling;
- var inner = content.children[0];
-
- if (heading.className.indexOf('heading') === -1) {
- // Clicked without hitting the right element?
- return;
- }
-
- if (content.style.maxHeight && content.style.maxHeight !== '0px') {
- // Currently showing, so let's hide it, but only if this nav item
- // is already selected. This prevents newly selected items from
- // collapsing in an annoying fashion.
- if (force || window.location.hash && endsWith(event.target.href, window.location.hash)) {
- content.style.maxHeight = '0px';
- }
- } else {
- // Currently hidden, so let's show it
- content.style.maxHeight = inner.offsetHeight + 12 + 'px';
- }
-}
-
-/*
- Refresh the page after a live update from the server. This only
- works in live preview mode (using the `--server` parameter).
-*/
-function refresh(body) {
- document.querySelector('body').className = 'preload';
- document.body.innerHTML = body;
-
- // Re-initialize the page
- init();
- autoCollapse();
-
- document.querySelector('body').className = '';
-}
-
-/*
- Determine which navigation items should be auto-collapsed to show as many
- as possible on the screen, based on the current window height. This also
- collapses them.
-*/
-function autoCollapse() {
- var windowHeight = getWindowDimensions()[1];
- var itemsHeight = 64; /* Account for some padding */
- var itemsArray = Array.prototype.slice.call(
- document.querySelectorAll('nav .resource-group .heading'));
-
- // Get the total height of the navigation items
- itemsArray.forEach(function (item) {
- itemsHeight += item.parentNode.offsetHeight;
- });
-
- // Should we auto-collapse any nav items? Try to find the smallest item
- // that can be collapsed to show all items on the screen. If not possible,
- // then collapse the largest item and do it again. First, sort the items
- // by height from smallest to largest.
- var sortedItems = itemsArray.sort(function (a, b) {
- return a.parentNode.offsetHeight - b.parentNode.offsetHeight;
- });
-
- while (sortedItems.length && itemsHeight > windowHeight) {
- for (var i = 0; i < sortedItems.length; i++) {
- // Will collapsing this item help?
- var itemHeight = sortedItems[i].nextSibling.offsetHeight;
- if ((itemsHeight - itemHeight <= windowHeight) || i === sortedItems.length - 1) {
- // It will, so let's collapse it, remove its content height from
- // our total and then remove it from our list of candidates
- // that can be collapsed.
- itemsHeight -= itemHeight;
- toggleCollapseNav({target: sortedItems[i].children[0]}, true);
- sortedItems.splice(i, 1);
- break;
- }
- }
- }
-}
-
-/*
- Initialize the interactive functionality of the page.
-*/
-function init() {
- var i, j;
-
- // Make collapse buttons clickable
- var buttons = document.querySelectorAll('.collapse-button');
- for (i = 0; i < buttons.length; i++) {
- buttons[i].onclick = toggleCollapseButton;
-
- // Show by default? Then toggle now.
- if (buttons[i].className.indexOf('show') !== -1) {
- toggleCollapseButton({target: buttons[i].children[0]});
- }
- }
-
- var responseCodes = document.querySelectorAll('.example-names');
- for (i = 0; i < responseCodes.length; i++) {
- var tabButtons = childrenByClass(responseCodes[i], 'tab-button');
- for (j = 0; j < tabButtons.length; j++) {
- tabButtons[j].onclick = toggleTabButton;
-
- // Show by default?
- if (j === 0) {
- toggleTabButton({target: tabButtons[j]});
- }
- }
- }
-
- // Make nav items clickable to collapse/expand their content.
- var navItems = document.querySelectorAll('nav .resource-group .heading');
- for (i = 0; i < navItems.length; i++) {
- navItems[i].onclick = toggleCollapseNav;
-
- // Show all by default
- toggleCollapseNav({target: navItems[i].children[0]});
- }
-}
-
-// Initial call to set up buttons
-init();
-
-window.onload = function () {
- autoCollapse();
- // Remove the `preload` class to enable animations
- document.querySelector('body').className = '';
-};
diff --git a/_site/core/api-specs.md b/_site/core/api-specs.md
deleted file mode 100644
index 80c445e37b..0000000000
--- a/_site/core/api-specs.md
+++ /dev/null
@@ -1,3061 +0,0 @@
-# Group Authorization
-
-## Auth Request View [GET /auth?authRequest={authRequestToken}]
-
-This endpoint is accessed internally by
-[blockstack.js](https://github.com/blockstack/blockstack.js) to process user
-sign-in requests. Applications use `blockstack.js` to direct users to sign in
-or sign up. Please see the [blockstack.js
-documentation](http://blockstack.github.io/blockstack.js/#authentication) on
-authentication for details.
-
-When the user clicks the Blockstack login button in an application, the app should
-redirect the user to this endpoint (via `blockstack.js`). If the user already has an
-account, they will be redirected along with requested data. If the
-user doesn’t have an account, the user will be presented with each of
-the app’s requested permissions, then will satisfy or deny them. The
-sign-in dashboard will then redirect the user back to the application
-with a signed JWT. This JWT contains a signature and an API
-token that the app can use for future authorization of endpoints.
-
-Each application specifies in advance which family of API calls it
-will need to make to function properly. This list is passed along to
-this endpoint when creating an application account. The
-account-creation page shows this list of API endpoints and what they
-do, and allows the user to line-item approve or deny them. The list
-is stored to the user's profile, and returned to the application
-application as part of the session JWT. The API
-server will NACK requests to endpoints in API families absent from the
-session JWT.
-
-+ Requires root authorization
-+ Parameters
- + authRequestToken: eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJhcHBfZG9tYWluIjoiaGVsbG9ibG9ja3N0YWNrLmNvbSIsIm1ldGhvZHMiOltdLCJhcHBfcHVibGljX2tleSI6IjAyYjk0ZjY4NDgzOGFkMjdmZTE0Nzk1MGMyNjQ1ZjRhYzhjYmU1OTJlYjYzYmQwYTQ5MWQ2YzBlYWZjNjE0YzVjMCJ9.0lLrxt8uGtB2rCKB9sb0jK1DdrrWuuuWM-nsyjvFnmjNx0XfG14Npl72w6hp9W2OHoXdPe7VuXkfvKmVNlQdeA (jwt token) - app token before signing
-+ Response 200
- + Body
-
- {"token":
- "eyJhbGciOiJFUzI1NksiLCJ0eXAiOiJKV1QifQ.eyJhcHBfZG9tYWluIjoiaGVsbG9ibG9ja3N0YWNrLmNvbSIsIm1ldGhvZHMiOltdLCJ0aW1lc3RhbXAiOjE0OTkzNDc4OTUsImV4cGlyZXMiOjE0OTk5NTI2OTUsImFwcF91c2VyX2lkIjoiMUVITmE2UTRKejJ1dk5FeEw0OTdtRTQzaWtYaHdGNmtabSIsImRldmljZV9pZCI6IjAiLCJibG9ja2NoYWluX2lkIjpudWxsLCJzdG9yYWdlIjp7ImNsYXNzZXMiOnsid3JpdGVfcHJpdmF0ZSI6WyJkaXNrIiwiczMiLCJibG9ja3N0YWNrX3NlcnZlciIsImRodCJdLCJyZWFkX2xvY2FsIjpbImRpc2siXSwicmVhZF9wdWJsaWMiOlsiczMiLCJibG9ja3N0YWNrX3Jlc29sdmVyIiwiYmxvY2tzdGFja19zZXJ2ZXIiLCJodHRwIiwiZGh0Il0sIndyaXRlX2xvY2FsIjpbImRpc2siXSwid3JpdGVfcHVibGljIjpbXSwicmVhZF9wcml2YXRlIjpbImRpc2siXX0sInByZWZlcmVuY2VzIjp7fX0sImFwaV9lbmRwb2ludCI6ImxvY2FsaG9zdDo2MjcwIiwiYXBwX3B1YmxpY19rZXlzIjpbXSwidmVyc2lvbiI6MX0.Bhne8wQpPVfkV-VLf2mrsoMmNiE2e04crgLN7OUFKEh_YWeGmqjoZU7JVSzXA5r7LCpZ9Eki5uAWlJSHk-JuCA"
- }
-
-# Group Core Node Administration
-
-Blockstack Core's API module provides a set of API calls for interacting with
-the node's configuration. However, most of this section is **DEPRECATED** in favor
-of moving configuration state to the [Blockstack
-Browser](https://github.com/blockstack/blockstack-browser). Client-side state
-is managed by [blockstack.js](https://github.com/blockstack/blockstack.js).
-
-## Ping the node [GET /v1/node/ping]
-Ping the Blockstack node to see if it's alive.
-+ Public Endpoint
-+ Response 200 (application/json)
- + Body
-
- {
- "status": "alive",
- "version": "###version###"
- }
- + Schema
-
- {
- "type": "object",
- "properties": {
- "status": {
- "type": "string"
- },
- "version": {
- "type": "string"
- }
- },
- "required": [
- "status",
- "version"
- ]
- }
-
-## Get the node's config [GET /v1/node/config]
-Returns the current configuation settings of the Blockstack node.
-
-+ DEPRECATED. Blockstack clients should use
- [blockstack.js](https://github.com/blockstack/blockstack.js) for querying
-client-side configuration state.
-+ Requires root authorization
-+ Legacy Endpoint
-+ Response 200 (application/json)
- + Body
-
- {
- "bitcoind": {
- "passwd": "blockstacksystem",
- "port": "18332",
- "regtest": "True",
- "server": "localhost",
- "spv_path": "/tmp/.../spv_headers.dat",
- "use_https": "False",
- "user": "blockstack"
- },
- "blockchain-reader": {
- "port": "18332",
- "rpc_password": "blockstacksystem",
- "rpc_username": "blockstack",
- "server": "localhost",
- "use_https": "False",
- "utxo_provider": "bitcoind_utxo",
- "version_byte": "0"
- },
- "blockchain-writer": {
- "port": "18332",
- "rpc_password": "blockstacksystem",
- "rpc_username": "blockstack",
- "server": "localhost",
- "use_https": "False",
- "utxo_provider": "bitcoind_utxo",
- "version_byte": "0"
- },
- "blockstack-client": {
- "advanced_mode": "true",
- "api_endpoint_port": "6270",
- "api_password": "...",
- "blockchain_reader": "bitcoind_utxo",
- "blockchain_writer": "bitcoind_utxo",
- "client_version": "0.18.0.0",
- "poll_interval": "300",
- "port": "16264",
- "queue_path": "/tmp/.../client/queues.db",
- "rpc_detach": "True",
- "server": "localhost",
- "storage_drivers": "disk",
- "storage_drivers_required_write": "disk",
- }
- }
-
- + Schema
-
- {
- 'type': 'object',
- 'patternProperties': {
- '.+': {
- 'type': 'string',
- 'pattern': '.+',
- },
- }
-
-## Set config field [POST /v1/node/config/{section}?{key}={value}]
-Set one or more config fields in a config section.
-
-+ DEPRECATED. Blockstack clients should use
- [blockstack.js](https://github.com/blockstack/blockstack.js) for client-side
-configuration management.
-+ Requires root authorization
-+ Legacy Endpoint
-+ Parameters
- + section: blockstack-client (string) - configuration section
- + key: server (string) - configuration variable to set
- + value: node.blockstack.org (string) - value to set
-
-+ Response 200 (application/json)
- + Body
-
- { 'status' : true }
-
- + Schema
-
- {
- 'anyOf': [
- {
- 'type': 'object',
- 'properties': {
- 'status': {
- 'type': 'boolean'
- },
- },
- },
- {
- 'type': 'object',
- 'properties': {
- 'error': {
- 'type': 'string',
- },
- },
- },
- ],
- }
-
-## Delete a config field [DELETE /v1/node/config/{section}/{key}]
-Delete a single field from the configuration.
-
-+ DEPRECATED. Blockstack clients should use
- [blockstack.js](https://github.com/blockstack/blockstack.js) for client-side
-configuration management.
-+ Requires root authorization
-+ Legacy Endpoint
-+ Parameters
- + section: blockstack-client (string) - configuration section
- + key: advanced_mode (string) - configuration variable to set
-
-+ Response 200 (application/json)
-
- + Body
-
- { 'status' : true }
-
- + Schema
-
- {
- 'anyOf': [
- {
- 'type': 'object',
- 'properties': {
- 'status': {
- 'type': 'boolean'
- },
- },
- },
- {
- 'type': 'object',
- 'properties': {
- 'error': {
- 'type': 'string',
- },
- },
- },
- ],
- }
-
-## Delete a config section [DELETE /v1/node/config/{section}]
-Deletes a whole section from the node's configuration.
-
-+ DEPRECATED. Blockstack clients should use
- [blockstack.js](https://github.com/blockstack/blockstack.js) for client-side
-configuration management.
-+ Requires root authorization
-+ Legacy Endpoint
-+ Parameters
- + section: blockstack-client (string) - configuration section
-
-+ Response 200 (application/json)
- + Body
-
- { 'status' : true }
-
- + Schema
-
- {
- 'anyOf': [
- {
- 'type': 'object',
- 'properties': {
- 'status': {
- 'type': 'boolean'
- },
- },
- },
- {
- 'type': 'object',
- 'properties': {
- 'error': {
- 'type': 'string',
- },
- },
- },
- ],
- }
-
-## Get registrar state [GET /v1/node/registrar/state]
-Gets the current state of the registrar. That is, the Blockstack operations
-that have been submitted to the blockchain but are still waiting for
-enough confirmations.
-
-+ DEPRECATED. Blockstack clients should use
- [blockstack.js](https://github.com/blockstack/blockstack.js) to query
-the status of pending transactions.
-+ Requires root authorization
-+ Legacy Endpoint
-+ Response 200 (application/json)
- + Body
-
- [
- {
- "block_height": 666,
- "fqu": "bar.test",
- "owner_address": "myaPViveUWiiZQQTb51KXCDde4iLC3Rf3K",
- "payment_address": "mv1uqYWZpnap4VBSKTHfKW6noTZcNtxtCW",
- "profile": {
- "@type": "Person",
- "accounts": []
- },
- "transfer_address": null,
- "tx_hash": "b0fa7d4d79bb69cb3eccf40978514dec1620d05fe7822c550c2764c670efcd29",
- "type": "preorder",
- "zonefile": "$ORIGIN bar.test\n$TTL 3600\npubkey TXT \"pubkey:data:03ea5d8c2a3ba84eb17625162320bb53440557c71f7977a57d61405e86be7bdcda\"\n_file URI 10 1 \"file:///home/bar/.blockstack/storage-disk/mutable/bar.test\"\n",
- "zonefile_hash": "cbe11bbbfffe415b915a7f9566748f72a0d8b2bd"
- }
- ]
-
- + Schema
-
- {
- 'type': 'array',
- 'items': {
- 'type': 'object',
- 'properties': {
- 'block_height': {
- 'type': 'integer',
- 'minimum': 0,
- },
- 'fqu': {
- 'type': 'string',
- 'pattern': r'^([a-z0-9\\-_.+]{3,37})$',
- },
- 'owner_address': {
- 'type': 'string',
- 'pattern': r'^([123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+)$',
- },
- 'payment_address': {
- 'type': 'string',
- 'pattern': r'^([123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+)$',
- },
- 'profile': {
- 'type': 'object',
- 'additionalProperties': true,
- 'properties': {
- '@context': {
- 'optional': true,
- 'type': 'string'
- },
- '@id': {
- 'optional': true,
- 'type': 'string'
- },
- '@type': {
- 'type': 'string'
- },
- 'account': {
- 'items': {
- 'properties': {
- '@type': {
- 'type': 'string'
- },
- 'identifier': {
- 'optional': true,
- 'type': 'string'
- },
- 'proofMessage': {
- 'optional': true,
- 'type': 'string'
- },
- 'proofSignature': {
- 'optional': true,
- 'type': 'string'
- },
- 'proofType': {
- 'optional': true,
- 'type': 'string'
- },
- 'proofUrl': {
- 'optional': true,
- 'type': 'string'
- },
- 'service': {
- 'optional': true,
- 'type': 'string'
- }
- },
- 'type': 'object'
- },
- 'optional': true,
- 'type': 'array'
- },
- 'address': {
- 'optional': true,
- 'properties': {
- '@type': {
- 'type': 'string'
- },
- 'addressCountry': {
- 'optional': true,
- 'type': 'string'
- },
- 'addressLocality': {
- 'optional': true,
- 'type': 'string'
- },
- 'postalCode': {
- 'optional': true,
- 'type': 'string'
- },
- 'streetAddress': {
- 'optional': true,
- 'type': 'string'
- }
- },
- 'type': 'object'
- },
- 'birthDate': {
- 'optional': true,
- 'type': 'string'
- },
- 'description': {
- 'optional': true,
- 'type': 'string'
- },
- 'familyName': {
- 'optional': true,
- 'type': 'string'
- },
- 'givenName': {
- 'optional': true,
- 'type': 'string'
- },
- 'image': {
- 'items': {
- 'properties': {
- '@type': {
- 'type': 'string'
- },
- 'contentUrl': {
- 'optional': true,
- 'type': 'string'
- },
- 'name': {
- 'optional': true,
- 'type': 'string'
- }
- },
- 'type': 'object'
- },
- 'optional': true,
- 'type': 'array'
- },
- 'knows': {
- 'items': {
- 'properties': {
- '@id': {
- 'optional': true,
- 'type': 'string'
- },
- '@type': {
- 'type': 'string'
- }
- },
- 'type': 'object'
- },
- 'optional': true,
- 'type': 'array'
- },
- 'name': {
- 'optional': true,
- 'type': 'string'
- },
- 'taxID': {
- 'optional': true,
- 'type': 'string'
- },
- 'website': {
- 'items': {
- 'properties': {
- '@type': {
- 'type': 'string'
- },
- 'url': {
- 'optional': true,
- 'type': 'string'
- }
- },
- 'type': 'object'
- },
- 'optional': true,
- 'type': 'array'
- },
- 'worksFor': {
- 'items': {
- 'properties': {
- '@id': {
- 'optional': true,
- 'type': 'string'
- },
- '@type': {
- 'type': 'string'
- }
- },
- 'type': 'object'
- },
- 'optional': true,
- 'type': 'array'
- }
- }
- },
- 'transfer_address': r'^([123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+)$',
- 'tx_hash': r'^([0-9a-fA-F]+)$',
- 'type': '.+',
- 'zonefile': '.+',
- 'zonefile_hash': r'^([0-9a-fA-F]+)$'
- }
- }
- }
-
-
-# Group Core Wallet Management
-
-This entire section is **DEPRECATED** in favor of the wallet software in
-[blockstack.js](https://github.com/blockstack/blockstack.js). Names registered
-with this API will need to be transferred to the Blockstack Browser.
-
-The Blockstack Core node manages its own wallet -- this has three keys
-for payment, name ownership, and signing data (e.g., user profiles). This
-wallet can be managed through these endpoints.
-
-## Get balance via mock-insight API [GET /insight-api/addr/{address}/balance]
-Returns the integer satoshi balance of the given address, with mininum
-of 1 confirmation.
-
-+ DEPRECATED. Blockstack clients should use
- [blockstack.js](https://github.com/blockstack/blockstack.js) to query
-balances.
-+ Authorization: `wallet_read`
-+ Legacy Endpoint
-+ Response 200 (application/json)
- + Body
-
- 2104
-
- + Schema
-
- { 'type' : 'integer' }
-
-## Get unconfirmed balance via mock-insight API [GET /insight-api/addr/{address}/unconfirmedBalance]
-Returns the integer *unconfirmed* satoshi balance of the given address
-(only the 0-confirmation balance). To get the min_conf=0 balance of an
-address, you want *unconfirmedBalance* + *balance*. The unconfirmed
-balance may be negative (if there is an unconfirmed spend). This
-specification is strange, I know, but it replicates the interface of
-insight-api.
-
-+ DEPRECATED. Blockstack clients should use
- [blockstack.js](https://github.com/blockstack/blockstack.js) to query
-balances.
-+ Authorization: `wallet_read`
-+ Legacy Endpoint
-+ Response 200 (application/json)
- + Body
-
- -1000
-
- + Schema
-
- { 'type' : 'integer' }
-
-## Get wallet payment address [GET /v1/wallet/payment_address]
-
-Returns core node's payment address.
-
-+ DEPRECATED. Blockstack clients should use
- [blockstack.js](https://github.com/blockstack/blockstack.js) to manage keys
-and query UTXOs.
-+ Authorization: `wallet_read`
-+ Legacy Endpoint
-+ Response 200 (application/json)
- + Body
-
- {
- "address": "mv1uqYWZpnap4VBSKTHfKW6noTZcNtxtCW"
- }
-
- + Schema
-
- {
- 'type': 'object',
- 'properties': {
- 'type': 'string',
- 'pattern': r'^([123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+)$',
- }
- }
-
-## Set a specific wallet key [PUT /v1/wallet/keys/{keyname}]
-This call instructs the blockstack core node to use a particular key
-instead of the core node's configured wallet key. The setting of this
-key is *temporary* by default, meaning that it is not written to
-`~/.blockstack/wallet.json`, and on a subsequent restart, the key will
-return to the original key. However, the core registrar *tracks* the
-owner key used for each `PREORDER`, and stores that private key
-encrypted (with `scrypt` and the core wallet password) in the
-queue. When the registrar detects that the key being used for a
-particular name has changed, it will recover by submitting further
-transactions with the stored key.
-
-However, for blockstack core >= 0.14.5, the `persist_change` keyword
-will instruct the core node to write the changed key to
-`~/.blockstack/wallet.json`. In this mode, the node will backup the
-previous wallet to `~/.blockstack/wallet.json.prior.`
-
-+ DEPRECATED. Blockstack clients should use
- [blockstack.js](https://github.com/blockstack/blockstack.js) to manage keys.
-+ Requires root authorization
-+ Legacy Endpoint
-+ Parameters
- + keyname: owner (string) - which key to set (one of 'owner', 'data', 'payment')
-
-+ Request (application/json)
- + Body
-
- "cPo24qGYz76xSbUCug6e8LzmzLGJPZoowQC7fCVPLN2tzCUJgfcW"
-
-+ Request (application/json)
- + Schema
-
- {
- "type" : "object",
- "properties" : {
- "private_key" : {
- "anyOf": [
- {
- "anyOf": [
- {
- "pattern": "^([123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+)$",
- "type": "string"
- },
- {
- "pattern": "^([0-9a-fA-F]+)$",
- "type": "string"
- }
- ]
- },
- {
- "properties": {
- "address": {
- "pattern": "^([123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+)$",
- "type": "string"
- },
- "private_keys": {
- "items": {
- "anyOf": [
- {
- "pattern": "^([123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+)$",
- "type": "string"
- },
- {
- "pattern": "^([0-9a-fA-F]+)$",
- "type": "string"
- }
- ]
- },
- "type": "array"
- },
- "redeem_script": {
- "pattern": "^([0-9a-fA-F]+)$",
- "type": "string"
- }
- },
- "required": [
- "address",
- "redeem_script",
- "private_keys"
- ],
- "type": "object"
- }
- ]
- },
- "persist_change" : {"type" : "boolean"}
- },
- "required" : [ "private_key" ]
- }
-
-+ Request (application/json)
- + Schema
-
- {
- "anyOf": [
- {
- "anyOf": [
- {
- "pattern": "^([123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+)$",
- "type": "string"
- },
- {
- "pattern": "^([0-9a-fA-F]+)$",
- "type": "string"
- }
- ]
- },
- {
- "properties": {
- "address": {
- "pattern": "^([123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+)$",
- "type": "string"
- },
- "private_keys": {
- "items": {
- "anyOf": [
- {
- "pattern": "^([123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+)$",
- "type": "string"
- },
- {
- "pattern": "^([0-9a-fA-F]+)$",
- "type": "string"
- }
- ]
- },
- "type": "array"
- },
- "redeem_script": {
- "pattern": "^([0-9a-fA-F]+)$",
- "type": "string"
- }
- },
- "required": [
- "address",
- "redeem_script",
- "private_keys"
- ],
- "type": "object"
- }
- ]
- }
-
-+ Response 200 (application/json)
- + Body
-
- {"status": true}
-
- + Schema
-
- {
- 'anyOf': [
- {
- 'type': 'object',
- 'properties': {
- 'status': {
- 'type': 'boolean'
- },
- },
- },
- {
- 'type': 'object',
- 'properties': {
- 'error': {
- 'type': 'string',
- },
- },
- },
- ],
- }
-
-## Get payment wallet balance [GET /v1/wallet/balance/{minconfs}]
-
-Fetches wallet balance, including UTXOs from transactions with at
-least a specified number of confirmations.
-
-+ DEPRECATED. Blockstack clients should use
- [blockstack.js](https://github.com/blockstack/blockstack.js) to manage keys
-and query UTXOs.
-+ Authorization: `wallet_read`
-+ Legacy Endpoint
-+ Parameters
- + minconfs: 0 (number, optional) - the minimum confs of transactions to include in balance
-+ Response 200 (application/json)
- + Body
-
- {
- "balance": {
- "bitcoin": 49.931727,
- "satoshis": 4993172700
- }
- }
-
- + Schema
-
- {
- 'type': 'object',
- 'properties': {
- 'balance': {
- 'type': 'object',
- 'properties': {
- 'bitcoin': {
- 'type': 'number',
- 'minimum': 0,
- },
- 'satoshis': {
- 'type': 'integer',
- 'minimum': 0,
- },
- },
- },
- },
- }
-
-## Withdraw payment wallet funds [POST /v1/wallet/balance]
-Withdraw an amount (given in satoshis) from the core payment
-wallet, to a particular address.
-
-+ DEPRECATED. Blockstack clients should use
- [blockstack.js](https://github.com/blockstack/blockstack.js) to manage keys,
-generate transactions, and send transactions.
-+ Authorization: `wallet_write`
-+ Legacy Endpoint
-+ Request (application/json)
- + Body
-
- {'address' : 'mibZW6EBpXSTWQNQ9E4fi9hhGKYSMkjyg9',
- 'amount' : 100,
- 'min_confs' : 6,
- 'tx_only' : false}
-
- + Schema
-
- {
- 'type': 'object',
- 'properties': {
- 'address': {
- 'type': 'string',
- 'pattern': r"^([123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+)$",
- },
- 'amount': {
- 'type': 'integer',
- 'minimum': 0,
- },
- 'message': {
- 'type': 'string',
- 'pattern': '^.{1,80}$',
- }
- 'min_confs': {
- 'type': 'integer',
- 'minimum': 0,
- },
- 'tx_only': {
- 'type': 'boolean'
- },
- 'payment_key': {
- 'anyOf': [
- {
- 'anyOf': [
- {
- 'pattern': '^([123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+)$',
- 'type': 'string'
- },
- {
- 'pattern': '^([0-9a-fA-F]+)$',
- 'type': 'string'
- }
- ]
- },
- {
- 'properties': {
- 'address': {
- 'pattern': '^([123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+)$',
- 'type': 'string'
- },
- 'private_keys': {
- 'items': {
- 'anyOf': [
- {
- 'pattern': '^([123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+)$',
- 'type': 'string'
- },
- {
- 'pattern': '^([0-9a-fA-F]+)$',
- 'type': 'string'
- }
- ]
- },
- 'type': 'array'
- },
- 'redeem_script': {
- 'pattern': '^([0-9a-fA-F]+)$',
- 'type': 'string'
- }
- },
- 'required': [
- 'owner'
- ],
- 'type': 'object'
- }
- ]
- }
- },
- 'required': [
- 'address'
- ],
- }
-
-+ Response 200 (application/json)
- + Body
-
- {
- "status": true,
- "transaction_hash": "c4ee8d1993794487e6b5aca802a1793530bdff35c763ca051fbaa4b998780822",
- "success": true
- }
- + Schema
-
- {
- 'anyOf': [
- {
- 'type': 'object',
- 'properties': {
- 'success': {
- 'type': 'boolean'
- },
- 'transaction_hash': {
- 'type': 'string',
- 'pattern': r'^([0-9a-fA-F]+)$',
- },
- },
- },
- {
- 'type': 'object',
- 'properties': {
- 'error': {
- 'type': 'string',
- },
- },
- },
- ],
- }
-
-
-## Get wallet owner address [GET /v1/wallet/owner_address]
-Returns core node's owner address.
-
-+ DEPRECATED. Blockstack clients should use
- [blockstack.js](https://github.com/blockstack/blockstack.js) to manage keys.
-+ Authorization: `wallet_read`
-+ Legacy Endpoint
-+ Response 200 (application/json)
- + Body
-
- {
- "address": "myaPViveUWiiZQQTb51KXCDde4iLC3Rf3K"
- }
- + Schema
-
- {
- 'anyOf': [
- {
- 'type': 'object',
- 'properties': {
- 'address': {
- 'type': 'string',
- 'pattern': r"^([123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+)$",
- },
- },
- },
- {
- 'type': 'object',
- 'properties': {
- 'error': {
- 'type': 'string',
- },
- },
- },
- ],
- }
-
-
-## Get wallet data public key [GET /v1/wallet/data_pubkey]
-Returns the public key the core node uses for signing user data
-
-+ DEPRECATED. Blockstack clients should use
- [blockstack.js](https://github.com/blockstack/blockstack.js) to manage keys.
-+ Authorization: `wallet_read`
-+ Legacy Endpoint
-+ Response 200 (application/json)
- + Body
-
- {
- "public_key": "03ea5d8c2a3ba84eb17625162320bb53440557c71f7977a57d61405e86be7bdcda"
- }
- + Schema
-
- {
- 'anyOf': [
- {
- 'type': 'object',
- 'properties': {
- 'public_key': {
- 'type': 'string',
- 'pattern': r'^([0-9a-fA-F]+)$',
- },
- },
- },
- {
- 'type': 'object',
- 'properties': {
- 'error': {
- 'type': 'string',
- },
- },
- },
- ],
- }
-
-## Change wallet password [PUT /v1/wallet/password]
-This will change the password for core's wallet. Currently not working endpoint.
-
-+ DEPRECATED. Blockstack clients should use
- [blockstack.js](https://github.com/blockstack/blockstack.js) to encrypt keys.
-+ Authorization: `wallet_write`
-+ Legacy Endpoint
-+ Request (application/json)
- + Body
-
- {'password' : '"0123456789abcdef"',
- 'new_password' : "abcdef0123456789"'}
- + Schema
-
- {
- 'anyOf': [
- {
- 'type': 'object',
- 'properties': {
- 'password': {
- 'type': 'string',
- },
- 'new_password': {
- 'type': 'string',
- },
- },
- },
- {
- 'type': 'object',
- 'properties': {
- 'error': {
- 'type': 'string',
- },
- },
- },
- ],
- }
-
-## Set all wallet keys [PUT /v1/wallet/keys]
-
-+ DEPRECATED. Blockstack clients should use
- [blockstack.js](https://github.com/blockstack/blockstack.js) to manage keys
-in a client wallet.
-+ Legacy Endpoint
-+ Requires root authorization
-
-## Get all wallet keys [GET /v1/wallet/keys]
-
-+ DEPRECATED. Blockstack clients should use
- [blockstack.js](https://github.com/blockstack/blockstack.js) to interact with
-a client wallet.
-+ Legacy Endpoint
-+ Requires root authorization
-
-# Group Managing Names
-
-All POST, PUT, and DELETE routes in this section are **DEPRECATED** in favor of using either the [Blockstack
-Browser](https://github.com/blockstack/blockstack-browser) or
-[blockstack.js](https://github.com/blockstack/blockstack.js) to register and
-manage names.
-
-All GET routes are still valid.
-
-## Register a name [POST /v1/names]
-Registers a name, optionally to a given owner key and optionally using
-a given payment key to pay for the name and transaction fees.
-
-This method takes a JSON blob with the following fields:
-
-* `name`: (required) the fully-qualified name to register.
-* `zonefile`: (optional) the zone file to associate with this name. If one is
- not given, a default one will be generated.
-* `owner_address`: (optional) the recipient of this name. See below.
-* `min_confs`: (optional) this is the minimum number of confirmations for UTXOs
- that will be used for payments for this name registration. Lower values speed
-up the name registration time, at the risk of blockchain reorgs or frontrunners
-invalidating your name's registration.
-* `tx_fee`: (optional) use this transaction fee (in satoshis) instead of
- estimating one.
-* `cost_satoshis`: (optional) how much to pay for this name. This value will be
- sent to the name's namespace's designated burn address. If not given, the
-precise value will be looked up automatically.
-* `unsafe`: (optional) ignore internal safety checks when generating and sending
- transactions. See below.
-* `owner_key`: (optional) if given, this is the *private key* of the owner
-that will receive the name. Useful for when you want to use your *personal*
-node to register names to a different key, without having to bother with the
-extra `NAME_TRANSFER` transaction required by passing `owner_address`.
-DO NOT USE IN PUBLIC SETTINGS.
-* `payment_key`: (optional) if given, this is the *private key* used to pay for
- the name registration fee and transaction fees. Useful for when you want to
-use your *personal* node to register names with a different payment key. DO NOT
-USE IN PUBLIC SETTINGS.
-
-If no `owner_address` is supplied in the POSTed JSON
-object, the node will register a name for the `owner_key` given in the
-JSON blob. If no `owner_key` is given, then the node's current owner address
-in its wallet will be used.
-
-If an `owner_address` is supplied, a `TRANSFER` transaction will be
-broadcasted to send the name to appropriate owner. If you intend to register
-many names to different addresses, it is recommended that you use one of the
-wallet endpoints to set the node's owner keys to save yourself the extra
-`TRANSFER` transactions (or pass `owner_key`). However, you should *ONLY* do
-this if you trust the node (i.e. only do this for personal nodes).
-
-The `min_confs` keyword controls the minimum number of confirmations for
-UTXOs used as payments for name registration.
-
-The `unsafe` keyword instructs the node's registrar to ignore certain
-safety checks while registering the name (in particular, the registrar
-will not verify that the user own's the name before issuing a
-`REGISTER` and `UPDATE`). This allows the registrar to submit
-operations before they have been confirmed on remote resolvers or
-indexers, in this mode, the registrar will wait for 4 confirmations on
-a `PREORDER`, 1 confirmation on a `REGISTER` and 1 confirmation on an
-`UPDATE`. `node.blockstack.org` will correctly detect the registration
-after the `UPDATE` has 6 confirmations.
-
-+ DEPRECATED. Registering names is now performed by [Blockstack
- Browser](https://github.com/blockstack/blocktack-browser) and
-[blockstack.js](https://github.com/blockstack/blockstack.js).
-+ Authorization: `register`
-+ Legacy Endpoint
-+ Request (application/json)
- + Body
-
- {
- 'name' : 'bar.test'
- }
-
-+ Request (application/json)
- + Schema
-
- {
- 'type': 'object',
- 'properties': {
- "name": {
- 'type': 'string',
- 'pattern': OP_NAME_PATTERN
- },
- "zonefile": {
- 'type': 'string',
- 'maxLength': RPC_MAX_ZONEFILE_LEN,
- },
- "owner_address": {
- 'type': 'string',
- 'pattern': OP_BASE58CHECK_PATTERN,
- },
- 'min_confs': {
- 'type': 'integer',
- 'minimum': 0,
- },
- 'tx_fee': {
- 'type': 'integer',
- 'minimum': 0,
- 'maximum': TX_MAX_FEE,
- },
- 'cost_satoshis': {
- 'type': 'integer',
- 'minimum': 0,
- },
- 'unsafe': {
- 'type': 'boolean'
- },
- 'owner_key': {
- 'anyOf': [
- {
- 'anyOf': [
- {
- 'pattern': '^([123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+)$',
- 'type': 'string'
- },
- {
- 'pattern': '^([0-9a-fA-F]+)$',
- 'type': 'string'
- }
- ]
- },
- {
- 'properties': {
- 'address': {
- 'pattern': '^([123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+)$',
- 'type': 'string'
- },
- 'private_keys': {
- 'items': {
- 'anyOf': [
- {
- 'pattern': '^([123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+)$',
- 'type': 'string'
- },
- {
- 'pattern': '^([0-9a-fA-F]+)$',
- 'type': 'string'
- }
- ]
- },
- 'type': 'array'
- },
- 'redeem_script': {
- 'pattern': '^([0-9a-fA-F]+)$',
- 'type': 'string'
- }
- },
- 'required': [
- 'owner'
- ],
- 'type': 'object'
- }
- ]
- },
- 'payment_key': {
- 'anyOf': [
- {
- 'anyOf': [
- {
- 'pattern': '^([123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+)$',
- 'type': 'string'
- },
- {
- 'pattern': '^([0-9a-fA-F]+)$',
- 'type': 'string'
- }
- ]
- },
- {
- 'properties': {
- 'address': {
- 'pattern': '^([123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+)$',
- 'type': 'string'
- },
- 'private_keys': {
- 'items': {
- 'anyOf': [
- {
- 'pattern': '^([123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+)$',
- 'type': 'string'
- },
- {
- 'pattern': '^([0-9a-fA-F]+)$',
- 'type': 'string'
- }
- ]
- },
- 'type': 'array'
- },
- 'redeem_script': {
- 'pattern': '^([0-9a-fA-F]+)$',
- 'type': 'string'
- }
- },
- 'required': [
- 'owner'
- ],
- 'type': 'object'
- }
- ]
- }
- },
- 'required': [
- 'name'
- ],
- 'additionalProperties': False,
- }
-
-+ Response 200 (application/json)
- + Body
-
- {
- "message": "Name queued for registration. The process takes several hours. You can check the status with `blockstack info`.",
- "success": true,
- "transaction_hash": "6cdb9722f72875b30e1ab3de463e3960aced951f674be942b302581a9a9469a5"
- }
-
- + Schema
-
- {
- 'anyOf': [
- {
- 'type': 'object',
- 'properties': {
- 'success': {
- 'type': 'boolean'
- },
- 'transaction_hash': {
- 'type': 'string',
- 'pattern': r'^([0-9a-fA-F]+)$',
- },
- },
- },
- {
- 'type': 'object',
- 'properties': {
- 'error': {
- 'type': 'string',
- },
- },
- },
- ],
- }
-
-
-## Revoke name [DELETE /v1/names/{name}]
-Revokes the name from Blockstack. This renders
-the name unusable until it expires. Use this method if your private keys
-are compromised.
-
-+ DEPRECATED. Blockstack clients should use
- [blockstack.js](https://github.com/blockstack/blockstack.js) for generating
-transactions.
-+ Authorization: `revoke`
-+ Legacy Endpoint
-+ Parameters
- + name: bar.test (string) - fully-qualified name
-+ Response 200 (application/json)
- + Body
-
- {
- "message": "Name queued for revocation. The process takes ~1 hour. You can check the status with `blockstack info`.",
- "success": true,
- "transaction_hash": "b2745b706d7a14ce652265de103d7eaefb44a75eb658d7bb1db8868da08768b2"
- }
-
- + Schema
-
- {
- 'anyOf': [
- {
- 'type': 'object',
- 'properties': {
- 'success': {
- 'type': 'boolean'
- },
- 'transaction_hash': {
- 'type': 'string',
- 'pattern': r'^([0-9a-fA-F]+)$',
- },
- },
- },
- {
- 'type': 'object',
- 'properties': {
- 'error': {
- 'type': 'string',
- },
- },
- },
- ],
- }
-
-
-## Transfer name [PUT /v1/names/{name}/owner]
-Transfers a name to a different owner.
-
-+ DEPRECATED. Blockstack clients should use
- [blockstack.js](https://github.com/blockstack/blockstack.js) for generating
-transactions.
-+ Authorization: `transfer`
-+ Legacy Endpoint
-+ Parameters
- + name: bar.test (string) - name to transfer
-+ Request (application/json)
- + Body
-
- { "owner" : "mjZicz7GSJBZuGeCMEgpzr8U9w6d41DfXm" }
-
-+ Request (application/json)
- + Schema
-
-
- {
- 'type': 'object',
- 'properties': {
- 'owner': {
- 'type': 'string',
- 'pattern': OP_BASE58CHECK_PATTERN,
- },
- 'tx_fee': {
- 'type': 'integer',
- 'minimum': 0,
- 'maximum': 500000
- },
- 'owner_key': {
- 'anyOf': [
- {
- 'anyOf': [
- {
- 'pattern': '^([123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+)$',
- 'type': 'string'
- },
- {
- 'pattern': '^([0-9a-fA-F]+)$',
- 'type': 'string'
- }
- ]
- },
- {
- 'properties': {
- 'address': {
- 'pattern': '^([123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+)$',
- 'type': 'string'
- },
- 'private_keys': {
- 'items': {
- 'anyOf': [
- {
- 'pattern': '^([123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+)$',
- 'type': 'string'
- },
- {
- 'pattern': '^([0-9a-fA-F]+)$',
- 'type': 'string'
- }
- ]
- },
- 'type': 'array'
- },
- 'redeem_script': {
- 'pattern': '^([0-9a-fA-F]+)$',
- 'type': 'string'
- }
- },
- 'required': [
- 'owner'
- ],
- 'type': 'object'
- }
- ]
- },
- 'payment_key': {
- 'anyOf': [
- {
- 'anyOf': [
- {
- 'pattern': '^([123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+)$',
- 'type': 'string'
- },
- {
- 'pattern': '^([0-9a-fA-F]+)$',
- 'type': 'string'
- }
- ]
- },
- {
- 'properties': {
- 'address': {
- 'pattern': '^([123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+)$',
- 'type': 'string'
- },
- 'private_keys': {
- 'items': {
- 'anyOf': [
- {
- 'pattern': '^([123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+)$',
- 'type': 'string'
- },
- {
- 'pattern': '^([0-9a-fA-F]+)$',
- 'type': 'string'
- }
- ]
- },
- 'type': 'array'
- },
- 'redeem_script': {
- 'pattern': '^([0-9a-fA-F]+)$',
- 'type': 'string'
- }
- },
- 'required': [
- 'owner'
- ],
- 'type': 'object'
- }
- ]
- }
- },
- 'additionalProperties': False,
- }
-
-
-+ Response 202 (application/json)
- + Body
-
- {
- "message": "Name queued for transfer. The process takes ~1 hour. You can check the status with `blockstack info`.",
- "success": true,
- "transaction_hash": "c0d677f9ee681abbed8ca6d231bc4ece517c8c6695ce883e5e196b5395402779"
- }
-
- + Schema
-
- {
- 'anyOf': [
- {
- 'type': 'object',
- 'properties': {
- 'success': {
- 'type': 'boolean'
- },
- 'transaction_hash': {
- 'type': 'string',
- 'pattern': r'^([0-9a-fA-F]+)$',
- },
- },
- },
- {
- 'type': 'object',
- 'properties': {
- 'error': {
- 'type': 'string',
- },
- },
- },
- ],
- }
-
-## Publish zone file [POST /v1/names/zonefile]
-Publish the zonefile which has _already_ been announced.
-Submit either as a string with the 'zonefile' property, or
-as a base64 encoded blob with the 'zonefile_b64' property.
-We recommend base64-encoding your zone files in order to guarantee that they
-will be JSON-encodable.
-
-+ DEPRECATED.
-+ Request (application/json)
- + Schema
-
- {
- 'type': 'object',
- 'properties': {
- "zonefile": {
- 'type': 'string',
- },
- "zonefile_b64": {
- 'type': 'string',
- }
- },
- 'additionalProperties': False,
- }
-
-+ Response 200 (application/json)
- + Body
-
- {'success': true, 'servers' : ['...']}
-
-
-## Set zone file [PUT /v1/names/{name}/zonefile]
-Sets the user's zonefile hash, and, if supplied, propagates the
-zonefile. If you supply the zonefile, the hash will be calculated from
-that. Ultimately, your requests should only supply one of `zonefile`,
-`zonefile_b64`, or `zonefile_hash`.
-
-The value for `zonefile_b64` is a base64-encoded string.
-New clients _should_ use the `zonefile_b64` field when specifying a zone file.
-The `zonefile` field is preserved for legacy compatibility.
-
-This API call issues a `NAME_UPDATE` transaction for a name that is owned by
-this node's wallet. That is, you can only call this API method if your node
-owns the name you're updating.
-
-+ DEPRECATED. Blockstack clients should use
- [blockstack.js](https://github.com/blockstack/blockstack.js) for generating
-transactions.
-+ Authorization: `update`
-+ Legacy Endpoint
-+ Parameters
- + name: bar.test (string) - fully-qualified name
-+ Request (application/json)
- + Schema
-
- {
- 'type': 'object',
- 'properties': {
- "zonefile": {
- 'type': 'string',
- },
- 'zonefile_b64': {
- 'type': 'string',
- 'pattern': r'^((?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{4}))$'
- },
- 'zonefile_hash': {
- 'type': 'string',
- 'pattern': '^([0-9a-fA-F]{20})$'
- },
- 'tx_fee': {
- 'type': 'integer',
- 'minimum': 0,
- 'maximum': 500000
- },
- 'owner_key': {
- 'anyOf': [
- {
- 'anyOf': [
- {
- 'pattern': '^([123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+)$',
- 'type': 'string'
- },
- {
- 'pattern': '^([0-9a-fA-F]+)$',
- 'type': 'string'
- }
- ]
- },
- {
- 'properties': {
- 'address': {
- 'pattern': '^([123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+)$',
- 'type': 'string'
- },
- 'private_keys': {
- 'items': {
- 'anyOf': [
- {
- 'pattern': '^([123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+)$',
- 'type': 'string'
- },
- {
- 'pattern': '^([0-9a-fA-F]+)$',
- 'type': 'string'
- }
- ]
- },
- 'type': 'array'
- },
- 'redeem_script': {
- 'pattern': '^([0-9a-fA-F]+)$',
- 'type': 'string'
- }
- },
- 'required': [
- 'owner'
- ],
- 'type': 'object'
- }
- ]
- },
- 'payment_key': {
- 'anyOf': [
- {
- 'anyOf': [
- {
- 'pattern': '^([123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+)$',
- 'type': 'string'
- },
- {
- 'pattern': '^([0-9a-fA-F]+)$',
- 'type': 'string'
- }
- ]
- },
- {
- 'properties': {
- 'address': {
- 'pattern': '^([123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+)$',
- 'type': 'string'
- },
- 'private_keys': {
- 'items': {
- 'anyOf': [
- {
- 'pattern': '^([123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+)$',
- 'type': 'string'
- },
- {
- 'pattern': '^([0-9a-fA-F]+)$',
- 'type': 'string'
- }
- ]
- },
- 'type': 'array'
- },
- 'redeem_script': {
- 'pattern': '^([0-9a-fA-F]+)$',
- 'type': 'string'
- }
- },
- 'required': [
- 'owner'
- ],
- 'type': 'object'
- }
- ]
- }
- },
- 'additionalProperties': False,
- }
-
-+ Response 202 (application/json)
- + Body
-
- {'success': true, 'transaction_hash' : '...'}
- + Schema
-
- {
- 'anyOf': [
- {
- 'type': 'object',
- 'properties': {
- 'success': {
- 'type': 'boolean'
- },
- 'transaction_hash': {
- 'type': 'string',
- 'pattern': r'^([0-9a-fA-F]+)$',
- },
- },
- },
- {
- 'type': 'object',
- 'properties': {
- 'error': {
- 'type': 'string',
- },
- },
- },
- ],
- }
-
-## Fetch zone file [GET /v1/names/{name}/zonefile]
-Fetch a user's raw zone file. This only works for RFC-compliant zone files.
-This method returns an error for names that have non-standard zone files.
-
-+ Parameters
- + name: bar.test (string) - fully-qualified name
-+ Response 200 (application/json)
- + Body
-
- {
- "zonefile": "$ORIGIN bar.test\n$TTL 3600\n_https._tcp URI 10 1 \"https://blockstack.s3.amazonaws.com/bar.test\"\n"
- }
-
- + Schema
-
- {
- 'anyOf': [
- {
- 'type': 'object',
- 'properties': {
- 'zonefile': {
- 'type': 'string',
- 'pattern': '.+',
- },
- },
- {
- 'type': 'object',
- 'properties': {
- 'error': {
- 'type': 'string',
- 'pattern': '.+',
- },
- },
- ]
- }
-
-# Group Name Querying
-This family of API endpoints deals with querying name information.
-
-## Get all names [GET /v1/names?page={page}]
-Fetch a list of all names known to the node.
-+ Public Endpoint
-+ Parameters
- + page: 23 (number) - names are returned in pages of size 100,
- so specify the page number.
-+ Response 200 (application/json)
- + Body
-
- [ "aldenquimby.id", "aldeoryn.id",
- "alderete.id", "aldert.id",
- "aldi.id", "aldighieri.id", ... ]
-
- + Schema
-
- {
- 'type': 'array',
- 'items': {
- 'type': 'string',
- 'pattern': r'^([a-z0-9\\-_.+]{3,37})$',
- }
- }
-
-## Get all subdomains [GET /v1/subdomains?page={page}]
-Fetch a list of all names known to the node.
-+ Public Endpoint
-+ Parameters
- + page: 3 (number) - names are returned in pages of size 100,
- so specify the page number.
-+ Response 200 (application/json)
- + Body
-
- [
- "collegeinfogeek.verified.podcast",
- "collider.verified.podcast",
- "combatandclassics.verified.podcast",
- "combatjack.verified.podcast",
- "comedybangbang.verified.podcast",
- "comedybutton.verified.podcast",
- "commonsense.verified.podcast",
- "concilio002.personal.id", ... ]
-
- + Schema
-
- {
- 'type': 'array',
- 'items': {
- 'type': 'string',
- 'pattern': r'^([a-z0-9\\-_.+]{3,37})\.([a-z0-9\\-_.+]{3,37})$',
- }
- }
-
-## Get name info [GET /v1/names/{name}]
-+ Public Endpoint
-+ Subdomain Aware
-+ Parameters
- + name: muneeb.id (string) - fully-qualified name
-+ Response 200 (application/json)
- + Body
-
- {
- "address": "1QJQxDas5JhdiXhEbNS14iNjr8auFT96GP",
- "blockchain": "bitcoin",
- "expire_block": 489247,
- "last_txid": "1edfa419f7b83f33e00830bc9409210da6c6d1db60f99eda10c835aa339cad6b",
- "status": "registered",
- "zonefile": "$ORIGIN muneeb.id\n$TTL 3600\n_http._tcp IN URI 10 1 \"https://blockstack.s3.amazonaws.com/muneeb.id\"\n",
- "zonefile_hash": "b100a68235244b012854a95f9114695679002af9"
- }
-
- + Schema
-
- {
- 'type': 'object',
- 'properties': {
- 'address': {
- 'type': 'string',
- 'pattern': r"^([123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+)$",
- },
- 'blockchain': {
- 'type': 'string',
- 'pattern': '^bitcoin$',
- },
- 'expire_block': {
- 'type': 'integer',
- 'minimum': 0,
- },
- 'last_txid': {
- 'type': 'string',
- 'pattern': '^[0-9a-fA-F]+$',
- },
- 'status': {
- 'type': 'string',
- 'pattern': '^(registered|revoked)$',
- },
- 'zonefile': {
- 'anyOf': [
- {
- 'type': 'string',
- },
- {
- 'type': 'object',
- 'properties': {
- 'error': {
- 'type': 'string',
- },
- },
- },
- ],
- },
- 'zonefile_hash': {
- 'type': 'string',
- 'pattern': '^[0-9a-fA-F]{20}$`,
- },
- },
- { 'required':
- [
- 'address', 'blockchain', 'last_txid',
- 'status', 'zonefile', 'zonefile_hash'
- ]
- }
- }
-
-## Name history [GET /v1/names/{name}/history?page={page}]
-Get a history of all blockchain records of a registered name.
-+ Public Endpoint
-+ Subdomain aware
-+ Parameters
- + name: muneeb.id (string) - name to query
- + page: 0 (integer) - the page (in 20-entry pages) of the history to fetch
-+ Response 200 (application/json)
- + Body
-
- {
- "373821": [
- {
- "address": "1QJQxDas5JhdiXhEbNS14iNjr8auFT96GP",
- "block_number": 373821,
- "consensus_hash": null,
- "first_registered": 373821,
- "importer": "76a9143e2b5fdd12db7580fb4d3434b31d4fe9124bd9f088ac",
- "importer_address": "16firc3qZU97D1pWkyL6ZYwPX5UVnWc82V",
- "last_creation_op": ";",
- "last_renewed": 373821,
- "name": "muneeb.id",
- "name_hash128": "deb7fe99776122b77925cbf0a24ab6f8",
- "namespace_block_number": 373601,
- "namespace_id": "id",
- "op": ";",
- "op_fee": 100000.0,
- "opcode": "NAME_IMPORT",
- "preorder_block_number": 373821,
- }
- ]
- }
-
- + Schema
-
- {
- 'type': 'object',
- 'patternProperties': {
- '^[0-9]+': {
- 'type': 'array',
- 'items': {
- 'type': 'object',
- 'properties': {
- 'address': {
- 'type': 'string',
- 'pattern': r"^([123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+)$",
- },
- 'base': {
- 'type': 'integer',
- 'minimum': 0,
- 'maximum': 255,
- },
- 'buckets': {
- 'anyOf': [
- {
- 'type': 'array',
- 'items': {
- 'type': 'integer',
- 'minItems': 16,
- 'maxItems': 16,
- },
- },
- {
- 'type': 'null',
- },
- ],
- },
- 'block_number': {
- 'type': 'integer',
- 'minimum': 0,
- },
- 'coeff': {
- 'anyOf': [
- {
- 'type': 'integer',
- 'minimum': 0,
- 'maximum': 255,
- },
- {
- 'type': 'null'
- },
- ],
- },
- 'consensus_hash': {
- 'anyOf': [
- {
- 'type': 'string',
- 'pattern': '^[0-9a-fA-F]{32}',
- },
- {
- 'type': 'null'
- },
- ],
- },
- 'fee': {
- 'type': 'integer',
- 'minimum': 0,
- },
- 'first_registered': {
- 'type': 'integer',
- 'minimum': 0,
- },
- 'history_snapshot': {
- 'type': 'boolean',
- },
- 'importer': {
- 'anyOf': [
- {
- 'type': 'string',
- 'pattern': r'^76[aA]914[0-9a-fA-F]{40}88[aA][cC]$',
- },
- {
- 'type': 'null',
- },
- ],
- },
- 'importer_address': {
- 'anyOf': [
- {
- 'type': 'string',
- 'pattern': r"^([123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+)$",
- },
- {
- 'type': 'null',
- },
- ],
- },
- 'last_renewed': {
- 'type': 'integer',
- 'minimum': 0,
- },
- 'op': {
- 'type': 'string',
- 'pattern': '^([>?+~:!&*:;#]{1}|>>|>~|::)$',
- },
- 'op_fee': {
- 'type': 'number',
- },
- 'opcode': {
- 'type': 'string',
- 'pattern': '^NAME_TRANSFER|NAME_PREORDER|NAME_UPDATE|NAME_REVOKE|NAME_REGISTRATION|NAMESPACE_READY|NAMESPACE_REVEAL|NAMESPACE_PREORDER|NAME_RENEWAL|NAME_IMPORT|ANNOUNCE$'
- },
- 'revoked': {
- 'type': 'boolean',
- },
- 'sender': {
- 'type': 'string',
- 'pattern': '^([0-9a-fA-F]+)$',
- },
- 'sender_pubkey': {
- 'anyOf': [
- {
- 'type': 'string',
- 'pattern': '^([0-9a-fA-F]+)$',
- },
- {
- 'type': 'null'
- },
- ],
- },
- 'recipient': {
- 'anyOf': [
- {
- 'type': 'string',
- 'pattern': '^([0-9a-fA-F]+)$',
- },
- {
- 'type': 'null'
- },
- ],
- },
- 'recipient_address': {
- 'anyOf': [
- {
- 'type': 'string',
- 'pattern': '^([123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+)$',
- },
- {
- 'type': 'null'
- },
- ],
- },
- 'recipient_pubkey': {
- 'anyOf': [
- {
- 'type': 'string',
- 'pattern': '^([0-9a-fA-F]+)$',
- },
- {
- 'type': 'null'
- },
- ],
- },
- 'txid': {
- 'type': 'string',
- 'pattern': '^([0-9a-fA-F]+)$',
- },
- 'value_hash': {
- 'anyOf': [
- {
- 'type': 'string',
- 'pattern': '^([0-9a-fA-F]{40})$',
- },
- {
- 'type': 'null',
- },
- ],
- },
- 'vtxindex': {
- 'type': 'integer',
- 'minimum': 0,
- },
- },
- 'required': [
- 'op',
- 'opcode',
- 'txid',
- 'vtxindex'
- ],
- }
- }
- }
- }
-
-## Get historical zone file [GET /v1/names/{name}/zonefile/{zoneFileHash}]
-Fetches the historical zonefile specified by the username and zone hash.
-+ Public Endpoint
-+ Subdomain aware
-+ Parameters
- + name: muneeb.id (string) username to fetch
- + zoneFileHash: b100a68235244b012854a95f9114695679002af9
-+ Response 200 (application/json)
- + Body
-
- {
- "zonefile":
- "$ORIGIN muneeb.id\n$TTL 3600\n_http._tcp IN URI 10 1 \"https://blockstack.s3.amazonaws.com/muneeb.id\"\n"
- }
-
- + Schema
-
- {
- 'anyOf': [
- {
- 'type': 'object',
- 'properties': {
- 'zonefile': { 'type': 'string' },
- },
- },
- {
- 'type': 'object',
- 'properties': {
- 'error': { 'type': 'string' },
- },
- },
- ],
- }
-
-## Get names owned by address [GET /v1/addresses/{blockchain}/{address}]
-Retrieves a list of names owned by the address provided.
-+ Subdomain Aware
-+ Public Endpoint
-+ Parameters
- + blockchain: bitcoin (string) - the layer-1 blockchain for the address
- + address: 1QJQxDas5JhdiXhEbNS14iNjr8auFT96GP (string) - the address to lookup
-
-+ Response 200 (application/json)
- + Body
-
- {
- "names": ["muneeb.id"]
- }
-
- + Schema
-
- {
- 'type': 'object',
- 'properties': {
- 'names': {
- 'type': 'array',
- 'items': {
- 'type': 'string',
- 'pattern': '^([a-z0-9\-_.+]{3,37})$',
- },
- },
- },
- }
-
-# Group Price Checks
-## Get namespace price [GET /v1/prices/namespaces/{tld}]
-
-This endpoint is used to get the price of a namespace. Anyone can create a
-namespace by following [this
-tutorial](https://github.com/blockstack/blockstack-core/blob/master/docs/namespace_creation.md).
-
-+ Public Endpoint
-+ Parameters
- + tld: id (string) - namespace to query price for
-+ Response 200 (application/json)
- + Body
-
- {
- "satoshis": 4000000000
- }
-
- + Schema
-
- {
- 'type': 'object',
- 'properties': {
- 'satoshis': {
- 'type': 'integer',
- 'minimum': 0,
- },
- },
- }
-
-## Get name price [GET /v1/prices/names/{name}]
-
-This endpoint is used to get the price of a name. If you are using
-a public endpoint, you should *only* rely on the `name_price` field in the
-returned JSON blob. Other fields are **DEPRECATED**, since they are relevant
-only for estimating the cost of registering a name (which should be done via
-[blockstack.js](https://github.com/blockstack/blockstack.js) or the [Blockstack
-Browser](https://github.com/blockstack/blockstack-browser)).
-
-+ Public Endpoint
-+ Parameters
- + name: muneeb.id (string) - name to query price information for
-+ Response 200 (application/json)
- + Body
-
- {
- "name_price": {
- "satoshis": 100000,
- "btc": 0.001
- },
- "total_tx_fees": 519209,
- "register_tx_fee": {
- "satoshis": 159110,
- "btc": 0.0015911
- },
- "preorder_tx_fee": {
- "satoshis": 163703,
- "btc": 0.00163703
- },
- "warnings": [
- "Insufficient funds; fees are rough estimates."
- ],
- "total_estimated_cost": {
- "satoshis": 619209,
- "btc": 0.00619209
- },
- "update_tx_fee": {
- "satoshis": 196396,
- "btc": 0.00196396
- }
- }
-
- + Schema
-
- {
- 'type': 'object',
- 'properties': {
- 'name_price': {
- 'type': 'object',
- 'properties': {
- 'btc': { 'type': 'number', 'minimum': 0 },
- 'satoshis': { 'type': 'integer', 'minimum': 0 }
- }
- },
- 'preorder_tx_fee': {
- 'type': 'object',
- 'properties': {
- 'btc': { 'type': 'number', 'minimum': 0 },
- 'satoshis': { 'type': 'integer', 'minimum': 0 }
- }
- },
- 'register_tx_fee': {
- 'type': 'object',
- 'properties': {
- 'btc': { 'type': 'number', 'minimum': 0 },
- 'satoshis': { 'type': 'integer', 'minimum': 0 }
- }
- },
- 'update_tx_fee': {
- 'type': 'object',
- 'properties': {
- 'btc': { 'type': 'number', 'minimum': 0 },
- 'satoshis': { 'type': 'integer', 'minimum': 0 }
- }
- },
- 'total_estimated_cost': {
- 'type': 'object',
- 'properties': {
- 'btc': { 'type': 'number', 'minimum': 0 },
- 'satoshis': { 'type': 'integer', 'minimum': 0 }
- }
- },
- 'total_tx_fees': {
- 'type': 'integer',
- 'minimum': 0,
- }
- 'name_price': {
- 'type': 'object',
- 'properties': {
- 'btc': { 'type': 'number', 'minimum': 0 },
- 'satoshis': { 'type': 'integer', 'minimum': 0 }
- }
- },
- 'warnings': {
- 'type': 'array',
- 'items': {
- 'type': 'string',
- },
- },
- },
- }
-
-# Group Blockchain Operations
-## Get consensus hash [GET /v1/blockchains/{blockchainName}/consensus]
-Get the current Blockstack consensus hash on a blockchain.
-+ Public Endpoint
-+ Parameters
- + blockchainName : bitcoin (string) - the given blockchain
-+ Response 200 (application/json)
- + Body
-
- {
- "consensus_hash": "2fcbdf66c350894fe03b42c6a2e8a6ac"
- }
-
- + Schema
-
- {
- 'type': 'object',
- 'properties': {
- 'consensus_hash': {
- 'type': 'string',
- 'pattern': '^[0-9a-fA-F]{32}$`,
- },
- },
- }
-
-## Get number of names on blockchain [GET /v1/blockchains/{blockchainName}/name_count{?all}]
-Get the number of names on a blockchain.
-+ Public Endpoint
-+ Parameters
- + blockchainName: bitcoin (string) - the given blockchain
- + all: true (enum[string], optional) - include expired names
-+ Response 200 (application/json)
- + Body
-
- {
- "names_count": 73950
- }
-
- + Schema
-
- {
- 'type': 'object',
- 'properties': {
- 'names_count': {
- 'type': 'integer',
- 'minimum': 0,
- },
- },
- }
-
-+ Response 401 (application/json)
- + Body
-
- { "error": "Unsupported blockchain" }
-
- + Schema
-
- {
- 'type': 'object',
- 'properties': {
- 'error': { 'type': 'string' },
- },
- },
-
-
-## Get number of subdomains on blockchain [GET /v1/blockchains/{blockchainName}/subdomains_count]
-Get the number of subdomains on a blockchain.
-+ Public Endpoint
-+ Parameters
- + blockchainName: bitcoin (string) - the given blockchain
-+ Response 200 (application/json)
- + Body
-
- {
- "names_count": 1646
- }
-
- + Schema
-
- {
- 'type': 'object',
- 'properties': {
- 'names_count': {
- 'type': 'integer',
- 'minimum': 0,
- },
- },
- }
-
-+ Response 401 (application/json)
- + Body
-
- { "error": "Unsupported blockchain" }
-
- + Schema
-
- {
- 'type': 'object',
- 'properties': {
- 'error': { 'type': 'string' },
- },
- },
-
-
-## Get operations in block [GET /v1/blockchains/{blockchainName}/operations/{blockHeight}]
-Get the Blockstack operations in a given block
-+ Parameters
- + blockchainName : bitcoin (string) - the given blockchain
- + blockHeight : 462592 (integer) - the block height
-+ Response 200 (application/json)
- + Body
-
- [
- {
- "address": "1GS1eHthSK2gqnU9MW9Nis1pUyHP3bJnFK",
- "block_number": 462592,
- "burn_address": "1111111111111111111114oLvT2",
- "consensus_hash": "d206b2f615de00803402cade4d0d51d4",
- "op": "?",
- "op_fee": 6250,
- "opcode": "NAME_PREORDER",
- "preorder_hash": "ba22cdf24b05b9a7972e13ada69f96a7850b471e",
- "sender": "76a914a944d29012f83c00105778e0bc717c46ea2accfc88ac",
- "sender_pubkey": "0343b263f7adc6ae59e8d8310f4a6a87799f6b10cec608f3236cd6a802ffc71728",
- "txid": "b3f4f7a43d60666d1a9b42131f9117ad7deac34a478b6ca152344da3d734691f",
- "vtxindex": 173
- },
- {
- "address": "1gijbF8NkbgwzcoZR1nXMa76NbdcD7GQW",
- "block_number": 462592,
- "burn_address": "1111111111111111111114oLvT2",
- "consensus_hash": "d206b2f615de00803402cade4d0d51d4",
- "op": "?",
- "op_fee": 6250,
- "opcode": "NAME_PREORDER",
- "preorder_hash": "386e2de88a908ad056361e586faa95852be454ca",
- "sender": "76a91407830f81167f6a2aa253c0f176b7ff2e1c04c61a88ac",
- "sender_pubkey": "03b7795d33b362338179e5b2a579431b285f6c303d07ddd83c897277be4e5eb916",
- "txid": "4dd315ad1d1b318614a19e15e767efb7ef327bd5cd4ebaf8f80ede58fd1da107",
- "vtxindex": 174
- },
- {
- "address": "17QEd6rrhNZp4xoyWu6BpA8NQ4axyNKaZy",
- "block_number": 462592,
- "burn_address": "1111111111111111111114oLvT2",
- "consensus_hash": "d206b2f615de00803402cade4d0d51d4",
- "op": "?",
- "op_fee": 6250,
- "opcode": "NAME_PREORDER",
- "preorder_hash": "a7a388a2bbe0e7741c6cfdc54d7b5a67811cd582",
- "sender": "76a9144635b1794a22bfbe6c5c5eba17b693f4aaf0e34888ac",
- "sender_pubkey": "020d6e50b2660af27933c42bc1395fe93df90ffac5e2a989f6a134919fb8cf8075",
- "txid": "51d6bd117da5889e710c62967d03233a84fc27f7fad10ca4359111928818f017",
- "vtxindex": 332
- },
- {
- "address": "15YMyvqz6v9ATSbmqJnudwrdm7RiVfkU3s",
- "block_number": 462453,
- "consensus_hash": "f6491e1d2b9817fa58512fc9bf8cd3df",
- "first_registered": 462575,
- "importer": null,
- "importer_address": null,
- "keep_data": true,
- "last_renewed": 462575,
- "name": "ablankstein.id",
- "name_hash128": "943b8e0613d975c05a05ccd5472e2a72",
- "namespace_block_number": 373601,
- "namespace_id": "id",
- "op": ">>",
- "op_fee": 25000,
- "opcode": "NAME_TRANSFER",
- "preorder_block_number": 462453,
- "preorder_hash": "822d5cb6f2e3f0f901d6af8c1111ee466b6c07bd",
- "revoked": false,
- "sender": "76a91431cee995f242f0f66518080a291714cd7e8d2f5e88ac",
- "sender_pubkey": null,
- "txid": "121540e81223c45d139fbe03a9713ddd292372f2f88fe2b10b6a7c5e6738e87f",
- "value_hash": "96ec93cbc57d17b16a347c11ddfa7ea88d2cf93b",
- "vtxindex": 633
- },
- {
- "address": "1Dwq9oA5BNz7DAR1LtDncEa647ZxgmkoVV",
- "block_number": 462325,
- "consensus_hash": "1288cef43f52bf97e2f458a4afe40b61",
- "first_registered": 462359,
- "importer": null,
- "importer_address": null,
- "keep_data": true,
- "last_renewed": 462359,
- "name": "fpenrose.id",
- "name_hash128": "7af28a9834934a0af81a19ee14a45f8e",
- "namespace_block_number": 373601,
- "namespace_id": "id",
- "op": ">>",
- "op_fee": 25000,
- "opcode": "NAME_TRANSFER",
- "preorder_block_number": 462325,
- "preorder_hash": "59c25d7cddf433b5122cabcbf2ebcc1bc1519e4d",
- "revoked": false,
- "sender": "76a9148e002a93b9b1936b5d320967194eaff3deaa979088ac",
- "sender_pubkey": null,
- "txid": "6461bb4bbf517e9c80ffcac4c349836972656572e113aba736b356119655064e",
- "value_hash": "ac73155702ca7aea1161d0f0c7877ac81d48d8fc",
- "vtxindex": 637
- },
- {
- "address": "1Q44Md5KFr6gxQ6TdUSFaCRm3MaUyXMF6t",
- "block_number": 462316,
- "consensus_hash": "1288cef43f52bf97e2f458a4afe40b61",
- "first_registered": 462353,
- "importer": null,
- "importer_address": null,
- "keep_data": true,
- "last_renewed": 462353,
- "name": "rahulpradhan.id",
- "name_hash128": "c55ff9e14c72b2950b14ff10067d7e27",
- "namespace_block_number": 373601,
- "namespace_id": "id",
- "op": ">>",
- "op_fee": 25000,
- "opcode": "NAME_TRANSFER",
- "preorder_block_number": 462316,
- "preorder_hash": "fcb3389ca4d2ab8003ce8b6b3baa0a5ae1600cce",
- "revoked": false,
- "sender": "76a914fcdef125f40f984fafad4b58e30e3b1761a953f388ac",
- "sender_pubkey": null,
- "txid": "be58e02642c457fec2835a354fbc2de45e8c838aa5b7fd18ed831f67d08269e6",
- "value_hash": "e213e58ca1446875b79d866720130cc90cbca681",
- "vtxindex": 638
- },
- {
- "address": "1D8pL725X9HWvoTVgzqDNbTPayHGG7tkY6",
- "block_number": 462345,
- "consensus_hash": "919df884f14f34fd15a791af2fddb569",
- "first_registered": 462380,
- "importer": null,
- "importer_address": null,
- "keep_data": true,
- "last_renewed": 462380,
- "name": "sajithskurup.id",
- "name_hash128": "3fda1c60620c42e1ede385bb246bd5f0",
- "namespace_block_number": 373601,
- "namespace_id": "id",
- "op": ">>",
- "op_fee": 25000,
- "opcode": "NAME_TRANSFER",
- "preorder_block_number": 462345,
- "preorder_hash": "540daefe1f3b520253f7ab954dbc8bf131471133",
- "revoked": false,
- "sender": "76a914851bee0185dd799755234fb20710a26ec40354d288ac",
- "sender_pubkey": null,
- "txid": "e7d35196ca3eec697274d848136f5267b1c935055a917020f93e8ecaf821ba99",
- "value_hash": "92534954e934019718478bb52150765dfad79171",
- "vtxindex": 644
- },
- {
- "address": "1EbjXtYv9QCVBp8iWiDH6xQ1B74oFW696X",
- "block_number": 462345,
- "consensus_hash": "e0c31e03125f2feefd4090e5c635ee45",
- "first_registered": 462380,
- "importer": null,
- "importer_address": null,
- "keep_data": true,
- "last_renewed": 462380,
- "name": "hubject.id",
- "name_hash128": "03e8bf92dd3cbde65cac012350efb79d",
- "namespace_block_number": 373601,
- "namespace_id": "id",
- "op": ">>",
- "op_fee": 25000,
- "opcode": "NAME_TRANSFER",
- "preorder_block_number": 462345,
- "preorder_hash": "ded4d097614cf5321388bbe56b24d3d592b2ef76",
- "revoked": false,
- "sender": "76a914952b4844005dd98a1f7fc99813db2a649109b45988ac",
- "sender_pubkey": null,
- "txid": "7b7a2a2963f7454b93003031cfce64ac609f902b4c2cababfbbfad2c01bbeb9b",
- "value_hash": "be968a1f17ac828179e5b2fbc70d238056af7482",
- "vtxindex": 645
- },
- {
- "address": "14YsDo5qgAP7kmnq33tw9JdHVBywpg9pge",
- "block_number": 462326,
- "consensus_hash": "e0c31e03125f2feefd4090e5c635ee45",
- "first_registered": 462354,
- "importer": null,
- "importer_address": null,
- "keep_data": true,
- "last_renewed": 462354,
- "name": "ramimassoud.id",
- "name_hash128": "61a48b6f8aeb027883ecd1f8d808c8ac",
- "namespace_block_number": 373601,
- "namespace_id": "id",
- "op": ">>",
- "op_fee": 25000,
- "opcode": "NAME_TRANSFER",
- "preorder_block_number": 462326,
- "preorder_hash": "23aa275e42d7d6d7e538584a799252939687c457",
- "revoked": false,
- "sender": "76a91426ef31b7aac60eff23cbbab51d453b84700e330388ac",
- "sender_pubkey": null,
- "txid": "85babcf66caf41cb7beb2e637cbed4e728ab8030337fb5df8461d0e14dd2be75",
- "value_hash": "e27c9c3dcce8a8445d84fb8b4d81fbd30fac9749",
- "vtxindex": 646
- },
- {
- "address": "1H934mT7AVVZmHwjddUZ9EiostLwm655oF",
- "block_number": 462345,
- "consensus_hash": "919df884f14f34fd15a791af2fddb569",
- "first_registered": 462391,
- "importer": null,
- "importer_address": null,
- "keep_data": true,
- "last_renewed": 462391,
- "name": "was2bme.id",
- "name_hash128": "f2b5688682fd47b8f3fbf709bb35ef33",
- "namespace_block_number": 373601,
- "namespace_id": "id",
- "op": ">>",
- "op_fee": 6250,
- "opcode": "NAME_TRANSFER",
- "preorder_block_number": 462345,
- "preorder_hash": "3dfdcee2b0e64697c4bb0b0dd791518bcb078dc7",
- "revoked": false,
- "sender": "76a914b107105f8ae57e7bb5bad58caba666faa679c70f88ac",
- "sender_pubkey": null,
- "txid": "16171e4e20778354a94c5353b0c6ed0b29a3e73c1b59b9bfbcbe6d26c570fd0c",
- "value_hash": "ac73155702ca7aea1161d0f0c7877ac81d48d8fc",
- "vtxindex": 649
- },
- {
- "address": "1B4zxvVMPm1PBGarc8PrYQjQY2ezwniyG6",
- "block_number": 462345,
- "consensus_hash": "e0c31e03125f2feefd4090e5c635ee45",
- "first_registered": 462391,
- "importer": null,
- "importer_address": null,
- "keep_data": true,
- "last_renewed": 462391,
- "name": "tadas_serbenta.id",
- "name_hash128": "6d800932daf830925ab47dee5ceb8661",
- "namespace_block_number": 373601,
- "namespace_id": "id",
- "op": ">>",
- "op_fee": 6250,
- "opcode": "NAME_TRANSFER",
- "preorder_block_number": 462345,
- "preorder_hash": "07a85eac4dbf20000a66a14a4a89a01134b70fab",
- "revoked": false,
- "sender": "76a9146e72e44bbe4c1706ea5830096a4bb4449dcc948f88ac",
- "sender_pubkey": null,
- "txid": "e3f0b019550417a7acfe27addfbd34ec7ec5fc1dd9616ed8c6bc86a0ad148290",
- "value_hash": "fbac107ba5d9bbfc30ecdeae3e10ca3db72b3431",
- "vtxindex": 855
- },
- {
- "address": "16BF35VputeLEmbsk7gDnUcwKXcjwPDUvf",
- "block_number": 462345,
- "consensus_hash": "919df884f14f34fd15a791af2fddb569",
- "first_registered": 462359,
- "importer": null,
- "importer_address": null,
- "keep_data": true,
- "last_renewed": 462359,
- "name": "alexucf.id",
- "name_hash128": "d9bc88b0fdc536e7ac5467609faed518",
- "namespace_block_number": 373601,
- "namespace_id": "id",
- "op": ">>",
- "op_fee": 25000,
- "opcode": "NAME_TRANSFER",
- "preorder_block_number": 462345,
- "preorder_hash": "30f841114af6ada90ba720d563672113c4f74439",
- "revoked": false,
- "sender": "76a91438c8814ae2a9035e85bbf2b7976919c2e3387ac588ac",
- "sender_pubkey": null,
- "txid": "f8e9eebd48b9182b82b22e5ce10f805d3db38786bb2aaf56f9badf83aa3cc0ee",
- "value_hash": "8ae0f51263f540be175230d6b46f5d9609de799d",
- "vtxindex": 856
- },
- {
- "address": "1EmXTRHC6f9bnLJkVZRavv7HLG1owLgNir",
- "block_number": 462326,
- "consensus_hash": "31a304b682e3291811441a12f19d14e5",
- "first_registered": 462391,
- "importer": null,
- "importer_address": null,
- "keep_data": true,
- "last_renewed": 462391,
- "name": "seamur.id",
- "name_hash128": "09f3b9d2da3d0aa1999824f7884f0d18",
- "namespace_block_number": 373601,
- "namespace_id": "id",
- "op": ">>",
- "op_fee": 100000,
- "opcode": "NAME_TRANSFER",
- "preorder_block_number": 462326,
- "preorder_hash": "678991fd4d3833babe27f732206a40d1f15dd3ca",
- "revoked": false,
- "sender": "76a91497055c47fa0ab396fb321e9d37f6bce1796e3d5688ac",
- "sender_pubkey": null,
- "txid": "e32124770c359eaf57709e5a666894f2954aa687820c41c6911f214e9006b58e",
- "value_hash": "4bcdd931185537902ef1af9975198c6404d4c73e",
- "vtxindex": 857
- },
- {
- "address": "13pGtMcHsNdq3EeLMa1yVVKppP1WjSKgFG",
- "block_number": 462345,
- "consensus_hash": "e0c31e03125f2feefd4090e5c635ee45",
- "first_registered": 462354,
- "importer": null,
- "importer_address": null,
- "keep_data": true,
- "last_renewed": 462354,
- "name": "innergame.id",
- "name_hash128": "a3e4e010d82369ee19b64fccc2b97f69",
- "namespace_block_number": 373601,
- "namespace_id": "id",
- "op": ">>",
- "op_fee": 25000,
- "opcode": "NAME_TRANSFER",
- "preorder_block_number": 462345,
- "preorder_hash": "f54850caf10c3041cb2a4d9186bbb234dd7d9f85",
- "revoked": false,
- "sender": "76a9141ee10ff0ae9969e2dc39d94a959e3160b26b6adf88ac",
- "sender_pubkey": null,
- "txid": "28de7193e28e1b0c950a32af393284578669c15dc98bad68f382f8b920d94509",
- "value_hash": "bab40c2b10f676288edea119edade67ff5e853ba",
- "vtxindex": 869
- }
- ]
-
-## Get pending transactions [GET /v1/blockchains/{blockchainName}/pending]
-Get the current transactions that the node has issued and are still pending.
-+ DEPRECATED. Blockstack clients should use
- [blockstack.js](https://github.com/blockstack/blockstack.js) to query the
-blockchain.
-+ Public Endpoint
-+ Parameters
- + blockchainName : bitcoin (string) - the given blockchain
-+ Response 200 (application/json)
- + Body
-
- {
- "queues": {}
- }
-
- + Schema
-
- {
- 'type': 'object',
- 'properties': {
- 'preorder': {
- 'type': 'array',
- 'items': {
- 'type': 'object',
- 'properties': {
- 'name': { 'type': 'string', 'pattern': '^([a-z0-9\-_.+]{3,37})$' },
- 'tx_hash': { 'type': 'string', 'pattern': '^[0-9a-fA-F]+$' },
- 'confirmations': { 'type': 'integer', 'minimum': 0 },
- },
- },
- },
- 'register': {
- 'type': 'array',
- 'items': {
- 'type': 'object',
- 'properties': {
- 'name': { 'type': 'string', 'pattern': '^([a-z0-9\-_.+]{3,37})$' },
- 'tx_hash': { 'type': 'string', 'pattern': '^[0-9a-fA-F]+$' },
- 'confirmations': { 'type': 'integer', 'minimum': 0 },
- },
- },
- },
- 'update': {
- 'type': 'array',
- 'items': {
- 'type': 'object',
- 'properties': {
- 'name': { 'type': 'string', 'pattern': '^([a-z0-9\-_.+]{3,37})$' },
- 'tx_hash': { 'type': 'string', 'pattern': '^[0-9a-fA-F]+$' },
- 'confirmations': { 'type': 'integer', 'minimum': 0 },
- },
- },
- },
- 'transfer': {
- 'type': 'array',
- 'items': {
- 'type': 'object',
- 'properties': {
- 'name': { 'type': 'string', 'pattern': '^([a-z0-9\-_.+]{3,37})$' },
- 'tx_hash': { 'type': 'string', 'pattern': '^[0-9a-fA-F]+$' },
- 'confirmations': { 'type': 'integer', 'minimum': 0 },
- },
- },
- },
- 'renew': {
- 'type': 'array',
- 'items': {
- 'type': 'object',
- 'properties': {
- 'name': { 'type': 'string', 'pattern': '^([a-z0-9\-_.+]{3,37})$' },
- 'tx_hash': { 'type': 'string', 'pattern': '^[0-9a-fA-F]+$' },
- 'confirmations': { 'type': 'integer', 'minimum': 0 },
- },
- },
- },
- 'revoke': {
- 'type': 'array',
- 'items': {
- 'type': 'object',
- 'properties': {
- 'name': { 'type': 'string', 'pattern': '^([a-z0-9\-_.+]{3,37})$' },
- 'tx_hash': { 'type': 'string', 'pattern': '^[0-9a-fA-F]+$' },
- 'confirmations': { 'type': 'integer', 'minimum': 0 },
- },
- },
- },
- 'name_import': {
- 'type': 'array',
- 'items': {
- 'type': 'object',
- 'properties': {
- 'name': { 'type': 'string', 'pattern': '^([a-z0-9\-_.+]{3,37})$' },
- 'tx_hash': { 'type': 'string', 'pattern': '^[0-9a-fA-F]+$' },
- 'confirmations': { 'type': 'integer', 'minimum': 0 },
- },
- },
- },
- }
- }
-
-## Get unspent outputs [GET /v1/blockchains/{blockchainName}/{address}/unspent]
-+ DEPRECATED. Blockstack clients should use
- [blockstack.js](https://github.com/blockstack/blockstack.js) to query the
-blockchain.
-+ Authorization: `blockchain`
-+ Parameters
- + blockchainName : bitcoin (string) - the given blockchain
- + address : 1GuKR3nJi2VH3E1ZSPvuX8nAu3jNnr7xzq (string) - the address to get unspents for
-+ Response 200 (application/json)
- + Body
-
- [
- {
- "confirmations": 18,
- "out_script": "76a914ae6ee3760fccb8225541ca89f08c927930adf97b88ac",
- "outpoint": {
- "hash": "977d3a025790e2cbdb50f63761872f36e78fbb9c53d515cb4c53155a1964932d",
- "index": 1
- },
- "transaction_hash": "977d3a025790e2cbdb50f63761872f36e78fbb9c53d515cb4c53155a1964932d",
- "value": 76779
- }
- ]
-
- + Schema
-
- {
- 'type': 'array',
- 'items': {
- 'type': 'object',
- 'properties': {
- 'confirmations': { 'type': 'integer', 'minimum': 0 },
- 'out_script': { 'type': 'string', 'pattern': '^[0-9a-fA-F]+$' },
- 'outpoint': {
- 'type': 'object',
- 'properties': {
- 'hash': { 'type': 'string', 'pattern': '^[0-9a-fA-F]+$' },
- 'index': { 'type': 'integer', 'minimum': 0 },
- },
- },
- 'transaction_hash': { 'type': 'string', 'pattern': '^[0-9a-fA-F]+$' },
- 'value': { 'type': 'integer', 'minimum': 0 },
- },
- },
- }
-
-## Broadcast transaction [POST /v1/blockchains/{blockchainName}/txs]
-+ DEPRECATED. Blockstack clients should use
- [blockstack.js](https://github.com/blockstack/blockstack.js) to broadcast
-transactions.
-+ Authorization: `blockchain`
-+ Parameters
- + blockchainName : bitcoin (string) - the blockchain to broadcast on
-+ Request (application/json)
- + Schema
-
- {
- 'type': 'object',
- 'properties': {
- 'tx': {
- 'type': 'string',
- 'pattern': OP_HEX_PATTERN,
- },
- },
- 'additionalProperties': False,
- 'required': [
- 'tx'
- ],
- }
-
-+ Response 200 (application/json)
- + Body
-
- { 'status' : True, 'tx_hash' : '...' }
-
- + Schema
-
- {
- 'anyOf': [
- {
- 'type': 'object',
- 'properties': {
- 'status': { 'type': 'boolean' },
- 'tx_hash': { 'type': 'string', 'pattern': '^[0-9a-fA-F]+$' },
- },
- },
- {
- 'type': 'object',
- 'properties': {
- 'error': { 'type': 'string' },
- },
- },
- ]
- }
-
-# Group Namespace Operations
-## Get all namespaces [GET /v1/namespaces]
-+ Public Endpoint
-+ Response 200 (application/json)
- + Body
-
- {
- "namespaces": [
- ".id"
- ]
- }
-
-## Get namespace names [GET /v1/namespaces/{tld}/names?page={page}]
-Fetch a list of names from the namespace.
-+ Public Endpoint
-+ Parameters
- + tld: id (string) - the namespace to fetch names from
- + page: 23 (number) - names are returned in pages of size 100,
- so specify the page number.
-+ Response 200 (application/json)
- + Body
-
- [ "aldenquimby.id", "aldeoryn.id",
- "alderete.id", "aldert.id",
- "aldi.id", "aldighieri.id", ... ]
-
-# Group Resolver Endpoints
-## Lookup User [GET /v1/users/{username}]
-Lookup and resolver a user's profile. Defaults to the `id` namespace.
-Note that [blockstack.js](https://github.com/blockstack/blockstack.js) does
-*not* rely on this endpoint.
-
-+ Public Only Endpoint
-+ Subdomain Aware
-+ Legacy Endpoint
-+ Parameters
- + username: fred (string) - username to lookup
-+ Response 200 (application/json)
-
-
-
- {
- "fred.id": {
- "owner_address": "1CER5u4QXuqffHjHKrU76iMCsqtJLM5VHu",
- "profile": {
- "@context": "http://schema.org",
- "@type": "Person",
- "account": [
- {
- "@type": "Account",
- "identifier": "fredwilson",
- "placeholder": false,
- "proofType": "http",
- "proofUrl": "https://twitter.com/fredwilson/status/943066895422455809",
- "service": "twitter"
- }
- ],
- "description": "I am a VC",
- "image": [
- {
- "@type": "ImageObject",
- "contentUrl": "https://gaia.blockstack.org/hub/1CER5u4QXuqffHjHKrU76iMCsqtJLM5VHu/0/avatar-0",
- "name": "avatar"
- }
- ],
- "name": "Fred Wilson"
- },
- "public_key": "026c94d1897fa148fa6401247a339b55abd869a3d562fdae8a7fcb9a11f1f846f3",
- "verifications": [
- {
- "identifier": "fredwilson",
- "proof_url": "https://twitter.com/fredwilson/status/943066895422455809",
- "service": "twitter",
- "valid": true
- }
- ],
- "zone_file": {
- "$origin": "fred.id",
- "$ttl": 3600,
- "uri": [
- {
- "name": "_http._tcp",
- "priority": 10,
- "target": "https://gaia.blockstack.org/hub/1CER5u4QXuqffHjHKrU76iMCsqtJLM5VHu/0/profile.json",
- "weight": 1
- }
- ]
- }
- }
- }
-
-
-## Profile Search [GET /v1/search?query={query}]
-Searches for a profile using a search string.
-+ Public Only Endpoint
-+ Parameters
- + query: wenger (string) - the search query
-+ Response 200 (application/json)
- + Body
-
- {
- "results": [
- {
- "fullyQualifiedName": "albertwenger.id",
- "username": "albertwenger",
- "profile": {
- "@type": "Person",
- "account": [
- {
- "@type": "Account",
- "identifier": "albertwenger",
- "proofType": "http",
- "service": "twitter"
- },
- {
- "@type": "Account",
- "identifier": "albertwenger",
- "proofType": "http",
- "service": "facebook"
- },
- {
- "@type": "Account",
- "identifier": "albertwenger",
- "proofType": "http",
- "service": "github"
- },
- {
- "@type": "Account",
- "identifier": "1QHDGGLEKK7FZWsBEL78acV9edGCTarqXt",
- "role": "payment",
- "service": "bitcoin"
- }
- ],
- "address": {
- "@type": "PostalAddress",
- "addressLocality": "New York"
- },
- "description": "VC at USV.com",
- ...
- }
-
diff --git a/_site/core/attic/README.md b/_site/core/attic/README.md
deleted file mode 100644
index 33ae11f758..0000000000
--- a/_site/core/attic/README.md
+++ /dev/null
@@ -1,4 +0,0 @@
-# Legacy Documentation
-
-Documents here are out-of-date but preserved for posterity. Do not rely on
-them.
diff --git a/_site/core/attic/advanced_usage.md b/_site/core/attic/advanced_usage.md
deleted file mode 100644
index 5d75b35eff..0000000000
--- a/_site/core/attic/advanced_usage.md
+++ /dev/null
@@ -1,124 +0,0 @@
-# Advanced Usage
-
-This section details some of the advanced features in the CLI.
-
-## A Word of Warning
-
-Advanced features are meant to be used by experienced Blockstack users and developers, They receive less UI/UX testing than basic features, and their interfaces are expected to change to accomodate bugfixes and security fixes. Moreover, improper use of some advanced methods can cost you money, corrupt your profile, or compromise your wallet. Once they receive sufficient testing, an advanced feature may become a basic-mode feature in a subsequent release.
-
-**Do not use advanced mode unless you know what you are doing!**
-
-## Activating Advanced Mode
-
-To activate advanced mode, use the command `blockstack set_advanced_mode on`.
-
-To deactivate it later (recommended), use the command `blockstack set_advanced_mode off`.
-
-## Changing or Using Exiting Keys
-
-If you already have a payment key you want to use, or an owner key you want to migrate over, you can generate a wallet directly with `import_wallet`. We recommend using this command interactively, so you know which keys correspond to which usages.
-
-## Accounts
-
-With the accounts methods, you can directly manage your social proofs, link existing services to your profile, and store small bits of information.
-
-The account management methods are:
-* `get_account`: Look up an account in a name's profile. There can be more than one match.
-* `list_accounts`: List all accounts in a name's profile.
-* `put_account`: Add or update an account in a name's profile.
-* `delete_account`: Remove an account from a name's profile. This may need to be done more than once, if there are duplicates of the account.
-
-## Advanced Blockstack ID Queries
-
-Beyond `lookup` and `whois`, there are a few other more advanced queries you can run on Blockstack IDs. These include:
-
-### Listing Blockstack IDs
-* `get_all_names`: Get the list of every single Blockstack ID in existance.
-* `get_names_owned_by_address`: Get the list of names owned by a particular ownership address.
-
-### Querying the Blockchain
-* `get_name_blockchain_record`: Get the raw database record for a Blockstack ID. It will contain a *compressed* history of all name operations that have affected it. This is meant primarily for debugging purposes; to get an easier-to-parse listing of the information this command returns, use `get_name_blockchain_history`.
-* `get_name_blockchain_history`: Get the set of all prior states a Blockstack ID has been in, keyed by the block heights at which the state-change was processed.
-* `get_records_at`: Get the list of name operation records processed at a particular block height.
-* `list_update_history`: Get the list of all zonefile hashes that a Blockstack ID has ever had.
-
-### Zonefiles
-* `get_name_zonefile`: Get only a Blockstack ID's zonefile.
-* `list_zonefile_history`: Get the list of all zonefiles a Blockstack ID has ever had. **NOTE:** There is no guarantee that the server will hold copies of old zonefiles. This command is meant mainly for determining which historic zonefiles a server has processed.
-* `set_zonefile_hash`: This is the counterpart to `update`, but instead of setting the zonefile directly and uploading it to storage, you can use this command to directly set the data hash for a Blockstack ID. **NOTE:** You should ensure that the associated zonefile data has been replicated off-chain to a place where other users can get at it.
-
-### Lightweight Queries
-
-The lightweight lookup protocol for Blockstack is called *Simplified Name Verification* (SNV). This command returns a prior blockchain-level record given a more recent known-good consensus hash, serial number, or transaction ID of a transaction that contains a consensus hash. The CLI does not need to trust the Blockstack server to use these commands.
-
-* `lookup_snv`: Use the Merkle skip-list in the name database to look up a historic name operation on a Blockstack ID.
-
-## Consensus Queries
-
-You can query consensus hash information from the server with the following commands:
-
-* `consensus`: Get the consensus hash at a particular block height
-
-## Namespace Queries
-
-In addition to querying Blockstack IDs, the CLI has advanced commands for querying namespaces. These include:
-
-* `get_namespace_blockchain_record`: Get the raw database record for a Blockstack namespace. It will contain a *compressed* history of all namespace operations that have affected it.
-* `get_names_in_namespace`: Get the list of every Blockstack ID in a particular namespace.
-* `get_namespace_cost`: Get the cost required to preorder a namespace. Does *not* include the cost to reveal and ready it, nor does it include the transaction fees.
-
-## Namespace Creation
-
-**WARNING:** We do not recommend that you try to do this by yourself. Creating a namespace is **EXTREMELY EXPENSIVE**. If you are interested in creating your own namespace, please contact the Blockstack developers on the [Blockstack Slack](http://chat.blockstack.org).
-
-These methods allow you to create a namespace. There are three steps: preordering, revealing, and readying. Preordering a namespace is like preordering a name--you announce the hash of the namespace ID and the address that will control it. Revealing a namespace not only reveals the namespace ID, but also sets the pricing and lifetime rules for names in the namespace. After revealing the namespace, the namespace controller can pre-populate the namespace by importing Blockstack IDs. Once the namespace has been pre-populated, the controller sends a final transaction that readies the namespace for general use.
-
-* `namespace_preorder`: Preorder a namespace.
-* `namespace_reveal`: Reveal a namespace, and set its pricing and lifetime parameters. **NOTE:** This must be done within 144 blocks of sending the namespace preorder transaction.
-* `name_import`: Import a name into a revealed (but not readied) namespace. You can set its owner address and zonefile hash directly.
-* `namespace_ready`: Open a namespace for general registrations.
-
-## Data Storage
-
-Blockstack allows users to store arbitrary data to any set of storage providers for which the CLI has a driver. The data will be signed by the user's data key, so when other users read the data later on, they can verify that it is authentic (i.e. the storage provider is not trusted). Moreover, Blockstack is designed such that users don't have to know or care about which storage providers were used--as far as users can see, storage providers are just shared hard drives.
-
-There are two types of data supported by Blockstack: *mutable* data, and *immutable* data. Mutable data is linked by the profile, and can be written as fast and as frequently as the storage provider allows. Mutable data is addressed by URL.
-
-**WARNING:** While mutable data guarantees end-to-end authenticity, there is a chance that a malicious storage provider can serve new readers stale versions of the data. That is, users who have read the latest data already will not get tricked into reading stale data, but users who have *not yet* read the latest data *can* be tricked (i.e. the CLI keeps a version number for mutable data to do so). This must be taken into account if you intend to use this API.
-
-Immutable data, however, is content-addressed, and its cryptographic hash is stored to the user's zonefile. Writing immutable data will entail updating the zonefile and sending an `update` transaction (handled internally), so it will be slow by comparison. This has the advantage that storage providers cannot perform the aforementioned stale data attack, but has the downside that writes cost money and take a long time to complete.
-
-That said, we recommend using the mutable data API with several different storage providers whenever possible.
-
-### Mutable Data
-
-The following commands affect mutable data:
-
-* `get_mutable`: Use the profile to look up and fetch a piece of mutable data.
-* `put_mutable`: Add a link to mutable data to the profile, and replicate the signed data itself to all storage providers. Other users will need the data's name to read it with `get_mutable`.
-* `delete_mutable`: Remove a link to mutable data from the profile, and ask all storage providers to delete the signed data.
-
-### Immutable Data
-
-The following commnds affect immutable data:
-
-* `get_immutable`: Look up and fetch a piece of immutable data. You can supply either the name of the data, or its hash (both are stored in the zonefile, so there is no gain or loss of security in this choice).
-* `put_immutable`: Replicate a piece of data to all storage providers, add its name and hash to the zonefile, and issue an `update` to upload the new zonefile to Blockstack servers and write the hash to the blockchain.
-* `delete_immutable`: Remove the link to the data from the zonefile, ask all storage providers to delete the data, and issue an `update` to upload the new zonefile to Blockstack servers and write the new hash to the blockchain.
-* `list_immutable_data_history`: Given the name of a piece of immutable data, query the zonefile history to find the historic list of hashes it has had. **NOTE:** Like `list_zonefile_history` above, this only returns data hashes for the data if the Blockstack server has the historic zonefile.
-
-## Fault Recovery
-
-Sometimes, things beyond our control can happen. Transactions can get stuck, storage providers can go offline or corrupt data, and so on. These commands are meant to assist in recovering from these problems:
-
-* `set_profile`: Directly set a Blockstack ID's profile. All previous accounts, data links, etc. must be included in the new profile, since the old profile (if still present) will be overwritten by the one given here.
-* `convert_legacy_profile`: Given a legacy profile taken from a resolver, directly convert it into a new profile. This can be used with `set_profile` to recover from a failed profile migration.
-* `unqueue`: If a transaction gets lost or stuck, you can remove it from the CLI's transaction queue with this command. This will allow you to re-try it.
-* `rpcctl`: This lets you directly start or stop the Blockstack CLI's background daemon, which lets you recover from any crashes it experiences (you can find a trace of its behavior in `~/.blockstack/api_endpoint.log`)
-
-## Programmatic Access
-
-Other programs may want to make RPC calls the Blockstack CLI daemon. They can do so using either the `blockstack_client` Python package, or they can do so via the CLI as follows:
-
-* `rpc`: Issue a JSON RPC call. Takes a raw JSON string that encodes a list of arguments.
-
diff --git a/_site/core/attic/figures/gaia-authentication.png b/_site/core/attic/figures/gaia-authentication.png
deleted file mode 100644
index 03ca186ef2..0000000000
Binary files a/_site/core/attic/figures/gaia-authentication.png and /dev/null differ
diff --git a/_site/core/attic/figures/gaia-connect.png b/_site/core/attic/figures/gaia-connect.png
deleted file mode 100644
index 34ab79479f..0000000000
Binary files a/_site/core/attic/figures/gaia-connect.png and /dev/null differ
diff --git a/_site/core/attic/figures/gaia-getfile.png b/_site/core/attic/figures/gaia-getfile.png
deleted file mode 100644
index 29d87c7252..0000000000
Binary files a/_site/core/attic/figures/gaia-getfile.png and /dev/null differ
diff --git a/_site/core/attic/figures/gaia-listdir.png b/_site/core/attic/figures/gaia-listdir.png
deleted file mode 100644
index b48072b7d2..0000000000
Binary files a/_site/core/attic/figures/gaia-listdir.png and /dev/null differ
diff --git a/_site/core/attic/figures/gaia-putfile.png b/_site/core/attic/figures/gaia-putfile.png
deleted file mode 100644
index 6ad02a5b82..0000000000
Binary files a/_site/core/attic/figures/gaia-putfile.png and /dev/null differ
diff --git a/_site/core/attic/gaia.md b/_site/core/attic/gaia.md
deleted file mode 100644
index b63e0536d3..0000000000
--- a/_site/core/attic/gaia.md
+++ /dev/null
@@ -1,461 +0,0 @@
-# LEGACY DOCUMENTATION
-
-Please see the [latest Gaia documentation](https://github.com/blockstack/gaia)
-
-Gaia: The Blockstack Storage System
-====================================
-
-The Blockstack storage system, called "Gaia", is used to host each user's data
-without requiring users to run their own servers.
-
-Gaia works by hosting data in one or more existing storage systems of the user's choice.
-These storage systems include cloud storage systems like Dropbox and Google
-Drive, they include personal servers like an SFTP server or a WebDAV server, and
-they include decentralized storage systems like BitTorrent or IPFS. The point
-is, the user gets to choose where their data lives, and Gaia enables
-applications to access it via a uniform API.
-
-A high-level analogy is to compare Gaia to the VFS and block layer in a UNIX
-operating system kernel, and to compare existing storage systems to block
-devices. Gaia has "drivers" for each storage system that allow it to load,
-store, and delete chunks of data via a uniform interface, and it gives
-applications a familiar API for organizing their data.
-
-Applications interface with Gaia via the [Blockstack Core
-API](https://github.com/blockstack/blockstack-core/tree/master/api). Javascript
-applications connect to Gaia using [Blockstack Portal](https://github.com/blockstack/blockstack-portal),
-which helps them bootstrap a secure connection to Blockstack Core.
-
-# Datastores
-
-Gaia organizes data into datastores. A **datastore** is a filesystem-like
-collection of data that is backed by one or more existing storage systems.
-
-When a user logs into an application, the application will create or connect to
-the datastore that holds the user's data. Once connected, it can proceed to
-interact with its data via POSIX-like functions: `mkdir`, `listdir`, `rmdir`,
-`getFile`, `putFile`, `deleteFile`, and `stat`.
-
-A datastore has exactly one writer: the user that creates it. However, all data
-within a datastore is world-readable by default, so other users can see the
-owner's writes even when the owner is offline. Users manage access controls
-by encrypting files and directories to make them readable to other specific users.
-All data in a datastore is signed by a datastore-specific key on write, in order
-to guarantee that readers only consume authentic data.
-
-The application client handles all of the encryption and signing. The other
-participants---Blockstack Portal, Blockstack Core, and the storage
-systems---only ferry data back and forth between application clients.
-
-## Data Organization
-
-True to its filesystem inspiration, data in a datastore is organized into a
-collection of inodes. Each inode has two parts:
-
-* a **header**, which contains:
-
- * the inode type (i.e. file or directory)
-
- * the inode ID (i.e. a UUID4)
-
- * the hash of the data it stores
-
- * the size of the data it stores
-
- * a signature from the user
-
- * the version number
-
- * the ID of the device from which it was sent (see Advanced Topics below)
-
-* a **payload**, which contains the raw bytes to be stored.
-
- * For files, this is just the raw bytes.
-
- * For directories, this is a serialized data structure that lists the names
- and inode IDs of its children, as well as a copy of the header.
-
-The header has a fixed length, and is somewhat small--only a few hundred bytes.
-The payload can be arbitrarily large.
-
-## Data Consistency
-
-The reason for organizing data this way is to make cross-storage system reads
-efficient, even when there are stale copies of the data available. In this
-organization, reading an inode's data is a matter of:
-
-1. Fetching all copies of the header
-
-2. Selecting the header with the highest version number
-
-3. Fetching the payload from the storage system that served the latest header.
-
-This way, we can guarantee that:
-
-* The inode payload is fetched *once* in the common case, even if there are multiple stale copies of the inode available.
-
-* All clients observe the *strongest* consistency model offerred by the
- underlying storage providers.
-
-* All readers observe a *minimum* consistency of monotonically-increasing reads.
-
-* Writers observe sequential consistency.
-
-This allows Gaia to interface with decentralized storage systems that make
-no guarantees regarding data consistency.
-
-*(Aside 1: The Core node keeps track of the highest last-seen inode version number,
-so if all inodes are stale, then no data will be returned).*
-
-*(Aside 2: In step 3, an error path exists whereby all storage systems will be
-queried for the payload if the storage system that served the fresh inode does
-not have a fresh payload).*
-
-# Accessing the Datastore
-
-Blockstack applications get access to the datastore as part of the sign-in
-process. Suppose the user wishes to sign into the application `foo.app`. Then,
-the following protocol is executed:
-
-
-
-1. Using `blockstack.js`, the application authenticates to Blockstack Portal via
-`makeAuthRequest()` and `redirectUserToSignIn()`.
-
-2. When Portal receives the request, it contacts the user's Core node to get the
- list of names owned by the user.
-
-3. Portal redirects the user to a login screen, and presents the user with the
- list of names to use. The user selects which name to sign in as.
-
-4. Now that Portal knows which name to use, and which application is signing in,
- it loads the datastore private key and requests a Blockstack Core session
-token. This token will be used by the application to access Gaia.
-
-5. Portal creates an authentication response with `makeAuthResponse()`, which it
- relays back to the application.
-
-6. The application retrieves the datastore private key and the Core session
- token from the authentication response object.
-
-
-## Creating a Datastore
-
-Once the application has a Core session token and the datastore private key, it
-can proceed to connect to it, or create it if it doesn't exist. To do so, the
-application calls `datastoreConnectOrCreate()`.
-
-This method contacts the Core node directly. It first requests the public
-datastore record, if it exists. The public datastore record
-contains information like who owns the datastore, when it was created, and which
-drivers should be used to load and store its data.
-
-
-
-Suppose the user signing into `foo.app` does not yet have a datastore, and wants
-to store her data on storage providers `A`, `B`, and `C`. Then, the following
-protocol executes:
-
-1. The `datastoreConnectOrCreate()` method will generate a signed datastore record
-stating that `alice.id`'s public key owns the datastore, and that the drivers
-for `A`, `B`, and `C` should be loaded to access its data.
-
-2. The `datastoreConnectOrCreate()` method will call `mkdir()` to create a
-signed root directory.
-
-3. The `datastoreConnectOrCreate()` method will send these signed records to the Core node.
-The Core node replicates the root directory header (blue path), the root
-direcory payload (green path), and the datastore record (gold path).
-
-4. The Core node then replicates them with drivers `A`, `B`, and `C`.
-
-Now, storage systems `A`, `B`, and `C` each hold a copy of the datastore record
-and its root directory.
-
-*(Aside: The datastore record's consistency is preserved the same way as the
-inode consistency).*
-
-## Reading Data
-
-Once the application has a Core session token, a datastore private key, and a
-datastore connection object, it can proceed to read it. The available methods
-are:
-
-* `listDir()`: Get the contents of a directory
-
-* `getFile()`: Get the contents of a file
-
-* `stat()`: Get a file or directory's header
-
-Reading data is done by path, just as it is in UNIX. At a high-level, reading
-data involes (1) resolving the path to the inode, and (2) reading the inode's
-contents.
-
-Path resolution works as it does in UNIX: the root directory is fetched, then
-the first directory in the path, then the second directory, then the third
-directory, etc., until either the file or directory at the end of the path is
-fetched, or the name does not exist.
-
-### Authenticating Data
-
-Data authentication happens in the Core node,.
-This is meant to enable linking files and directories to legacy Web
-applications. For example, a user might upload a photo to a datastore, and
-create a public URL to it to share with friends who do not yet use Blockstack.
-
-By default, the Core node serves back the inode payload data
-(`application/octet-stream` for files, and `application/json` for directories).
-The application client may additionally request the signatures from the Core
-node if it wants to authenticate the data itself.
-
-### Path Resolution
-
-Applications do not need to do path resolution themselves; they simply ask the
-Blockstack Core node to do so on their behalf. Fetching the root directory
-works as follows:
-
-1. Get the root inode ID from the datastore record.
-
-2. Fetch all root inode headers.
-
-3. Select the latest inode header, and then fetch its payload.
-
-4. Authenticate the data.
-
-For example, if a client wanted to read the root directory, it would call
-`listDir()` with `"/"` as the path.
-
-
-
-The blue paths are the Core node fetching the root inode's headers. The green
-paths are the Core node selecting the latest header and fetching the root
-payload. The Core node would reply the list of inode names within the root
-directory.
-
-Once the root directory is resolved, the client simply walks down the path to
-the requested file or directory. This involves iteratively fetching a
-directory, searching its children for the next directory in the path, and if it
-is found, proceeding to fetch it.
-
-### Fetching Data
-
-Once the Core node has resolved the path to the base name, it looks up the inode
-ID from the parent directory and fetches it from the backend storage providers
-via the relevant drivers.
-
-For example, fetching the file `/bar` works as follows:
-
-
-
-1. Resolve the root directory (blue paths)
-
-2. Find `bar` in the root directory
-
-3. Get `bar`'s headers (green paths)
-
-4. Find the latest header for `bar`, and fetch its payload (gold paths)
-
-5. Return the contents of `bar`.
-
-## Writing Data
-
-There are three steps to writing data:
-
-* Resolving the path to the inode's parent directory
-
-* Creating and replicating the new inode
-
-* Linking the new inode to the parent directory, and uploading the new parent
- directory.
-
-All of these are done with both `putFile()` and `mkdir()`.
-
-### Creating a New Inode
-
-When it calls either `putFile()` or `mkdir()`, the application client will
-generate a new inode header and payload and sign them with the datastore private
-key. Once it has done so successfully, it will insert the new inode's name and
-ID into the parent directory, give the parent directory a new version number,
-and sign and replicate it and its header.
-
-For example, suppose the client attempts to write the data `"hello world"` to `/bar`.
-To do so:
-
-
-
-1. The client executes `listDir()` on the parent directory, `/` (blue paths).
-
-2. If an inode by the name of `bar` exists in `/`, then the method fails.
-
-3. The client makes a new inode header and payload for `bar` and signs them with
- the datastore private key. It replicates them to the datastore's storage
-drivers (green paths).
-
-4. The client adds a record for `bar` in `/`'s data obtained from (1),
- increments the version for `/`, and signs and replicates `/`'s header and
-payload (gold paths).
-
-
-### Updating a File or Directory
-
-A client can call `putFile()` multiple times to set the file's contents. In
-this case, the client creates, signs, and replicates a new inode header and new
-inode payload for the file. It does not touch the parent directory at all.
-In this case, `putFile()` will only succeed if the parent directory lists an
-inode with the given name.
-
-A client cannot directly update the contents of a directory.
-
-## Deleting Data
-
-Deleting data can be done with either `rmdir()` (to remove an empty directory)
-or `deleteFile()` (to remove a file). In either case, the protocol executed is
-
-1. The client executes `listDir()` on the parent directory
-
-2. If an inode by the given name does not exist, then the method fails.
-
-3. The client removes the inode's name and ID from the directory listing, signs
- the new directory, and replicates it to the Blockstack Core node.
-
-4. The client tells the Blockstack Core node to delete the inode's header and
- payload from all storage systems.
-
-
-# Advanced Topics
-
-These features are still being implemented.
-
-## Data Integrity
-
-What happens if the client crashes while replicating new inode state? What
-happens if the client crashes while deleting inode state? The data hosted in
-the underlying data stores can become inconsistent with the directory structure.
-
-Given the choice between leaking data and rendering data unresolvable, Gaia
-chooses to leak data.
-
-### Partial Inode-creation Failures
-
-When creating a file or directory, Gaia stores four records in this order:
-
-* the new inode payload
-
-* the new inode header
-
-* the updated parent directory payload
-
-* the updated parent directory header
-
-If the new payload replicates successfully but the new header does not, then the
-new payload is leaked.
-
-If the new payload and new header replicate successfully, but neither parent
-directory record succeeds, then the new inode header and payload are leaked.
-
-If the new payload, new header, and updated parent directory payload replicate
-successfully, but the updated parent header fails, then not only are the new
-inode header and payload leaked, but also *reading the parent directory will
-fail due to a hash mismatch between its header and inode*. This can be detected
-and resolved by observing that the copy of the header in the parent directory
-payload has a later version than the parent directory header indicates.
-
-### Partial Inode-deletion Failures
-
-When deleting a file or directory, Gaia alters records in this order:
-
-* update parent directory payload
-
-* update parent directory header
-
-* delete inode header
-
-* delete inode payload
-
-Similar to partial failures from updating parent directories when creating
-files, if the client replicates the new parent directory inode payload but fails
-before it can update the header, then clients will detect on the next read that
-the updated payload is valid because it has a signed inode header with a newer
-version.
-
-If the client successfully updates the parent directory but fails to delete
-either the inode header or payload, then they are leaked. However, since the
-directory was updated, no correct client will access the deleted inode data.
-
-### Leak Recovery
-
-Gaia's storage drivers are designed to keep the inode data they store in a
-"self-contained" way (i.e. within a single folder or bucket). In the future,
-we will implement a `fsck`-like tool that will scan through a datastore and find
-the set of inode headers and payloads that are no longer referenced and delete
-them.
-
-## Multi-Device Support
-
-Contemporary users read and write data across multiple devices. In this
-document, we have thus far described datastores with the assumption that there
-is a single writer at all times.
-
-This assumption is still true in a multi-device setting, since a user is
-unlikely to be writing data with the same application simultaneously from two
-different devices.
-
-However, an open question is how multiple devices can access the same
-application data for a user. Our design goal is to **give each device its own
-keyring**, so if it gets lost, the user can revoke its access without having to
-re-key her other devices.
-
-To do so, we'll expand the definition of a datastore to be a **per-user,
-per-application, and per-device** collection of data. The view of a user's
-application data will be constructed by merging each device-specific
-datastore, and resolving conflicts by showing the "last-written" inode (where
-"last-written" is determined by a loosely-synchronized clock).
-
-For example, if a user uploads a profile picture from their phone, and then
-uploads a profile picture from their tablet, a subsequent read will query the
-phone-originated picture and the tablet-originated picture, and return the
-tablet-originated picture.
-
-The aforementioned protocols will need to be extended to search for inode
-headers not only on each storage provider, but also search for inodes on the
-same storage provider that may have been written by each of the user's devices.
-Without careful optimization, this can lead to a lot of inode header queries,
-which we address in the next topic.
-
-## A `.storage` Namespace
-
-Blockstack Core nodes can already serve as storage "gateways". That is, one
-node can ask another node to store its data and serve it back to any reader.
-
-For example, Alice can make her Blockstack Core node public and program it to
-store data to her Amazon S3 bucket and her Dropbox account. Bob can then post data to Alice's
-node, causing her node to replicate data to both providers. Later, Charlie can
-read Bob's data from Alice's node, causing Alice's node to fetch and serve back
-the data from her cloud storage. Neither Bob nor Charlie have to set up accounts on
-Amazon S3 and Dropbox this way.
-
-Since Alice is on the read/write path between Bob and Charlie and cloud storage,
-she has the opportunity to make optimizations. First, she can program her
-Core node to synchronously write data to
-local disk and asynchronously back it up to S3 and Dropbox. This would speed up
-Bob's writes, but at the cost of durability (i.e. Alice's node could crash
-before replicating to the cloud).
-
-In addition, Alice can program her Core node to service all reads from disk. This
-would speed up Charlie's reads, since he'll get the latest data without having
-to hit back-end cloud storage providers.
-
-Since Alice is providing a service to Bob and Charlie, she will want
-compensation. This can be achieved by having both of them send her money via
-the underlying blockchain.
-
-To do so, she would register her node's IP address in a
-`.storage` namespace in Blockstack, and post her rates per GB in her node's
-profile and her payment address. Once Bob and Charlie sent her payment, her
-node would begin accepting reads and writes from them up to the capacity
-purchased. They would continue sending payments as long as Alice provides them
-with service.
-
-Other experienced node operators would register their nodes in `.storage`, and
-compete for users by offerring better durability, availability, performance,
-extra storage features, and so on.
diff --git a/_site/core/auth/howitworks.html b/_site/core/auth/howitworks.html
deleted file mode 100644
index 121d9c31ca..0000000000
--- a/_site/core/auth/howitworks.html
+++ /dev/null
@@ -1,597 +0,0 @@
-
-
-
-
-
-
-
-
-How Atlas Works | Blockstack
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- How Atlas Works
-
-
-
-
-
-
-
-
-
Atlas was designed to overcome the structural weaknesses inherent to all
-distributed hash tables. In particular, it uses an unstructured peer network to
-maximize resilience against network link failure, and it uses the underlying
-blockchain (through BNS) to rate-limit chunk announcements.
-
-
This section contains the following sections:
-
-
-
-
Peer Selection
-
-
Atlas peers self-organize into an unstructured peer-to-peer network.
-The Atlas peer network is a random K-regular
-graph . Each node maintains
-K neighbors chosen at random from the set of Atlas peers.
-
-
Atlas nodes select peers by carrying out an unbiased random walk of the peer
-graph. When “visiting” a node N , it will ask for N ’s neighbors and then
-“step” to one of them with a probability dependent on N ’s out-degree and the
-neighbor’s in-degree.
-
-
The sampling algorithm is based on the Metropolis-Hastings (MH) random graph walk
-algorithm, but with a couple key differences. In particular, the algorithm
-attempts to calculate an unbiased peer graph sample that accounts for the fact
-that most nodes will be short-lived or unreliable, while a few persistent nodes
-will remain online for long periods of time. The sampling algorithm accounts
-for this with the following tweaks:
-
-
-
- If the neighbors of the visited node N are all unresponsive, the random
-walk resets to a randomly-chosen known neighbor. There is no back-tracking on
-the peer graph in this case.
-
-
- The transition probability from N to a live neighbor is NOT min(1,
-degree(neighbor)/degree(N)) like it is in the vanilla MH algorithm. Instead,
-the transition probability discourages backtracking to the previous neighbor N_prev ,
-but in a way that still guarantees that the sampling will remain unbiased.
-
-
- A peer does not report its entire neighbor set when queried,
-but only reports a random subset of peers that have met a minimium health threshold.
-
-
- A new neighbor is only selected if it belongs to the same BNS
-fork-set (i.e. it reports
-as having a recent valid consensus hash).
-
-
-
-
The algorithm was adapted from the work from Lee, Xu, and
-Eun in the proceedings of
-ACM SIGMETRICS 2012.
-
-
Comparison to DHTs
-
-
The reason Atlas uses an unstructured random peer network
-instead of a distributed hash table
-(DHT) is that DHTs are susceptbile to Sybil attacks. An adaptive adversary can
-insert malicious nodes into the DHT in order to stop victims from
-resolving chunks or finding honest neighbors.
-
-
Chunk Censorship
-
-
In a DHT, an attacker can censor a chunk by inserting nodes into the peers’ routing tables
-such that the attacker takes control over all of the chunk’s hash buckets.
-It can do so at any point in time after the chunk was first stored,
-because only the peers who maintain the chunk’s hash bucket have to store it.
-This is a fundamental problem with structured overlay networks
-that perform request routing based on content hash—they give the attacker
-insight as to the path(s) the queries take through the peer graph, and thus
-reduce the number of paths the attacker must disrupt in order to censor the
-chunk.
-
-
Atlas uses an unstructured overlay network combined with a 100% chunk
-replication strategy in order to maximize
-the amount of work an adversary has to do to censor a chunk.
-In Atlas, all peers replicate a chunk, and the paths the chunk take through the
-network are independent of the content and randomized by the software
-(so the paths cannot be predicted in advance). The attacker’s only
-recourse is to quickly identify the nodes that can serve the chunk and partition them from
-the rest of the network in order to carry out a censorship attack.
-This requires them to have visibility into the vast majority of network links in
-the Atlas network (which is extremely difficult to do, because in practice Atlas
-peers maintain knowledge of up to 65536 neighbors and only report 10 random peers
-when asked).
-
-
Neighbor Censorship
-
-
Another problem with DHTs is that their overlay
-network structure is determined by preferential attachment. Not every peer that
-contacts a given DHT node has an equal chance of becoming its neighbor.
-The node will instead rank a set of peers as being more or less ideal
-for being neighbors. In DHTs, the degree of preference a node exhibits to
-another node is usually a function of the node’s self-given node identifier
-(e.g. a node might want to select neighbors based on proximity in the key
-space).
-
-
The preferential attachment property means that an adaptive adversary can game the node’s
-neighbor selection algorithm by inserting malicious nodes that do not
-forward routing or lookup requests. The attacker does not even have to eclipse
-the victim node—the victim node will simply prefer to talk to the attacker’s unhelpful nodes
-instead of helpful honest nodes. In doing so, the attacker can prevent honest peers from discovering each
-other and each other’s chunks.
-
-
Atlas’s neighbor selection strategy does not exhibit preferential attachment
-based on any self-reported node properties. A
-node is selected as a neighbor only if it is reached through an unbiased random graph
-walk, and if it responds to queries correctly.
-In doing so, an attacker is forced to completely eclipse a set of nodes
-in order to cut them off from the rest of the network.
-
-
Chunk Propagation
-
-
Atlas nodes maintain an inventory of chunks that are known to exist. Each
-node independently calculates the chunk inventory from its BNS database.
-Because the history of name operations in BNS is linearized, each node can
-construct a linearized sub-history of name operations that can set chunk
-hashes as their name state. This gives them a linearized sequence of chunks,
-and every Atlas peer will independently arrive at the same sequence by reading
-the same blockchain.
-
-
Atlas peers keep track of which chunks are present and which are absent. They
-each construct an inventory vector of chunks V such that V[i] is set to 1
-if the node has the chunk whose hash is in the i th position in the chunk
-sequence (and set to 0 if it is absent).
-
-
Atlas peers exchange their inventory vectors with their neighbors in order to
-find out which chunks they each have. Atlas nodes download chunks from
-neighbors in rarest-first order in order to prioritize data replication for the
-chunks that are currently most at-risk for disappearing due to node failure.
-
-
Name operation | chunk hashes | chunk data | Inventory
- history | as name state | | vector
-
-+-------------------+
-| NAME_PREORDER |
-+-------------------+----------------+
-| NAME_REGISTRATION | chunk hash | "0123abcde..." 1
-+-------------------+----------------+
-| NAME_UPDATE | chunk hash | (null) 0
-+-------------------+----------------+
-| NAME_TRANSFER |
-+-------------------+
-| NAME_PREORDER |
-+-------------------+----------------+
-| NAME_IMPORT | chunk hash | "4567fabcd..." 1
-+-------------------+----------------+
-| NAME_TRANSFER |
-+-------------------|
- . . .
-
-
-Figure 2: Relationship between Atlas node chunk inventory and BNS name state.
-Some name operations announce name state in the blockchain, which Atlas
-interprets as a chunk hash. The Atlas node builds up a vector of which chunks
-it has and which ones it does not, and announces it to other Atlas peers so
-they can fetch chunks they are missing. In this example, the node's
-inventory vector is [1, 0, 1], since the 0th and 2nd chunks are present
-but the 1st chunk is missing.
-
-
-
-
Querying Chunk Inventories
-
-
Developers can query a node’s inventory vector as follows:
-
-
>>> import blockstack
->>> result = blockstack . lib . client . get_zonefile_inventory ( "https://node.blockstack.org:6263" , 0 , 524288 )
->>> print len ( result [ 'inv' ])
-11278
->>>
-
-
-
-
The variable result['inv'] here is a big-endian bit vector, where the i th
-bit is set to 1 if the i th chunk in the chunk sequence is present. The bit at
-i=0 (the earliest chunk) refers to the leftmost bit.
-
-
A sample program that inspects a set of Atlas nodes’ inventory vectors and determines
-which ones are missing which chunks can be found
-here .
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Related Articles
-
-
-
-
-
-
-
-
-
-
-
-
-
- Name
- E-mail
- Message
- Go!
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Blockstack
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/_site/core/auth/howtouse.html b/_site/core/auth/howtouse.html
deleted file mode 100644
index c8a85c133c..0000000000
--- a/_site/core/auth/howtouse.html
+++ /dev/null
@@ -1,531 +0,0 @@
-
-
-
-
-
-
-
-
-
How to Use the Atlas Network | Blockstack
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- How to Use the Atlas Network
-
-
-
-
-
-
-
-
-
This section teaches you how to use the Atlas network, it contains the
-following sections:
-
-
-
-
The API
-
-
While the Blockstack software stack expects that Atlas-hosted data is made up of
-DNS zone files, Atlas itself does not enforce this (nor does it care about the
-format of its chunks). It is designed as a general-purpose chunk store.
-Nevertheless, the ubiquitous use of Atlas to store data as DNS zone files has
-had an influence on its API design—fields and method names frequently allude
-to zone files and zone file hashes. This is intentional.
-
-
The public BNS API endpoint does not support
-resolving Atlas chunks that do not encode Gaia routing information or subdomain
-information. To directly interact with Atlas, developers will need to install
-Blockstack Core and use its
-Python client libraries for these examples.
-
-
Looking up Chunks
-
-
All Atlas chunks are addressed by the RIPEMD160 hash of the SHA256 hash of the
-chunk data. A client can query up to 100 chunks in one RPC call.
-
-
A client can look up a chunk with the get_zonefiles() method. If successful,
-the returned payload will be a dict with a zonefiles key that maps the chunk
-hashes to their respective data.
-
-
>>> import blockstack
->>> data = blockstack . lib . client . get_zonefiles ( 'https://node.blockstack.org:6263' , [ '1b89a685f4c4ea245ce9433d0b29166c22175ab4' ])
->>> print data [ 'zonefiles' ][ '1b89a685f4c4ea245ce9433d0b29166c22175ab4' ]
-$ ORIGIN duckduckgo_tor . id
-$ TTL 3600
-tor TXT "3g2upl4pq6kufc4m.onion"
-
->>>
-
-
-
-
(This particular chunk happens to be associated with the BNS name
-duckduckgo_tor.id).
-
-
Adding a New Chunk
-
-
The only way to add a chunk to Atlas is to do so through an on-chain name in
-BNS. Adding a new chunk is a two-step process:
-
-
- The name owner announces the chunk hash as a name’s state
-via a NAME_REGISTRATION, NAME_UPDATE, NAME_RENEWAL, or NAME_IMPORT transaction.
- Once the transaction is confirmed and processed by BNS, the name owner
-broadcasts the matching zone file.
-
-
-
Setting a name’s state to be the hash of a chunk is beyond the scope of this
-document, since it needs to be done through a BNS client.
-See the relevant documentation for
-blockstack.js and the Blockstack
-Browser for doing this.
-
-
Once the name operation is confirmed, you can announce the data to the
-Atlas network. You can do so with the Python client as follows:
-
-
>>> import blockstack
->>> import base64
->>> data = "..." # this is the chunk data you will announce
->>> data_b64 = base64 . b64encode ( data )
->>> result = blockstack . lib . client . put_zonefiles ( 'https://node.blockstack.org:6263' , [ data_b64 ])
->>> assert result [ 'saved' ][ 0 ] == 1
->>>
-
-
-
-
At most five chunks can be announced in one RPC call.
-Note that the data must be base64-encoded before it can be announced.
-
-
When the put_zonefiles() method succeeds, it returns a dict with a list
-under the saved key. Here, result['saved'][i] will be 1 if the ith
-chunk given to put_zonefiles() was saved by the node, and 0 if not.
-The node will not save a chunk if it is too big, or if it has not yet processed
-the name operation that contained the chunk’s hash.
-
-
The put_zonefiles() method is idempotent.
-
-
Propagating Chunks
-
-
Atlas peers will each store a copy of the chunks you announce. In the
-background, they will asynchronously announce to one another which chunks they
-have available, and replicate them to one another in a rarest-first order (much
-like how BitTorrent works). Eventually, every Atlas peer will receive the
-chunk.
-
-
However, developers can accelerate this process by eagerly propagating chunks.
-To do so, they can ask an Atlas peer for its immediate neighbors in the Atlas
-peer graph, and replicate the chunk to each of them as well.
-
-
For example, this code will replicate the chunk to not only
-https://node.blockstack.org:6263, but also to its immediate neighbors.
-
-
>>> import blockstack
->>> import base64
->>> data = "..." # this is the chunk you will replicate widely
->>> data_b64 = base64 . b64encode ( data )
->>>
->>> result = blockstack . lib . client . get_atlas_peers ( 'https://node.blockstack.org:6263' )
->>> neighbors = result [ 'peers' ]
->>> print ", " . join ( neighbors )
-13.65 . 207.163 : 6264 , 52.225 . 128.191 : 6264 , node . blockstack . org : 6264 , 23.102 . 162.7 : 6264 , 52.167 . 230.235 : 6264 , 23.102 . 162.124 : 6264 , 52.151 . 59.26 : 6264 , 13.92 . 134.106 : 6264
->>>
->>> for neighbor in neighbors :
-... result = blockstack . lib . client . put_zonefiles ( neighbor , [ data_b64 ])
-... assert result [ 'saved' ][ 0 ] == 1
-...
->>>
-
-
-
-
This is not strictly necessary, but it does help accelerate chunk replication
-and makes it less likely that a chunk will get lost due to individual node
-failures.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Related Articles
-
-
-
-
-
-
-
-
-
-
-
-
-
- Name
- E-mail
- Message
- Go!
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Blockstack
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/_site/core/auth/overview.html b/_site/core/auth/overview.html
deleted file mode 100644
index 3a2e5ba13e..0000000000
--- a/_site/core/auth/overview.html
+++ /dev/null
@@ -1,588 +0,0 @@
-
-
-
-
-
-
-
-
-
Overview of the Atlas network | Blockstack
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Overview of the Atlas network
-
-
-
-
-
-
-
-
-
https://zbabystack.netlify.com/core/auth/overview.html
-
-
This document describes the Atlas network, a peer-to-peer content-addressed
-storage system whose chunks’ hashes are announced on a public blockchain. Atlas
-allows users and developers to permanently store chunks of data that are
-replicated across every peer. As long as at least one Atlas peer is online,
-all chunks are available to clients.
-
-
This document is aimed at developers and technical users. The following
-concepts are discussed:
-
-
-
-
The reader of this document is expected to be familiar with the Blockstack
-Naming Service (BNS), as well as Blockstack’s
-storage system Gaia . We advise the reader
-to familiarize themselves with both systems before approaching this document.
-
-
Architecture
-
-
Atlas is designed to integrate with BNS in order to allow users to
-store name state off-chain, encoded as a DNS zone file.
-The overwhelmingly-common use-cases in Blockstack are:
-
-
- Storing a name’s routing information for its owners’ Gaia
-datastores.
- Storing BNS subdomain transactions and associated state.
-
-
-
Atlas is a middleware system in Blockstack. Most developers do not
-interact with it directly. BNS clients like the
-Blockstack Browser
-automatically generate zone files for the names they register, and automatically
-propagate them to the Atlas network. BNS API endpoints, including our
-public endpoint and the
-blockstack.js library,
-will automatically fetch zone files from Atlas when they need to look
-up data in Gaia (such as profiles and app data).
-
-
+--------------+ +---------------+ +----------------+
-clients | Blockstack | | blockstack.js | | BNS API module |
- | Browser | | | | |
- +--------------+ +---------------+ +----------------+
- ^ ^ ^ ^ ^ ^
- | | | | | |
- | | | | | |
- V | V | V |
- +----------+ | +----------+ | +----------+ |
-Gaia | Gaia hub | | | Gaia hub | | | Gaia hub | |
- +----------+ | +----------+ | +----------+ |
- | | |
- | | |
- V V V
- +---------------------------------------------------------------+
-Atlas | Atlas Peer Network |
- +----------+------+----------+-----+----------+------+----------+
-BNS | BNS node | | BNS node | | BNS node | | BNS node |
- +----------+ +----------+ +----------+ +----------+
- ^ ^ ^ ^
- | (indexing | | |
- | blockchain) | | |
- +---------------------------------------------------------------+
-Blockchain | Blockchain Peer Network |
- +---------------------------------------------------------------+
-
-
-Figure 1: Location of Atlas in the Blockstack architecture. Each BNS node
-implements an Atlas peer. An Atlas peer treats a name state value in BNS as
-the hash of a DNS zone file. Atlas peers exchange zone files with one another
-until they each have a full replica of all known zone files. Clients can look
-up zone files for names using the name's stat value as a zone file hash. Clients
-can broadcast zone files to the network if they match a previously-announced
-hash. In practice, zone files store URLs to a name owner's Gaia hubs, thereby
-allowing Blockstack apps to read and write data in Gaia.
-
-
-
-
Nevertheless, Atlas is a general-purpose content-addressed storage
-system that advanced developers can use to host data in an immutable
-and durable manner. Beyond its default use-case in Blockstack,
-Atlas is ideal for tasks like:
-
-
- Announcing PGP public keys under a human-readable name
- Storing package hashes for a software release
- Securely deploying shell scripts to remote VMs
- Binding human-readable names to Tor .onion addresses
-(example )
-
-
-
Motivation
-
-
Atlas was designed to augment BNS. BNS allows each name to store a small
-amount of state—on the order of 20 bytes. The size is so small because the
-state must be recorded to a public blockchain, where the cost per byte is
-high and the blockchain protocol limits the size of transactions.
-
-
To compensate for this, we developed an off-chain storage system allows BNS
-names to bind and store a large amount of state to each name in a way that
-preserves the security properties of having written that state to the
-blockchain . Instead of storing 20 bytes of data on the blockchain, a BNS name
-owner would store the cryptograhpic hash of its state, and then store the actual state
-Atlas. This decouples the name’s state size from the blockchain.
-
-
The reference implementation of Atlas currently allows up to 40kb of state to be
-bound to a BNS name, instead of a measly 20 bytes. The 40kb of data is
-replicated to each BNS node, where it is stored forever.
-
-
Feature Comparison
-
-
Atlas is not the only peer-to-peer content-addressible chunk store in existance. The following
-feature table describes Atlas in relation to other popular chunk stores.
-
-
-
-
- Features
- Atlas
- BitTorrent
- DAT
- IPFS
- Swarm
-
-
-
-
- Each peer stores all chunks
- X
- X
-
-
-
-
-
- Replicas are permanent [1]
- X
- X
- X
-
-
-
-
- Replicas are free
-
- X
- X
- X
-
-
-
- Sybil-resistant chunk discovery
- X
- X
-
-
- X
-
-
- Sybil-resistant peer discovery
- X
-
-
-
-
-
-
- Fixed chunk size
- X
-
- X
- X
- X
-
-
-
-
-
[1] Here, “permanent” means that once a peer has data, they will never evict it
-as part of the protocol.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Related Articles
-
-
-
-
-
-
-
-
-
-
-
-
-
- Name
- E-mail
- Message
- Go!
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Blockstack
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/_site/core/basic_usage.md b/_site/core/basic_usage.md
deleted file mode 100644
index b579a04679..0000000000
--- a/_site/core/basic_usage.md
+++ /dev/null
@@ -1,324 +0,0 @@
-# Basic Usage
-
-This section describes the basic features of Blockstack CLI. This document is meant to supplement the built-in documentation in the tool.
-
-If at any point you forget how to use a particular CLI command, you can just type `blockstack
`, and you will be interactively prompted for each piece of data it needs.
-
-## Client Setup
-
-By default, the CLI tool will automatically configure itself with sensible defaults. If you don't like the defaults, you can change them by running `blockstack configure`.
-
-In particular, you can enable the advanced features with `blockstack set_advanced_mode on`. Please see the `advanced_usage.md` file for details.
-
-## Wallet Setup
-
-Blockstack uses its own wallet, stored to `~/.blockstack/wallet.json`. You do not need a wallet to do lookups.
-
-Blockstack will set up a wallet for you when you try to do something that requires payment (e.g. registering a name). When prompted, you will be asked for a wallet password. This password will be used to encrypt your private keys, and must be at least 16 characters. We recommend using a random string of words that you can easily memorize, since **there is no way to recover your wallet if you forget your password.**
-
-Once you generate a wallet, **make a back-up to a USB key**. You can also print it out, since it's just a string of plain text.
-
-## Doing Lookups
-
-There are two kinds of lookups: a `whois` and a `lookup`. The `whois` queries only information found in the blockchain, whereas a `lookup` queries off-chain data.
-
-A `lookup` fetches the off-chain profile and zonefile. For example:
-
-```
- $ blockstack lookup guylepage3.id
- {
- "profile": {
- "@type": "Person",
- "account": [
- {
- "@type": "Account",
- "identifier": "1Mp5vKwCbekeWetMHLKDD2fDLJzw4vKxiQ",
- "role": "payment",
- "service": "bitcoin"
- },
- {
- "@type": "Account",
- "identifier": "guylepage3",
- "proofType": "http",
- "proofUrl": "https://twitter.com/guylepage3/status/731252874886385665",
- "service": "twitter"
- },
- {
- "@type": "Account",
- "identifier": "g3lepage",
- "proofType": "http",
- "proofUrl": "https://www.facebook.com/g3lepage/posts/10154223148908760",
- "service": "facebook"
- },
- {
- "@type": "Account",
- "identifier": "guylepage3",
- "proofType": "http",
- "proofUrl": "https://gist.github.com/guylepage3/06f522444fb71f1daf01a534396d1f9e",
- "service": "github"
- }
- ],
- "address": {
- "@type": "PostalAddress",
- "addressLocality": "New York, NY"
- },
- "description": "@blockstackorg developer. 1st hire, Design Partner @blockstacklabs (YC/USV backed) entrepreneur, blockchain, creative, marketing, surf, triathlon, ironman",
- "graph": {
- "url": "https://s3.amazonaws.com/grph/guylepage3"
- },
- "image": [
- {
- "@type": "ImageObject",
- "contentUrl": "https://s3.amazonaws.com/dx3/guylepage3",
- "name": "cover"
- },
- {
- "@type": "ImageObject",
- "contentUrl": "https://s3.amazonaws.com/kd4/guylepage3",
- "name": "avatar"
- }
- ],
- "name": "Guy Lepage",
- "website": [
- {
- "@type": "WebSite",
- "url": "http://blockstack.com/team"
- }
- ]
- },
- "zonefile": {
- "$origin": "guylepage3.id",
- "$ttl": 3600,
- "uri": [
- {
- "name": "_http._tcp",
- "priority": 10,
- "target": "https://blockstack.s3.amazonaws.com/guylepage3.id",
- "weight": 1
- }
- ]
- }
- }
-```
-There will always be two keys defined: `profile` and `zonefile`. The hash of the contents of the `zonefile` object are stored in the blockchain, and the Blockstack servers hold copies of zonefile data. The `profile` object is constructed from a **signed JSON web token** (JWT), which is hosted on the storage providers of the user's choice (as determined in the `client.ini` config file). A modern zonefile points to where the profile JWT is hosted.
-
-The `whois` query is more low-level, and pulls up information that's hosted only in the blockchain. Here's a sample `whois` query:
-```
- $ blockstack whois muneeb.id
- {
- "approx_expiration_date": "2016 Sep 09 13:12:31 UTC",
- "block_preordered_at": 373821,
- "block_renewed_at": 373821,
- "expire_block": 426416,
- "has_zonefile": true,
- "last_transaction_height": 402804,
- "last_transaction_id": "904c5f187ab143d187e26afaddaa6061059451407193fbfc4c4a9b0baa24dbd7",
- "owner_address": "1QJQxDas5JhdiXhEbNS14iNjr8auFT96GP",
- "owner_script": "76a914ff95f5612a26a81e919e4b6e63fdd929fd115d6d88ac",
- "zonefile_hash": "3085137b19ce56092f5cb91b7f78d073c815dbc1"
- }
-```
-
-This information includes the block heights at which the name was preordered (for the first time ever), when it was registered to its curent owner, when it will expire, and when the last transaction (whose ID is given) that affected the name was seen. It also encodes the hash of the zonefile (stored off-chain), the owner's address (public key hash), and owner script (scriptPubKey from Bitcoin).
-
-Note that the `approx_expiration_data` is *approxmiate*. The system uses the `expire_block` to determine when exactly the name expires; the date is extrapolated from the average block time. You should renew your name well before it expires, just to be sure the transaction gets accepted. We recommend doing it 1,000 blocks before it is set to expire.
-
-### A Note on Legacy Profiles
-
-Older profiles used a different structure for storing information. Looking them up will produce a "legacy" zonefile, as well as the profile it represents.
-
-Legacy zonefiles do not look like DNS zonefiles at all. For example:
-```
- $ blockstack lookup muneeb.id
- {
- "profile": {
- "@type": "Person",
- "account": [
- {
- "@type": "Account",
- "identifier": "muneeb",
- "proofType": "http",
- "service": "twitter"
- },
- {
- "@type": "Account",
- "identifier": "muneeb.ali",
- "proofType": "http",
- "service": "facebook"
- },
- {
- "@type": "Account",
- "identifier": "muneeb-ali",
- "proofType": "http",
- "service": "github"
- },
- {
- "@type": "Account",
- "identifier": "1LNLCwtigWAvLkNakUK4jnmmvdVvmULeES",
- "role": "payment",
- "service": "bitcoin"
- },
- {
- "@type": "Account",
- "contentUrl": "http://muneebali.com/static/files/key.asc",
- "identifier": "9862A3FB338BE9EB6C6A5E05639C89272AFEC540",
- "role": "key",
- "service": "pgp"
- }
- ],
- "address": {
- "@type": "PostalAddress",
- "addressLocality": "New York, NY"
- },
- "description": "Co-founder of Onename (YC S14), final-year PhD candidate at Princeton. Interested in distributed systems and blockchains.",
- "image": [
- {
- "@type": "ImageObject",
- "contentUrl": "https://s3.amazonaws.com/kd4/muneeb",
- "name": "avatar"
- },
- {
- "@type": "ImageObject",
- "contentUrl": "https://s3.amazonaws.com/dx3/muneeb",
- "name": "cover"
- }
- ],
- "name": "Muneeb Ali",
- "website": [
- {
- "@type": "WebSite",
- "url": "http://muneebali.com"
- }
- ]
- },
- "zonefile": {
- "avatar": {
- "url": "https://s3.amazonaws.com/kd4/muneeb"
- },
- "bio": "Co-founder of Onename (YC S14), final-year PhD candidate at Princeton. Interested in distributed systems and blockchains.",
- "bitcoin": {
- "address": "1LNLCwtigWAvLkNakUK4jnmmvdVvmULeES"
- },
- "cover": {
- "url": "https://s3.amazonaws.com/dx3/muneeb"
- },
- "facebook": {
- "proof": {
- "url": "https://facebook.com/muneeb.ali/posts/10152524743274123"
- },
- "username": "muneeb.ali"
- },
- "github": {
- "proof": {
- "url": "https://gist.github.com/muneeb-ali/0f00d4da967646ee0bc3"
- },
- "username": "muneeb-ali"
- },
- "graph": {
- "followee_count": 4,
- "url": "https://s3.amazonaws.com/grph/muneeb"
- },
- "location": {
- "formatted": "New York, NY"
- },
- "name": {
- "formatted": "Muneeb Ali"
- },
- "pgp": {
- "fingerprint": "9862A3FB338BE9EB6C6A5E05639C89272AFEC540",
- "url": "http://muneebali.com/static/files/key.asc"
- },
- "twitter": {
- "proof": {
- "url": "https://twitter.com/muneeb/status/483765788478689280"
- },
- "username": "muneeb"
- },
- "v": "0.2",
- "website": "http://muneebali.com"
- }
- }
-```
-
-## Blockstack Wallet
-
-The Blockstack wallet has three keys: your payment key, your ownership key (i.e. the key that owns the names), and your data key (i.e. the key that signs your profile data).
-In the basic mode of operation, you can query information about them with these commands:
-
-* `blockstack balance`: Query your payment account balance (excludes transactions with less than 6 confirmations).
-* `blockstack deposit`: Get your payment address information. This is the address that **pays for names and transaction fees**.
-* `blockstack import`: Get your name owner address. This is the address for **transferring a name to a different wallet**.
-* `blockstack names`: See the list of names that are owned by your owner address.
-
-## Registering a Name
-
-To register a name, simply type:
-```
- $ blockstack register .id
-```
-
-At this time, the name must end in `.id`. It will be registered in the `.id` namespace, since only the `.id` namespace exists (see [here](https://blockstack.org/docs/namespaces) for details).
-
-You will be prompted to confirm the purchase, and (if you haven't entered it yet), you will be prompted for your wallet password.
-
-If you'd like to see the price of a name, without actually purchasing it, you can use `blockstack price .id`.
-
-### A Note on Transaction Fees
-The total name cost includes all the relevant transaction fees. However, fee prices are dynamic, and may change during the registration (which requires issuing three transactions).
-
-To ensure timely registration, you should fill your payment address with **at least +0.001 BTC more than the name cost**.
-
-## Migrating an Existing Name to the New Profile Schema
-
-Some advanced options are disabled for older names registered through [Onename](https://onename.com). To enable them, you will need to migrate your name's off-chain data.
-
-To do so, run `blockstack migrate .id`. It will take about an hour and a half to complete, but only needs to be done once, and only if your name has a legacy zonefile (see above).
-
-## Checking the Blockstack Server
-
-You can track the progress of your name transactions with `blockstack info`, which will show you which names have unconfirmed transactions (and what kind they are). The CLI waits for 10 confirmations before considering it confirmed.
-
-When registering a name, a name will pass through three states: `preorder`, `register`, and `update`. The first step registers your public key and the hash of the name, and waits for it to be confirmed (so no one can front-run you when you reveal the name). The second step reveals the name in the blockchain; you can look at the transaction in a block explorer and find it in the `OP_RETURN` data. The third stage sets up your zonefile and your profile, and writes your zonefile's hash to the blockchain.
-
-## Other Operations
-
-### Transferring a Name
-
-You can send a name to a new ownership address with `blockstack transfer .id `.
-
-### Renewing a Name
-
-Names do not last forever, and must be periodically renewed. You can see when a name expires using `whois`, and renew it with `blockstack renew .id`.
-
-**If you do not renew your name, someone else can register it, and you will not be able to get it back.** The best alternative is to try to ask the new owner if (s)he will sell it back to you.
-
-### Revoking a Name
-
-If you lose your Blockstack wallet or the device(s) that host it, you have the option of revoking the name using a backed up copy of your wallet. To do so, type `blockstack revoke .id`.
-
-
-### Updating a Name's Zonefile
-
-**OpenBazaar Users**: If you are trying to add your OpenBazaar GUID to your Blockstack ID, please follow [these instructions](https://github.com/blockstack/blockstack-cli/blob/master/docs/openbazaar.md) instead.
-
-**CAUTION**: You almost never want to update your name's zonefile, since it's slow, tedious, and costs money. It is meant primarily for recovering from zonefile loss, for changing where people find your profile, and for changing your data public key. If you want to store data in your profile, please see the [data storage](https://github.com/blockstack/blockstack-cli/blob/master/docs/advanced_usage.md#data-storage) and [accounts](https://github.com/blockstack/blockstack-cli/blob/master/docs/advanced_usage.md#accounts) commands in the [advanced usage](https://github.com/blockstack/blockstack-cli/blob/master/docs/advanced_usage.md) section (but read the [warnings](https://github.com/blockstack/blockstack-cli/blob/master/docs/advanced_usage.md#a-word-of-warning) first).
-
-If you want to change the name's zonefile, you can do so with `blockstack update`. You must specify the new zonefile to do so. For example:
-
-```
- $ blockstack update judecn.id '$ORIGIN judecn.id
- > $TTL 3600
- > pubkey TXT "pubkey:data:04cabba0b5b9a871dbaa11c044066e281c5feb57243c7d2a452f06a0d708613a46ced59f9f806e601b3353931d1e4a98d7040127f31016311050bedc0d4f1f62ff"
- > _file URI 10 1 "file:///home/jude/.blockstack/storage-disk/mutable/judecn.id"
- > _https._tcp URI 10 1 "https://blockstack.s3.amazonaws.com/judecn.id"
- > _http._tcp URI 10 1 "http://node.blockstack.org:6264/RPC2#judecn.id"
- > _dht._udp URI 10 1 "dht+udp://fc4d9c1481a6349fe99f0e3dd7261d67b23dadc5"
- > '
-```
-
-The zonefile can be any valid DNS zonefile, but must follow these extra rules:
-* There must be only one `$ORIGIN`, and it must be the blockstack ID.
-* There must be at least one `URI` resource record.
-* If you want to set a new data keypair, you must do so via a `TXT` record named `pubkey`, and the text field must start with `pubkey:data:` (as per the example). It must be an ECDSA public key.
-
-**WARNING**: Each of the URLs must refer to the **signed JSON Web Token** (JWT) that encodes your profile data. The JWT can be signed either with the private key that owns your name, or with a private key that matches the `pubkey:data:` TXT record. If you do not do this, your profile **will not be readable** to the Blockstack CLI tool or to any public profile resolvers.
diff --git a/_site/core/cli.md b/_site/core/cli.md
deleted file mode 100644
index 09b7f060c2..0000000000
--- a/_site/core/cli.md
+++ /dev/null
@@ -1,530 +0,0 @@
-# Blockstack CLI
-
-Blockstack CLI is both a command-line interface (CLI) tool, a system service (daemon), and a client (Python library) for interacting with Blockstack. It talks to Blockstack Core and provides an interface for interacting with it.
-
-## Architecture Overview
-
-Most of the complexity of Blockstack lives in its client library. Specifically, the library does the following:
-
-* Generating and sending name operation transactions.
-* Reading, writing, and deleting data in your storage providers (and reading other peoples' data from their storage providers).
-* Handling data authenticity, encryption, and validation.
-* Querying a Blockstack Server for blockchain-hosted information.
-
-The CLI tool is a wrapper around the library. Most of its commands are thin wrappers around library functions.
-
-In addition to a CLI tool and library, Blockstack CLI comes with a system service that runs in the background as a daemon. The daemon does the following:
-
-* Acts as a personal registrar. It queues up all your name operation transactions, waits for them to be confirmed by the blockchain, sends them out, and replicates your zonefile and profile as needed.
-* Hosts your wallet. Your wallet is never stored in plaintext; it only lives in the daemon's RAM (for when it needs to send out transactions).
-* Allows programmatic access to a subset of CLI commands. This allows other programs on your computer to do things like look up Blockstack IDs, query their data, and so on. For security, the daemon will never serve the wallet via the API, nor does it expose any API call that can change data or send transactions (it is effectively a read-only API).
-
-## Files
-
-These files are created by Blockstack CLI:
-
-### Files You Can Edit
-
-These files define how the CLI behaves.
-
-* `~/.blockstack/client.ini`: This is the CLI config file. You can interactively modify it with `blockstack configure`.
-* `~/.blockstack/wallet.json`: This is your JSON-encoded wallet. It contains your password-encrypted keys.
-
-### Files You Can Read
-
-These files are useful primarily for troubleshooting.
-
-* `~/.blockstack/api_endpoint.log`: This is the log for the system service that manages your wallet, sends your name operations, and accesses your profile and data. It's a great source for troubleshooting.
-* `~/.blockstack/api_endpoint.pid`: This contains the PID of the system service.
-* `~/.blockstack/metadata/`: This directory contains versioning information for mutable data from other profiles you have read. It gets used to stop malicious storage providers from serving you older versions of the data you've already seen.
-* `~/.blockstack/storage-disk/`: If you use the `disk` storage driver (it is activated by default), then this is where it holds your zonefiles, profiles, and data.
-
-### Files You Should NOT Edit
-
-You shouldn't touch these files unless you're a developer, and even then, you should only do so at your own risk.
-
-* `~/.blockstack/queues.db`: This is a SQLite database that contains queued-up transactions for name operations. If you want to remove any stuck transactions, use `blockstack unqueue` in the [advanced](https://github.com/blockstack/blockstack-cli/blob/master/docs/advanced_usage.md) usage.
-* `~/.blockstack/registrar.lock`: This is a lockfile held by a thread in the registrar thread in the CLI daemon.
-* `~/.blockstack/blockchain_headers.dat`: SPV headers.
-* `~/.blockstack/client.uuid`: Used for anonymous statistics gathering purposes (which you can disable using `blockstack configure`). If you remove it, a new one will be generated.
-
-## Getting Help
-
-If you ever need help with these instructions or want to learn more, please join the [Blockstack Slack](https://blockstack.slack.com) and drop us a line on the \#cli channel.
-
-## Installation
-
-Installing the command line interface and client library:
-
-### Debian + Ubuntu
-
-Via APT:
-```
-$ curl https://raw.githubusercontent.com/blockstack/packaging/master/repo-key.pub | sudo apt-key add -
-$ sudo sh -c "echo \"deb http://packages.blockstack.com/repositories/ubuntu xenial main\" > /etc/apt/sources.list.d/blockstack.list"
-$ sudo apt-get update
-$ sudo apt-get install blockstack
-```
-
-Via pip:
-```
-$ sudo apt-get update && sudo apt-get install -y python-pip python-dev libssl-dev libffi-dev rng-tools
-$ sudo pip install blockstack --upgrade
-```
-
-### OS X
-
-```bash
-$ brew install libffi openssl
-$ sudo pip install blockstack --upgrade
-```
-
-We recommend installing the CLI inside of a [virtual environment](http://docs.python-guide.org/en/latest/dev/virtualenvs/), in which case you can drop the "sudo" at the beginning like so:
-
-```bash
-$ pip install blockstack --upgrade
-```
-
-If the installation command above fails, see the [troubleshooting section](#troubleshooting-installation).
-
-### Windows Subsystem for Linux
-
-Installation will mirror `Debian + Ubuntu`, above, with an additional package.
-
-```bash
-$ sudo apt-get update && sudo apt-get install -y python-pip python-dev libssl-dev libffi-dev
-```
-
-```bash
-$ sudo pip install functools32
-$ sudo pip install blockstack
-```
-
-## Command-Line Reference
-
-### Listing All Commands
-
-```bash
-$ blockstack
-usage: blockstack [-h]
- ...
-
-Blockstack cli version 0.14.0
-positional arguments:
- balance Get the account balance
- configure Interactively configure the client
- deposit Display the address with which to receive bitcoins
- import Display the address with which to receive names
- info Get details about pending name commands
- lookup Get the zone file and profile for a particular name
- migrate Migrate a profile to the latest profile format
- names Display the names owned by local addresses
- ping Check server status and get server details
- price Get the price of a name
- register Register a name
- renew Renew a name
- revoke Revoke a name
- set_advanced_mode Enable advanced commands
- transfer Transfer a name to a new address
- update Set the zone file for a name
- whois Look up the blockchain info for a name
-
-optional arguments:
- -h, --help show this help message and exit
-```
-
-### Info (or ping or status)
-
-```bash
-$ blockstack info
-```
-
-##### Examples
-
-```bash
-$ blockstack info
-{
- "advanced_mode": false,
- "cli_version": "0.14.0",
- "consensus_hash": "106d4648661d49e16d103b071e26617e",
- "last_block_processed": 420518,
- "last_block_seen": 420596,
- "server_alive": true,
- "server_host": "40.76.8.249",
- "server_port": "6264",
- "server_version": "0.14.0"
-}
-```
-
-### Config
-
-```bash
-$ blockstack configure
-```
-
-##### Examples
-
-```bash
-$ blockstack configure
-# ... interactive prompts ...
-{
- "path": "/home/jude/.blockstack/client.ini"
-}
-```
-
-### Cost
-
-```bash
-$ blockstack price
-```
-
-##### Examples
-
-```bash
-$ blockstack price $(whoami).id
-{
- "name_price": {
- "btc": "0.00025",
- "satoshis": "25000"
- },
- "preorder_tx_fee": {
- "btc": "0.00047406",
- "satoshis": "47406"
- },
- "register_tx_fee": {
- "btc": "0.00046184",
- "satoshis": "46184"
- },
- "total_estimated_cost": {
- "btc": "0.00188394",
- "satoshis": "188394"
- },
- "update_tx_fee": {
- "btc": "0.00069804",
- "satoshis": "69804"
- }
-}
-```
-
-### Whois
-
-```bash
-$ blockstack whois
-```
-
-##### Examples
-
-```bash
-$ blockstack whois fredwilson.id
-{
- "block_preordered_at": 374084,
- "block_renewed_at": 374084,
- "expire_block": 426679,
- "has_zonefile": true,
- "last_transaction_id": "2986ec31ec957692d7f5bc58a3b02d2ac2d1a60039e9163365fc954ff51aeb5a",
- "owner_address": "1F2nHEDLRJ39XxAvSxwQhJsaVzvS5RHDRM",
- "owner_script": "76a91499e7f97f5d2c77b4f32b4ed9ae0f0385c45aa5c788ac",
- "zonefile_hash": "1a587366368aaf8477d5ddcea2557dcbcc67073e"
-}
-```
-
-```bash
-$ blockstack whois $(whoami)_$(date +"%m_%d").id
-Not found.
-```
-
-### Lookup
-
-```bash
-$ blockstack lookup
-```
-
-##### Examples
-
-```bash
-$ blockstack lookup fredwilson.id
-{
- "profile": {
- "avatar": {
- "url": "https://s3.amazonaws.com/kd4/fredwilson1"
- },
- "bio": "I am a VC",
- ...
-}
-
-```
-
-```bash
-$ blockstack lookup $(whoami)_$(date +"%m_%d").id
-Not found.
-```
-
-### Register
-
-```bash
-$ blockstack register
-```
-
-##### Example
-
-```bash
-$ blockstack register $(whoami)_$(date +"%m_%d").id
-Registering muneeb_02_22.id will cost 0.0002225 BTC. Continue? (y/n): y
-{
- "transaction_hash": "f576313b2ff4cc7cb0d25545e1e38e2d0d48a6ef486b7118e5ca0f8e8b98ae45",
- "message": "The name has been queued up for registration and will take a few hours to go through. You can check on the status at any time by running 'blockstack info'."
- "success": true
-}
-```
-
-```bash
-$ blockstack register fredwilson.id
-fredwilson.id is already registered.
-```
-
-### Update
-
-```bash
-$ blockstack update
-```
-
-##### Examples
-
-```bash
-$ echo > new_zone_file.txt <
-```
-
-##### Examples
-
-```bash
-$ blockstack transfer $(whoami)_$(date +"%m_%d").id 1Jbcrh9Lkwm73jXyxramFukViEtktwq8gt
-{
- "transaction_hash": "8a68d52d70cf06d819eb72a9a58f4dceda942db792ceb35dd333f43f55fa8713",
- "message": "The name has been queued up for transfer and will take ~1 hour to process. You can check on the status at any time by running 'blockstack info'."
- "success": true
-}
-```
-
-```bash
-$ blockstack transfer fredwilson.id 1Jbcrh9Lkwm73jXyxramFukViEtktwq8gt
-fredwilson.id is not in your possession.
-```
-
-### Balance
-
-```bash
-$ blockstack balance
-```
-
-##### Examples
-
-```bash
-$ blockstack balance
-{
- "addresses": [
- {
- "address": "16yE3e928JakaXbympwSywyrJPM9cuL4wZ",
- "bitcoin": 0.00959454,
- "satoshis": 959454
- }
- ],
- "total_balance": {
- "bitcoin": 0.00959454,
- "satoshis": 959454
- }
-}
-```
-
-### Names
-
-```bash
-$ blockstack names
-```
-
-##### Examples
-
-```bash
-$ blockstack names
-{
- "addresses": [
- {
- "address": "16CtpS8LhmW3bGtVC69UGZ3wSwvi95BE8E",
- "names_owned": [
- "testregistration001.id",
- "testregistration002.id"
- ]
- }
- ],
- "names_owned": [
- "testregistration001.id",
- "testregistration002.id"
- ]
-}
-```
-
-### Deposit
-
-```bash
-$ blockstack deposit
-```
-
-##### Examples
-
-```bash
-$ blockstack deposit
-{
- "address": "1EHgqHVpA1tjn6RhaVj8bx6y5NGvBwoMNS",
- "message": "Send bitcoins to the address specified.",
-}
-```
-
-### Import
-
-```bash
-$ blockstack import
-```
-
-##### Examples
-
-```bash
-$ blockstack import
-{
- "address": "1Jbcrh9Lkwm73jXyxramFukViEtktwq8gt"
- "message": "Send the name you want to receive to the address specified.",
-}
-```
-
-## Troubleshooting Installation
-
-**a) Error installing pycrypto**
-
-If you see the following error, while pycrpyto installs on OS X:
-
-```bash
-error: command 'cc' failed with exit status 1
-```
-
-Try installing it with the following:
-
-```bash
-$ ARCHFLAGS=-Wno-error=unused-command-line-argument-hard-error-in-future pip install pycrypto
-```
-
-**b) Blockstack hangs while running in a VM**
-
-If Blockstack hangs while performing one of the above operations while running in a VM, and you hit Ctrl+C, you
-may see a stack trace like this:
-
-```
-Traceback (most recent call last):
- File "/home/dev/blockstack-venv/bin/blockstack", line 67, in
- result = run_cli()
- File "/home/dev/blockstack-venv/local/lib/python2.7/site-packages/blockstack_client/cli.py", line 287, in run_cli
- result = method( args, config_path=config_path )
- File "/home/dev/blockstack-venv/local/lib/python2.7/site-packages/blockstack_client/actions.py", line 479, in cli_price
- fees = get_total_registration_fees( fqu, payment_privkey_info, owner_privkey_info, proxy=proxy, config_path=config_path, payment_address=payment_address )
- File "/home/dev/blockstack-venv/local/lib/python2.7/site-packages/blockstack_client/actions.py", line 271, in get_total_registration_fees
- preorder_tx_fee = estimate_preorder_tx_fee( name, data['satoshis'], payment_address, utxo_client, owner_privkey_params=get_privkey_info_params(owner_privkey_info), config_path=config_path, include_dust=True )
- File "/home/dev/blockstack-venv/local/lib/python2.7/site-packages/blockstack_client/backend/nameops.py", line 116, in estimate_preorder_tx_fee
- fake_privkey = make_fake_privkey_info( owner_privkey_params )
- File "/home/dev/blockstack-venv/local/lib/python2.7/site-packages/blockstack_client/backend/nameops.py", line 103, in make_fake_privkey_info
- return virtualchain.make_multisig_wallet( m, n )
- File "/home/dev/blockstack-venv/local/lib/python2.7/site-packages/virtualchain/lib/blockchain/bitcoin_blockchain/multisig.py", line 82, in make_multisig_wallet
- pk = BitcoinPrivateKey().to_wif()
- File "/home/dev/blockstack-venv/local/lib/python2.7/site-packages/pybitcoin/privatekey.py", line 55, in __init__
- secret_exponent = random_secret_exponent(self._curve.order)
- File "/home/dev/blockstack-venv/local/lib/python2.7/site-packages/pybitcoin/privatekey.py", line 32, in random_secret_exponent
- random_hex = hexlify(dev_random_entropy(32))
- File "/home/dev/blockstack-venv/local/lib/python2.7/site-packages/utilitybelt/entropy.py", line 38, in dev_random_entropy
- return open("/dev/random", "rb").read(numbytes)
-KeyboardInterrupt
-```
-
-If so, the reason is because the VM does not have enough entropy. This causes reads to `/dev/random` to block
-for a long time.
-
-The solution is to install `rng-tools` and configure it to seed `/dev/random` with entropy from `/dev/urandom`.
-Please see your distribution documentation for setting up `rng-tools`.
-
-If the issue you are experiencing is not listed here, please
-[report it as a new issue](https://github.com/blockstack/blockstack-client/issues/new).
-
-## Running Your Server
-
-The CLI by default talks to a remote server, but you can easily start your own server.
-
-Open a new terminal window and run the following command:
-
-```bash
-$ blockstack-server start --foreground
-```
-
-You can now switch the cli to use the local server:
-
-```bash
-$ blockstack configure
-...
-server (default: 'node.blockstack.org'): 127.0.0.1
-...
-```
-
-[More information on the Blockstack Server(http://github.com/blockstack/blockstack-server)
-
-## Client Library
-
-You can also import the blockstack client and write your own programs.
-
-Here is some example code to get you started:
-
-```python
-from blockstack_client import client
-from blockstack_client.utils import print_result as pprint
-
-client.session(server_host='127.0.0.1', server_port=6264)
-resp = client.ping()
-pprint(resp)
-```
diff --git a/_site/core/faq_technical.md b/_site/core/faq_technical.md
deleted file mode 100644
index f1f1c30f97..0000000000
--- a/_site/core/faq_technical.md
+++ /dev/null
@@ -1,385 +0,0 @@
-# Blockstack Technical FAQ
-
-This document lists frequently-asked questions and answers to technical
-questions about Blockstack.
-
-If you are new to Blockstack, you should read the
-[non-technical FAQ](https://blockstack.org/faq) first.
-
-If you have a technical question that gets frequently asked on the
-[forum](https://forum.blockstack.org) or [Slack](https://blockstack.slack.com),
-feel free to send a pull-request with the question and answer.
-
-# General Questions
-
-## What is Blockstack?
-
-Blockstack is a new Internet for decentralized applications. Blockstack
-applications differ from Web applications in two ways:
-
-* **Users own their identities**. The user brings their identity to the
- applications; applications do not require the user to create accounts and
-passwords.
-* **Users own their data**. Users control who can read it, and where it gets stored.
- The application does not need to worry about hosting any user data.
-
-The Blockstack project provides all of the infrastructure required for building
-these kinds of applications.
-
-## Is Blockstack decentralized?
-
-Yes! The components that make up Blockstack do not have any central points of
-control.
-
-* The [Blockstack Naming Service](blockstack_naming_service.md) runs on top of
- the Bitcoin blockchain, which itself is decentralized. It binds Blockstack
-IDs to a small amount of on-chain data (usually a hash of off-chain data).
-* The [Atlas Peer Network](atlas_network.md) stores chunks of data referenced by
-names in BNS. It operates under similar design principles to BitTorrent, and
-has no single points of failure. The network is self-healing---if a node
-crashes, it quickly recovers all of its state from its peers.
-* The [Gaia storage system](https://github.com/blockstack/gaia) lets users
- choose where their application data gets hosted. Gaia reduces all storage
-systems---from cloud storage to peer-to-peer networks---to dumb, interchangeable
-hard drives. Users have maximum flexibility and control over their data in a
-way that is transparent to app developers.
-
-## Are Blockstack applications usable today?
-
-Yes! Blockstack applications are as easy to use as normal Web applications, if
-not easier. Moreover, they are just as performant if not more so.
-
-If you install the [Blockstack
-Browser](https://github.com/blockstack/blockstack-browser), or use our
-[Web-hosted Blockstack Browser](https://browser.blockstack.org), you can get
-started with them right away.
-
-## Where does Blockstack keep my user account?
-
-Your user account is ultimately controlled by a [private
-key](https://en.wikipedia.org/wiki/Public-key_cryptography). You and only you
-know what the private key is, and using your private key, you can prove to other
-people that you own a particular piece of data (such as your Blockstack ID).
-
-Your private key resides within your locally-running Blockstack Browser.
-It never leaves your computer.
-
-Your public keys are stored off-chain, and the *hash* of your public key is
-stored on the Bitcoin blockchain. The [Blockstack Naming
-Service](blockstack_naming_service.md) allows anyone to look up your public key
-hash, given your Blockstack ID.
-
-## Where does Blockstack keep my app data?
-
-As a Blockstack user, you can choose exactly where your data gets stored.
-Blockstack uses a decentralized storage system called
-[Gaia](https://github.com/blockstack/gaia) to host your data. Gaia is different
-from other storage systems because it lets you securely host your data wherever you want---in cloud
-storage providers, on your personal server, or in another decentralized storage
-system like BitTorrent or IPFS.
-
-When you register, you are given a default Gaia hub that replicates your
-data to a bucket in Microsoft Azure. However, you can configure and
-deploy your own Gaia hub and have Blockstack store your data there instead.
-
-The [Blockstack Naming Service](blockstack_naming_service.md) and the [Atlas
-network](atlas_network.md) work together to help other users discover your
-app-specific public data, given your Blockstack ID.
-
-# Blockstack IDs
-
-## What is a Blockstack ID?
-
-Blockstack IDs are usernames. Unlike normal Web app usernames, Blockstack IDs
-are usable *across every Blockstack app.* They fill a similar role to
-centralized single-signon services like Facebook or Google. However, you and
-only you control your Blockstack ID, and no one can track your logins.
-
-## How do I get a Blockstack ID?
-
-If you install the [Blockstack
-Browser](https://github.com/blockstack/blockstack-browser) or use the
-[Web-hosted Blockstack Browser](https://browser.blockstack.org), you can
-purchase one with Bitcoin.
-
-## Do I need a Blockstack ID to use Blockstack apps?
-
-No, you can use Blockstack applications right away. However, if you want to
-*share data with other users*, then you need a Blockstack ID.
-
-## Why do I need a Blockstack ID?
-
-Blockstack IDs are used to discover where you are keeping your
-(publicly-readable) application data. For example, if `alice.id` wants to share
-a document with `bob.id`, then `bob.id`'s browser uses the Blockstack ID
-`alice.id` to look up where `alice.id` stored it.
-
-The technical descriptions of how and why this works are quite long.
-Please see the [Blockstack Naming Service](blockstack_naming_service.md)
-documentation for a full description.
-
-## What is a Blockstack Subdomain?
-
-This is also a Blockstack ID, and can be used for all the things a Blockstack ID
-can be used for. The only difference is that they have the format `foo.bar.baz`
-instead of `bar.baz`. For example,
-[jude.personal.id](https://core.blockstack.org/v1/users/jude.personal.id) is a
-Blockstack ID, and is a subdomain of `personal.id`.
-
-Subdomains are first-class Blockstack IDs---they can be used for all the same
-things that an on-chain Blockstack ID can be used for, and they have all of
-the same safety properties. They are globally unique, they are strongly owned
-by a private key, and they are human-readable.
-
-Subdomains are considerably cheaper than Blockstack IDs, since hundreds of them
-can be registered with a single transaction. The [BNS
-documentation](blockstack_naming_service.md) describes them in detail.
-
-Subdomains provide a fast, inexpensive way to onboard many users at once.
-
-## Can I get a Blockstack ID without spending Bitcoin?
-
-Blockstack subdomains can be obtained without spending Bitcoin
-by asking a subdomain registrar to create one for you.
-
-## Is there a Blockstack name explorer?
-
-Yes! It's at https://explorer.blockstack.org
-
-# Blockstack App Development
-
-## I'm a Web developer. Can I build on Blockstack?
-
-Yes! Blockstack is geared primarily towards Web developers. All of your
-existing knowledge is immediately applicable to Blockstack. Anything you can do
-in a Web browser, you can do in a Blockstack app.
-
-## I'm a non-Web developer. Can I build on Blockstack?
-
-Yes! Blockstack implements a [RESTful API](https://core.blockstack.org) which
-lets you interact with Blockstack from any language and any runtime. In fact,
-the reference client
-([blockstack.js](https://github.com/blockstack/blockstack.js)) is mainly a
-wrapper around these RESTful API calls, so you won't be missing much by using a
-language other than Javascript.
-
-## What's the difference between a Web app and a Blockstack app?
-
-Blockstack apps are built like [single-page Web
-apps](https://en.wikipedia.org/wiki/Single-page_application)---they are, in
-fact, a type of Web application.
-
-Blockstack apps are a subset of Web applications that use Blockstack's
-technology to preserve the user's control over their identities and data.
-As such, they tend to be simpler
-in design and operation, since in many cases they don't have to host anything
-besides the application's assets.
-
-## Do I need to learn any new languages or frameworks?
-
-No. Blockstack applications are built using existing Web frameworks and programming
-The only new thing you need to learn is either [blockstack.js](https://github.com/blockstack/blockstack.js) or
-the [Blockstack RESTful API](https://core.blockstack.org).
-
-## How does my Web app interact with Blockstack?
-
-The [blockstack.js](https://github.com/blockstack/blockstack.js) library gives
-any Web application the ability to interact with Blockstack's authentication and
-storage services. In addition, we supply a [public RESTful API](https://core.blockstack.org).
-
-## What does `blockstack.js` do?
-
-This is the reference client implementation for Blockstack. You use it in your
-Web app to do the following:
-
-* Authenticate users
-* Load and store user data
-* Read other users' public data
-
-## How do I use `blockstack.js`?
-
-Please see the API documentation [here](https://github.com/blockstack/blockstack.js).
-
-## How can I look up names and profiles?
-
-You can use `blockstack.js`, or you can use the [public Blockstack Core
-endpoint](https://core.blockstack.org).
-
-## How can I read my public app data without `blockstack.js`?
-
-The URLs to a user's public app data are in a canonical location in their
-profile. For example, here's how you would get public data from the
-[Publik](https://publik.ykliao.com) app, stored under the Blockstack ID `ryan.id`.
-
-1. Get the bucket URL
-```bash
-$ BUCKET_URL="$(curl -sL https://core.blockstack.org/v1/users/ryan.id | jq -r '."ryan.id"["profile"]["apps"]["http://publik.ykliao.com"]')"
-$ echo "$BUCKET_URL"
-https://gaia.blockstack.org/hub/1FrZTGQ8DM9TMPfGXtXMUvt2NNebLiSzad/
-```
-
-2. Get the data
-```bash
-$ curl -sL "${BUCKET_URL%%/}/statuses.json"
-[{"id":0,"text":"Hello, Blockstack!","created_at":1515786983492}]
-```
-
-## How do I register Blockstack IDs?
-
-You should use the [Blockstack Browser](https://github.com/blockstack/blockstack-browser).
-
-## How do I register Blockstack Subdomains?
-
-You can deploy and use a [Blockstack Subdomain Registrar](subdomains.md), or
-use an existing one.
-
-## Can I programmatically register Blockstack IDs?
-
-Blockstack applications do not currently have
-have access to the user's wallet. Users are expected to
-register Blockstack IDs themselves.
-
-However, if you feel particularly ambitious, you can do one of the following:
-
-* Set up a `blockstack api` endpoint (see the project [README](../README.md)) and write a
- program to automatically register names. Also, see the [API
-documentation](https://blockstack.github.io/blockstack-core/#managing-names-register-a-name)
-for registering names on this endpoint.
-
-* Write a `node.js` program that uses `blockstack.js` to register
- names. This is currently in development.
-
-## Can I programmatically register Blockstack Subdomains?
-
-Yes! Once you deploy your own subdomain registrar, you can have your Web app
-send it requests to register subdomains on your Blockstack ID. You can also
-create a program that drives subdomain registration on your Blockstack ID.
-
-## Do you have a testnet or sandbox to experiment with Blockstack?
-
-We have an [integration test framework](../integration_tests) that provides a
-private Blockstack testnet. It uses `bitcoin -regtest` to create a private
-blockchain that you can interact with, without having to spend any Bitcoin or
-having to wait for blocks to confirm. Please see the
-[README](../integration_tests/README.md) for details.
-
-## Does Blockstack have a smart contract system?
-
-No, not yet. This is because
-Blockstack's design philosophy focuses on keeping system complexity at the
-"edges" of the network (e.g. clients), instead of the "core" of the network (e.g.
-the blockchain), in accordance with the [end-to-end
-principle](https://en.wikipedia.org/wiki/End-to-end_principle).
-Generally speaking, this can be interpreted as "if you can do X without
-a smart contract, you should do X without a smart contract." This organizing
-principle applies to a lot of useful decentralized applications.
-
-## Can Blockstack applications interact with Bitcoin? Ethereum? Smart contracts? Other blockchains?
-
-Yes! Since Blockstack applications are built like Web applications, all you need to do is include the
-relevant Javascript library into your application.
-
-## Do you have a Blockstack app development tutorial?
-
-Yes! See [here](https://blockstack.org/tutorials).
-
-# Comparisons to Other Systems
-
-## Blockstack vs DNS
-
-Blockstack and DNS both implement naming systems, but in fundamentally
-different ways. Blockstack *can be used* for resolving host names to IP
-addresses, but this is not its default use-case. The [Blockstack Naming
-Service](blockstack_naming_service.md) (BNS) instead behaves
-more like a decentralized
-[LDAP](https://en.wikipedia.org/wiki/Lightweight_Directory_Access_Protocol) system for
-resolving user names to user data.
-
-While DNS and BNS handle different problems, they share some terminology and
-serialization formats. However, it is important to recognize that this is the
-*only* thing they have in common---BNS has fundamentally different semantics
-than DNS:
-
-* **Zone files**: Blockstack stores a DNS zone file for each name. However,
-the semantics of a BNS zone file are nothing like the semantics of a DNS zone
-file---the only thing they have in common is their format.
-A "standard" Blockstack zone files only have `URI` and `TXT` resource records
-that point to the user's application data. Moreover, a Blockstack ID has a
-*history* of zone files, and historic zone files can alter the way in which a
-Blockstack ID gets resolved (DNS has no such concept). It is conceivable that an advanced
-user could add `A` and `AAAA` records to their Blockstack ID's zone file,
-but these are not honored by any Blockstack software at this time.
-
-* **Subdomains**: Blockstack has the concept of a subdomain, but it is
- semantically very different from a DNS subdomain. In Blockstack, a subdomain
-is a Blockstack ID whose state and transaction history are anchored to the
-blockchain, but stored within an on-chain Blockstack ID's zone file history.
-Unlike DNS subdomains, a BNS subdomain has
-its own owner and is a first-class BNS name---all subdomains are resolvable,
-and only the subdomain's owner can update the subdomain's records. The only thing BNS subdomains and DNS
-subdomains have in common is the name format (e.g. `foo.bar.baz` is a subdomain
-of `bar.baz` in both DNS and BNS).
-
-More details can be found in the [Blockstack vs
-DNS](https://blockstack.org/docs/blockstack-vs-dns) document. A feature
-comparison can be found at the end of the [Blockstack Naming
-Service](blockstack_naming_service.md) document.
-
-## Blockstack vs Namecoin
-
-Namecoin also implements a decentralized naming service on top of a blockchain,
-just like BNS. In fact, early versions of Blockstack were built on Namecoin.
-However, [it was discovered](https://www.usenix.org/node/196209) that Namecoin's
-merged mining with Bitcoin regularly placed it under the *de facto* control of a single
-miner. This prompted a re-architecting of the system to be *portable* across
-blockchains, so that if Blockstack's underlying blockchain (currently Bitcoin)
-ever became insecure, the system could migrate to a more secure blockchain.
-
-A feature comparison can be found at the end of the [Blockstack Naming
-Service](blockstack_naming_service.md) document.
-
-## Blockstack vs ENS
-
-ENS also implements a decentralized naming system on top of a blockchain, but as
-a smart contract on Ethereum. Like BNS, ENS is geared towards resolving names
-to off-chain state (ENS names resolve to a hash, for example). Moreover, ENS is
-geared towards providing programmatic control over names with Turing-complete
-on-chain resolvers.
-
-BNS has a fundamentally different relationship with blockchains than ENS.
-WHereas ENS tries to use on-chain logic as much as possible, BNS
-tries to use the blockchain as little as possible. BNS only uses it to store a
-database log for name operations (which are interpreted with an off-chain BNS
-node like Blockstack Core). BNS name state and BNS subdomains reside entirely
-off-chain in the Atlas network. This has allowed BNS to migrate from blockchain
-to blockchain in order to survive individual blockchain failures, and this has
-allowed BNS developers to upgrade its consensus rules without having to get the
-blockchain's permission (see the [virtualchain
-paper](https://blockstack.org/virtualchain_dccl2016.pdf) for details).
-
-A feature comparison can be found at the end of the [Blockstack Naming
-Service](blockstack_naming_service.md) document.
-
-## Blockstack vs Ethereum
-
-Blockstack and Ethereum both strive to provide a decentralized application
-platform. Blockstack's design philosophy differs from Ethereum's design
-philosophy in that Blockstack emphasizes treating the blockchain as a "dumb
-ledger" with no special functionality or properties beyond a few bare minimum
-requirements. Instead, it strives to do everything off-chain---an application of the [end-to-end principle](https://en.wikipedia.org/wiki/End-to-end_principle).
-Most Blockstack applications do *not*
-interact with the blockchain, and instead interact with Blockstack
-infrastructure through client libraries and RESTful endpoints.
-This is evidenced by Blockstack's decision to implement its naming system (BNS), discovery and routing system
-(Atlas), and storage system (Gaia) as blockchain-agnostic components that can be
-ported from one blockchain to another.
-
-Ethereum takes the opposite approach. Ethereum dapps are expected to interface
-directly with on-chain smart contract logic, and are expected to host a
-non-trivial amount of state in the blockchain itself. This is necessary for
-them, because many Ethereum dapps' business logic is centered around the
-mechanics of an ERC20 token.
-
-Blockstack does not implement a smart contract system (yet), but it will soon
-implement a [native token](https://blockstack.com/distribution.pdf) that will be
-accessible to Blockstack applications.
diff --git a/_site/core/figures/test-screen.png b/_site/core/figures/test-screen.png
deleted file mode 100644
index c47fc26b65..0000000000
Binary files a/_site/core/figures/test-screen.png and /dev/null differ
diff --git a/_site/core/gaia.md b/_site/core/gaia.md
deleted file mode 100644
index 0060549c62..0000000000
--- a/_site/core/gaia.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# Gaia Documentation
-
-This document has moved to the [Gaia repository](https://github.com/blockstack/gaia)
diff --git a/_site/core/glossary.md b/_site/core/glossary.md
deleted file mode 100644
index c710ca277e..0000000000
--- a/_site/core/glossary.md
+++ /dev/null
@@ -1,148 +0,0 @@
-# Glossary
-
-Commonly used terms and jargon in Blockstack
-
-## Account
-
-A field in a profile that links the name to an existing service, like Twitter or OpenBazaar. They are listed under the `accounts` listing in a profile.
-
-Some accounts serve as social proofs, but they can contain any data the user wants.
-
-## Atlas
-
-A peer-to-peer network maintained by Blockstack Core nodes that stores each
-name's zone files and immutable data. See [this document](atlas_network.md) for
-details.
-
-## Blockstack ID
-
-(Also called a "name").
-
-A human-readable name in Blockstack. It is comprised only of upper and lower-case ASCII characters, numbers, as well as `-`, `_`, and `.`. It must end with a `.`, followed by a namespace ID. It has at least 3 characters, and at most 37 (including the `.` and the namespace ID).
-
-Anyone can register a Blockstack ID, such as through the [Blockstack Browser](https://github.com/blockstack/blockstack-browser)
-
-## Blockstack Core
-
-A server that reads a blockchain with [virtualchain](https://github.com/blockstack/blockstack-virtualchain), filters out transactions that represent name operations, and builds up a database of (name, public key, state value) triples.
-
-## Blockstack Naming Service (BNS)
-
-This is the naming protocol that Blockstack Core implements. See [this
-document](blockstack_naming_service.md) for details.
-
-## Consensus Hash
-
-A cryptographic hash that represents a proof-of-computation by a Blockstack Core node. Two Blockstack Core nodes have seen and processed the same name operations up to block `n` if and only if they each calculate the same consensus hash at height `n`.
-
-A Blockstack Core node only accepts a name operation if it has a previously-calculated but recent consensus hash. Blockstack clients obtain a consensus hash from a Blockstack Core node in order to construct a name operation.
-
-## Gaia
-
-This is Blockstack's storage system. Gaia hosts all of your app-specific data.
-
-## Gaia Hub
-
-This is a publicly-routable server that serves as an entry point for Gaia data.
-Anyone can stand up and run a Gaia hub by following [these
-instructions](https://github.com/blockstack/gaia).
-Blockstack provides a [default Gaia hub](https://gaia.blockstack.org).
-
-## Immutable Data
-
-This is the general term for chunks of data whose hash is cryptographically
-bound to a blockchain transaction. This includes all data stored in the Atlas
-network (such as your Blockstack ID's zone file),
-as well as any data whose hash is stored in the Atlas network.
-
-## Mutable Data
-
-This is the general term for data that is (1) signed by your Blockstack ID, and
-(2) can be looked up using your Blockstack ID. This includes all your Gaia
-data, as well as your profile.
-
-## Name
-
-See Blockstack ID.
-
-## Name Database
-
-The set of (name, public key, name state) triples that the Blockstack Core node generates by reading the blockchain. The name state is usually the hash of a DNS zone file stored in Atlas.
-
-## Name Operation
-
-A specially-crafted transaction in the underlying blockchain that, when processed, will change each Blockstack Core's name database. Examples include `NAME_PREORDER` (preorders a name), `NAME_REGISTRATION` (registers a name), `NAME_UPDATE` (changes a name's zonefile hash), `NAME_TRANSFER` (changes a name's public key), and `NAME_REVOKE` (locks everyone out of a name until it expires).
-
-Name operations are encoded on Bitcoin as `OP_RETURN` outputs that start with `id`, followed by a 1-byte character that identifies the particular operation.
-
-See the [wire format](wire-format.md) document for details.
-
-## Namespace
-
-Analogous to a DNS TLD, it represents a grouping of names. All names under the same namespace have the same pricing and lifetime rules.
-
-Anyone can create a namespace, but doing so is expensive by design. See the
-[namespace creation](namespace_creation.md) tutorial for details.
-
-## Preorder
-
-The first of two steps to acquire a name. This operation writes the hash of both the name and the address that will own it.
-
-## Profile
-
-A signed JSON web token that describes a [Person](https://schema.org/Person), which describes the name's owner. You can put anything you want into your profile.
-
-Additionally, profiles hold lists of social verifications and pointers to your Gaia data.
-
-## Register
-
-(1) The act of acquiring a name in Blockstack.
-
-(2) The second of two steps to create a new name entry in the name database. Reveals the name as plaintext to the world. Must match a recent preorder to be accepted.
-
-## Registrar
-
-An online service that lets you sign up for and manage the profiles of Blockstack IDs.
-
-## Resolver
-
-An online service that displays zonefile and profile data for a Blockstack ID. [The Blockstack Explorer](https://explorer.blockstack.org) is a resolver.
-
-## Social proof
-
-A post in an account on an existing Web service like Twitter, Facebook, or GitHub that points back to a Blockstack ID. Used to provide some evidence that the person who owns the Blockstack ID is also the person who owns the Web service account.
-
-Social proofs are listed in your profile.
-
-## Storage Provider
-
-This is any service that can serve your zone file, profile, or data. In all cases, the data is signed by one of your wallet's keys, so you can use any provider without having to worry about it trying to change the data.
-
-Storage providers are accessed through a Gaia hub. Gaia hubs ship with drivers
-that allow them to treat storage providers as dumb hard drives, which store
-signed encrypted data on the hub's behalf.
-
-Not all storage providers support writes--some of them are read-only.
-
-Supported storage providers today include:
-* Amazon S3
-* Dropbox
-* Your harddrive
-* Any HTTP/HTTPS/FTP server (read-only)
-* Any public-use Gaia hub
-* IPFS
-
-Support is being added for:
-* Google Drive
-* Microsoft OneDrive
-* Box.com
-* BitTorrent
-
-If you have a preferred storage provider, and you're a developer, please consider sending us a pull request to add support for it!
-
-## Zone file
-
-A specially-formatted file that stores routing information for a Blockstack ID.
-Blockstack clients use your zone file to find out where your preferred Gaia
-hub(s) are. Ever Blockstack Core node stores a copy of every zone file for
-every Blockstack ID by participating in the Atlas network.
diff --git a/_site/core/identity/openbazaar.md b/_site/core/identity/openbazaar.md
deleted file mode 100644
index 9859401344..0000000000
--- a/_site/core/identity/openbazaar.md
+++ /dev/null
@@ -1,64 +0,0 @@
-# Linking your OpenBazaar GUID to your Blockstack ID
-
-If you don't have the Blockstack CLI. Download and install it first. Instructions are [here](https://github.com/blockstack/blockstack-cli/blob/master/README.md). The rest of this tutorial assumes that you've already registered a name using the Blockstack CLI.
-
-## Step 1: Advanced Mode
-
-The first step is to activate "advanced mode" in the CLI. The command to do so is:
-
-```
- $ blockstack set_advanced_mode on
-```
-
-## Step 2: Add an OpenBazaar Account
-
-The second step is to create an OpenBazaar account for your profile (the [Onename](https://onename.com) app also enabled to link your OpenBazaar GUID). The command to do so is:
-
-```
- $ blockstack put_account "" "openbazaar" "" ""
-```
-
-The URL can be any valid URL; it won't be used by OpenBazaar. Here's an example, using the name `testregistration001.id` and the GUID `0123456789abcdef`:
-
-```
- $ blockstack put_account "testregistration001.id" "openbazaar" "0123456789abcdef" "https://bazaarbay.org/@testregistration001"
-```
-
-The update should be instantaneous. You can verify that your store is present with `list_accounts`:
-
-```
- $ blockstack list_accounts "testregistration001.id"
- {
- "accounts": [
- {
- "contentUrl": "https://bazaarbay.org/@testregistration001.id",
- "identifier": "0123456789abcdef",
- "service": "openbazaar"
- }
- ]
- }
-````
-
-# Troubleshooting
-
-Common problems you might encounter.
-
-## Profile is in legacy format
-
-If you registered your blockstack ID before spring 2016, there's a chance that your profile is still in a legacy format. It will get migrated to the new format automatically if you update your profile on the [Onename](https://onename.com) app. However, you have to do this manually with the CLI.
-
-To do so, the command is:
-```
- $ blockstack migrate
-```
-
-It will take a little over an hour to complete, but once finished, you'll be able to manage your accounts with the above commands (and do so with no delays).
-
-## Failed to broadcast update transaction
-
-This can happen during a `migrate` for one of a few reasons:
-* You do not have enough balance to pay the transaction fee (which is calculated dynamically).
-* Your payment address has unconfirmed transactions.
-* You can't connect to a Bitcoin node.
-
-To determine what's going on, you should try the command again by typing `BLOCKSTACK_DEBUG=1 blockstack ...` instead of `blockstack...`.
diff --git a/_site/core/install-api.md b/_site/core/install-api.md
deleted file mode 100644
index 932bc110c7..0000000000
--- a/_site/core/install-api.md
+++ /dev/null
@@ -1,80 +0,0 @@
-# Blockstack API
-
-Step-by-step instructions for deploying a Blockstack API node on Debian or
-Ubuntu are below.
-
-- **Step 1:** Make sure you have Blockstack Core running locally (see [instructions](https://github.com/blockstack/blockstack-core/blob/master/README.md#quick-start)).
-
-- **Step 2:** Make sure you have [virtualenv installed](http://docs.python-guide.org/en/latest/dev/virtualenvs/).
-Then, setup the API:
-```
-$ sudo apt-get install -y python-pip memcached rng-tools python-dev libmemcached-dev zlib1g-dev libgmp-dev libffi-dev libssl-dev
-$ sudo service memcached start
-$ sudo pip install virtualenv
-$ sudo npm -g install aglio
-$ virtualenv api && source api/bin/activate
-$ git clone https://github.com/blockstack/blockstack-core.git
-$ cd blockstack-core/
-$ pip install .
-$ pip install -r api/requirements.txt
-$ blockstack setup_wallet
-$ blockstack api start
-$ deactivate
-$ ./build_docs.sh public_api
-```
-
-### Search Subsystem
-
-If you want to enable the search subsystem in your installation, you can
-follow the instructions [here](search.md).
-
-### Nginx Deployment
-
-For a production deployment we recommend using nginx and uwsgi:
-
-- **Step 1:** Install nginx and uWSGI:
-```
-$ sudo apt-get install -y nginx
-$ sudo pip install uwsgi
-```
-- **Step 2:** Copy [this sample nginx sites file](../api/nginx/config/nginx_sites-available/blockstack_api) to
-
-> /etc/nginx/sites-available/blockstack_api
-
-and edit the paths depending on the uwsgi blockstack_api socket directory (defaults to /tmp/blockstack_api.sock)
-You can test your nginx settings:
-```
-$ sudo nginx -t
-```
-- **Step 3:** Copy [this sample systemd service file](../api/nginx/config/systemd_system/blockstack_api.service) to
-
-> /etc/systemd/system/blockstack_api.service
-
-and edit the service user and blockstack paths depending on where your blockstack repo is located, and
-where your virtualenv is located.
-
-Note: The following sed commands will work if the virtualenv is currently active and your shell is in the repo's root directory.
-
-```
-$ sudo sed -i "s/User\=USER/User\=$USER/" /etc/systemd/system/blockstack_api.service
-$ sudo sed -i "s#/path/to/blockstack#$PWD#" /etc/systemd/system/blockstack_api.service
-$ sudo sed -i "s#/path/to/virtualenv#$VIRTUAL_ENV#" /etc/systemd/system/blockstack_api.service
-```
-
-- **Step 4:** Get a security certificate from [Let's Encrypt](https://letsencrypt.org/).
-```
-$ git clone https://github.com/certbot/certbot.git
-$ cd certbot/
-$ ./certbot-auto --nginx -d
-```
-
-And copy the cert files to the path given in the nginx sites file earlier.
-
-- **Step 5:** Start nginx and the Blockstack API uwsgi server:
-```
-sudo systemctl restart blockstack_api
-sudo systemctl restart nginx
-```
-
-If you run into any issues, please [submit a Github issue](https://github.com/blockstack/blockstack-core/issues) and we'll update these
-instructions.
diff --git a/_site/core/interactive_regtest_macos.md b/_site/core/interactive_regtest_macos.md
deleted file mode 100644
index cc4a535965..0000000000
--- a/_site/core/interactive_regtest_macos.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Documentation for setting up the regtest mode for Blockstack Browser
-using core's integration tests in macOS and Linux has
-moved [here](../integration_tests).
diff --git a/_site/core/memcached.md b/_site/core/memcached.md
deleted file mode 100644
index aedd01e151..0000000000
--- a/_site/core/memcached.md
+++ /dev/null
@@ -1,42 +0,0 @@
-Installing Memcached
-=======
-
-The Blockstack API optionally uses memcached and pylibmc for scaling read-only
-calls. If you want to enable this functionality then you should have memcached
-running locally.
-
-### Memcached on Debian & Ubuntu:
-
-```
-$ sudo apt-get install -y python-dev libmemcached-dev zlib1g-dev
-$ pip install pylibmc
-```
-
-### Memcached on macOS:
-
-Easiest way to install memcached on macOS is by using [Homebrew](https://brew.sh/).
-
-After installing Homebrew:
-
-```
-$ brew install memcached
-$ brew install libmemcached
-$ pip install pylibmc --install-option="--with-libmemcached=/usr/local/Cellar/libmemcached/1.0.18_1/"
-```
-
-After installing, you can start memcached and check if it's running properly:
-
-```
-$ memcached -d
-$ echo stats | nc localhost 11211
-```
-
-### Memcached on Heroku
-
-To deploy on Heroku:
-
-```bash
-$ heroku create
-$ heroku addons:add memcachedcloud
-$ git push heroku master
-```
diff --git a/_site/core/naming/architecture.html b/_site/core/naming/architecture.html
deleted file mode 100644
index 43f1dde5af..0000000000
--- a/_site/core/naming/architecture.html
+++ /dev/null
@@ -1,547 +0,0 @@
-
-
-
-
-
-
-
-
-Understand the Architecture | Blockstack
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Understand the Architecture
-
-
-
-
-
-
-
-
The BNS node is the heart of the system. It is responsible for building up
-and replicating global name state.
-
-
There are three parts to BNS that developers should be aware of. They are:
-
-
-
- The BNS indexer . This module crawls the blockchain and builds
-up its name database. BNS indexers do not contain any private or sensitive
-state, and can be deployed publicly. We maintain a fleet of them at
-https://node.blockstack.org:6263 for developers to use to get started.
-
-
- The BNS API . This module gives
-developers a stable RESTful API for interacting with the BNS network.
-We provide one for developers to experiment with at https://core.blockstack.org.
-
-
- BNS clients . These communicate with the BNS API module in order to
-resolve names. Internally, they generate and send transactions to register
-and modify names.
-
-
-
-
The BNS indexer and BNS API comprise the BNS node . An architectural schematic appears below.
-
-
+-------------------------------------------------------+
- RESTful | +----------------+ +--------------------+ |
-+--------+ API | | | private API | | |
-| client |<------------>| BNS API module |<----------->| BNS indexer module | |
-+--------+ | | | | | |
- | | +----------------+ | +----------------+ | |
- | | | | name database | | |
- | | | +----------------+ | |
- | | +--------------------+ |
- | | BNS node ^ |
- | +------------------------------------------|------------+
- | |
- | v
- | blockchain transactions +--------------------+
- +------------------------------------------------->| blockchain peer |
- +--------------------+
-
-Figure 1: BNS architecture overview. Clients talk to the BNS API module to
-resolve names, and generate and send blockchain transactions to register and
-modify names. The API module talks to the indexer module and gives clients
-a stable, Web-accessible interface for resolving names. The indexer module reads
-the blochchain via a blockchain peer, over the blockchain's peer network.
-
-Blockstack Core currently implements the API module and indexer module as separate
-daemons (`blockstack api` and `blockstack-core`, respectively). However, this
-is an implementation detail, and may change in the future.
-
-
-
-
The BNS indexer implements the blockchain consensus rules and network protocols.
-Its main responsibility is to build up and replicate all of the name state. It does
-not have any public APIs of its own.
-
-
The BNS API modules allows users and developers to resolve names via a RESTful
-interface. Resolution can be done with vanilla curl or wget.
-BNS applications should use the BNS API module for name resolution.
-They should not attempt to talk to a BNS indexer directly, because its API is not stable and is not meant
-for consumption by any other process except for the API module.
-
-
Registering and managing names require generating and sending blockchain
-transactions, which requires running a BNS client. We provide two reference
-BNS clients:
-
-
- The Blockstack Browser gives users
-and developers a graphical UI to resolve, register and manage names. This is the recommended
-way to interact with BNS.
- The Blockstack CLI gives developers low-level
-control over resolving, registering, and managing names.
-A new CLI that uses blockstack.js
-is under development, and will replace the existing CLI program.
-
-
-
We recommend that new developers use the Blockstack
-Browser .
-
-
Developers who want to make their own client programs that do not use
-the reference client library code should read the
-BNS transaction wire format document for generating and
-sending their own transactions.
-
-
The examples in this document focus on resolving names using curl. We refer
-the reader to client-specific documentation for registering and managing names.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Related Articles
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Blockstack
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/_site/core/naming/comparison.html b/_site/core/naming/comparison.html
deleted file mode 100644
index b9ab7b06b6..0000000000
--- a/_site/core/naming/comparison.html
+++ /dev/null
@@ -1,596 +0,0 @@
-
-
-
-
-
-
-
-
-
Naming system feature comparison | Blockstack
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Naming system feature comparison
-
-
-
-
-
-
-
-
BNS is not the only naming system in wide-spread use, nor is it the only
-decentralized naming system that implements human-readable,
-globally-unique, and strongly-owned names. The following feature table
-describes how BNS differs from other naming systems
-
-
-
-
- Feature
- BNS
- ENS
- DNS
- Namecoin
-
-
-
-
- Globally unique names
- X
- X
- X
- X
-
-
- Human-readable names
- X
- X
- X
- X
-
-
- Strongly-owned names
- X
- X
-
- X
-
-
- Names are enumerable
- X
-
-
- X
-
-
- Registration times
- 1-2 hours
- ~1 week
- ~1 day
- 1-2 hours
-
-
- Subdomain registration times
- 1 hour (instant with #750 )
- varies
- instant
- ~1 hour
-
-
- Anyone can make a TLD/namespace
- X
- [1]
-
- [1]
-
-
- TLD/Namespace owners get registration fees
- X
-
- X
-
-
-
- TLD/Namespace can be seeded with initial names
- X
-
- X
-
-
-
- Portable across blockchains
- X
-
- N/A
-
-
-
- Off-chain names
- X
-
- N/A
-
-
-
- Off-chain name state
- X
- X
- N/A
-
-
-
- Name provenance
- X
- X
-
- X
-
-
- DID support
- X
-
-
-
-
-
- Turing-complete namespace rules
-
- X
- X
-
-
-
- Miners are rewarded for participating
- [1]
-
- N/A
- X
-
-
-
-
-
[1] Requires support in higher-level applications. These systems are not aware
-of the existence of namespaces/TLDs at the protocol level.
-
-
[2] Blockstack Core destroys the underlying blockchain token to pay for
-registration fees when there is no pay-to-namespace-creator address set in the
-name’s namespace. This has the effect of making the blockchain miners’ holdings
-slightly more valuable.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Related Articles
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Blockstack
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/_site/core/naming/did.html b/_site/core/naming/did.html
deleted file mode 100644
index 0ebefd65f8..0000000000
--- a/_site/core/naming/did.html
+++ /dev/null
@@ -1,500 +0,0 @@
-
-
-
-
-
-
-
-
-
DID Encoding for Subdomains | Blockstack
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- DID Encoding for Subdomains
-
-
-
-
-
-
-
-
Every name and subdomain in BNS has a DID. The encoding is slightly different
-for subdomains, so the software can determine which code-path to take.
-
-
-
- For on-chain BNS names, the { address } is the same as the Bitcoin address
-that owns the name. Currently, both version byte 0 and version byte 5
-addresses are supported (i.e. addresses starting with 1 or 3, meaning p2pkh and
-p2sh addresses).
-
-
- For off-chain BNS subdomains, the { address } has version byte 63 for
-subdomains owned by a single private key, and version byte 50 for subdomains
-owned by a m-of-n set of private keys. That is, subdomain DID addresses start
-with S or M, respectively.
-
-
-
-
The { index } field for a subdomain’s DID is distinct from the { index } field
-for a BNS name’s DID, even if the same created both names and subdomains.
-For example, the name abcdefgh123456.id has the DID did:stack:v0:16EMaNw3pkn3v6f2BgnSSs53zAKH4Q8YJg-0,
-because it was the first name created by 16EMaNw3pkn3v6f2BgnSSs53zAKH4Q8YJg.
-However, 16EMaNw3pkn3v6f2BgnSSs53zAKH4Q8YJg also created jude.statism.id
-as its first subdomain name. The DID for jude.statism.id is
-did:stack:v0:SSXMcDiCZ7yFSQSUj7mWzmDcdwYhq97p2i-0. Note that the address
-SSXMcDiCZ7yFSQSUj7mWzmDcdwYhq97p2i encodes the same public key hash as the address
-16EMaNw3pkn3v6f2BgnSSs53zAKH4Q8YJg (the only difference between these two
-strings is that the first is base58check-encoded with version byte 0, and the
-second is encoded with version byte 63).
-
-
You can see this play out in practice with the following code snippit:
-
-
>>> import blockstack
->>> blockstack . lib . client . get_name_record ( 'jude.statism.id' , hostport = 'https://node.blockstack.org:6263' )[ 'address' ]
-u'16EMaNw3pkn3v6f2BgnSSs53zAKH4Q8YJg'
->>> import virtualchain
->>> virtualchain . address_reencode ( '16EMaNw3pkn3v6f2BgnSSs53zAKH4Q8YJg' , version_byte = 63 )
-'SSXMcDiCZ7yFSQSUj7mWzmDcdwYhq97p2i'
->>> blockstack . lib . client . resolve_DID ( 'did:stack:v0:SSXMcDiCZ7yFSQSUj7mWzmDcdwYhq97p2i-0' , hostport = 'https://node.blockstack.org:6263' )
-{ 'public_key' : '020fadbbcea0ff3b05f03195b41cd991d7a0af8bd38559943aec99cbdaf0b22cc8' }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Related Articles
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Blockstack
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/_site/core/naming/forks.html b/_site/core/naming/forks.html
deleted file mode 100644
index 27db1eff2f..0000000000
--- a/_site/core/naming/forks.html
+++ /dev/null
@@ -1,589 +0,0 @@
-
-
-
-
-
-
-
-
-
BNS Forks | Blockstack
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- BNS Forks
-
-
-
-
-
-
-
-
BNS effectively uses a public blockchain to store a database log. A BNS peer
-bootstraps itself by downloading and replaying the database log from the
-blockchain, and in doing so, will calculate the same name database state as
-every other (honest) BNS peer that has the same view of the blockchain.
-
-
Crucially, BNS is built on top of a public blockchain that is unaware of BNS’s existence.
-This means that the blockchain peers do not validate BNS transactions. Instead,
-the BNS peer needs to do so, and must know how to reject both invalid transactions
-as well as well-formed transactions from dishonest peers (i.e. peers that do not
-follow the same consensus rules).
-
-
BNS nodes do not directly communicate with one another—by design, the set of
-BNS peers is not enumerable. The only shared communication medium between BNS
-peers is the blockchain.
-
-
To identify and reject invalid and malicious transactions without the blockchain’s help,
-the log of name operations embedded in the blockchain is constructed as a
-fork*-consistent database
-log. Fork*-consistency is a consistency
-model whereby the state
-replicas in all of the nodes exhibit the following properties:
-
-
-
- Each correct peer maintains a history of well-formed, valid state operations. In this
-case, each correct BNS node maintains a copy of the history blockchain transactions
-that encoded well-formed, valid name operations.
-
-
- Each honest peer’s history contains the sequence of all operations that it
-sent. That is, a user’s BNS peer’s transaction log will contain the sequence of all valid
-transactions that the user’s client wrote to the blockchain.
-
-
- If two peers accept operations op and op’ from the same correct client,
-then both of their logs will have the both operations in the same order. If
-op’ was accepted before op , then both peers’ logs are identical up to op’ .
-In BNS, this means that if two peers both accept a given transaction, then it
-means that they have accepted the same sequence of prior transactions.
-
-
-
-
This means that unlike with blockchains,
-there can be multiple long-lived conflicting forks of the BNS database log.
-However, due to fork*-consistency, a correct BNS peer will only process one
-of these forks, and will ignore transactions from peers in other forks. In other words,
-fork*-consistency partitions the set of BNS peers into different fork-sets ,
-where all peers in a fork-set process each other’s transactions, but the
-completely ignore peers in other fork-sets.
-
-
BNS nodes identify which fork set they belong to using a consensus hash . The
-consensus hash is a cryptographic digest of a node’s operation
-history. Each BNS peer calculates a new consensus hash each time it processes a
-new block, and stores the history of consensus hashes for each block it
-processed.
-
-
Two honest BNS peers can quickly determine if they are in the same fork-set by querying
-each other’s consensus hashes for a given block. If they match, then they are
-in the same fork-set (assming no hash collisions).
-
-
A BNS client executes a name operation on a specific fork-set by including a
-recent consensus hash from that fork-set in the blockchain transaction.
-At the same time, the BNS consensus rules state that a transaction can only be
-accepted if it included a recent valid consensus hash.
-This means that all BNS nodes in the client’s desired fork-set will accept
-the transaction, and all other BNS nodes not in the fork-set will ignore it.
-You can see where the consensus hash is included in blockchain transactions by reading
-the transaction wire format document.
-
-
Fork-set Selection
-
-
The blockchain linearizes the history of transactions, which means that
-in general, there exists a fork-set for each distinct set of BNS
-consensus rules. For example, the Blockstack Core 2016 hard fork
-and 2017 hard fork both introduced new consensus
-rules, which means at the time of this writing there are three possible fork-sets:
-the pre-2016 fork-set, the 2016-2017 fork-set, and the post-2017 fork-set.
-The public BNS nodes are always running
-in the fork-set with the latest consensus rules.
-
-
BNS clients are incentivized to communicate with peers in the fork-set that has
-the most use, since this fork-set’s name database will encode name/state
-bindings that are the most widely-accepted and understood by users.
-To identify this fork-set, a BNS client needs to learn one of
-its recent consensus hashes. Once it has a recent consensus hash, it can
-query an untrusted BNS node for a copy of
-its name database, and use the consensus hash to verify that the name database
-was used to generate it.
-
-
How does a BNS node determine whether or not a consensus hash corresponds to the
-most widely-used fork-set? There are two strategies:
-
-
-
- Determine whether or not a characteristic transaction was accepted by the
-widely-used fork-set. If a client knows that a specific transaction belongs to
-the widely-used fork-set and not others, then they can use the consensus hash to
-efficiently determine whether or not a given node belongs to this fork-set.
-
-
- Determine how much “economic activity” exists in a fork-set by inspecting
-the blockchain for burned cryptocurrency tokens. Namespace and name
-registrations are structured in a way that sends cryptocurrency tokens to either
-a well-known burn address, or to an easily-queried pay-to-namespace-creator
-address.
-
-
-
-
Both strategies rely on the fact that the consensus hash is calculated as a
-Merkle skip-list
-over the BNS node’s accepted transactions. A client can use a consensus hash to
-determine whether or not a transaction T was accepted by a node with O(log
-n) time and space complexity. We call the protocol for resolving a consensus hash to a specific transaction
-Simplified Name Verification (SNV). See our paper on the subject
-for details of how SNV works under the hood.
-
-
If the client has a consensus hash and knows of a characteristic transaction in the widely-used fork-set,
-it can use SNV to determine whether or not a node belongs to the fork-set that accepted it.
-
-
If the client knows about multiple conflicting consensus hashes,
-they can still use SNV to determine which one corresponds
-to the most-used fork-set. To do so, the client would use a
-blockchain explorer to find the
-list of transactions that burned cryptocurrency tokens. Each of these
-transactions will be treated as potential characteristic transactions:
-the client would first select the subset of transactions that are well-formed
-BNS transactions, and then use SNV to determine which of them correspond to which
-consensus hashes. The client chooses the consensus hash that corresponds
-to the fork-set with the highest cumulative burn.
-
-
Work is currently underway to automate this process.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Related Articles
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Blockstack
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/_site/core/naming/introduction.html b/_site/core/naming/introduction.html
deleted file mode 100644
index 70ed470cc1..0000000000
--- a/_site/core/naming/introduction.html
+++ /dev/null
@@ -1,1961 +0,0 @@
-
-
-
-
-
-
-
-
-
Blockstack Naming Service (BNS) | Blockstack
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Blockstack Naming Service (BNS)
-
-
-
-
-
-
-
-
This document gives an overview of how the Blockstack Naming Service work. This
-document explains the following concepts:
-
-
- Why a secure decentralized naming service is an important building
-block in decentralized systems
- How Blockstack applications can leverage BNS to solve real-world problems
- How the Blockstack Naming Service is different from other offerings in this
-space.
-
-
-
The (Blockstack Core )
-repository is the reference implementation of the Blockstack Naming Service.
-
-
Introduction
-
-
The Blockstack Naming Service (BNS) is a network system that binds names
-to off-chain state without relying on any central points of control.
-It does so by embedding a log of its control-plane messages within a public blockchain, like Bitcoin.
-
-
Each BNS peer determines the state of each name by indexing these specially-crafted
-transactions. In doing so, each peer independently calculates the same global
-name state.
-
-
Names in BNS have three properties:
-
-
- Names are globally unique. The protocol does not allow name collisions, and all
-well-behaved nodes resolve a given name to the same state.
- Names are human-meaningful. Each name is chosen by its creator.
- Names are strongly-owned. Only the name’s owner can change the state it
-resolves to. Specifically, a name is owned by one or more ECDSA private keys.
-
-
-
Internally, a BNS node implements a replicated name database. Each BNS node keeps itself
-synchronized to all of the other ones in the world, so queries on one BNS node
-will be the same on other nodes. BNS nodes allow a name’s owner to bind
-up to 40Kb of off-chain state to their name, which will be replicated to all
-BNS nodes via the Atlas network .
-
-
BNS nodes extract the name database log from an underlying blockchain (Blockstack
-Core currently uses Bitcoin, and had used Namecoin in the past).
-BNS uses the blockchain to establish a shared “ground truth” for the system: as long as
-two nodes have the same view of the blockchain, then they will build up the same
-database.
-
-
The biggest consequence for developers is that in BNS, reading name state is
-fast and cheap but writing name state is slow and expensive. This is because
-registering and modifying names requires one or more transactions to be sent to
-the underlying blockchain, and BNS nodes will not process them until they are
-sufficiently confirmed. Users and developers need to acquire and spend
-the requisite cryptocurrency (i.e. Bitcoin) to send BNS transactions.
-
-
Motivation
-
-
We rely on naming systems in everyday life, and they play a critical
-role in many different applications. For example, when you look up a
-friend on social media, you are using the platform’s naming service to resolve
-their name to their profile. When you look up a website, you are using the
-Domain Name Service to
-resolve the hostname to its host’s IP address. When you check out a Git branch, you
-are using your Git client to resolve the branch name to a commit hash.
-When you look up someone’s PGP key on a keyserver, you are resolving
-their key ID to their public key.
-
-
What kinds of things do we want to be true about names? In BNS, names are
-globally unique, names are human-meaningful, and names are strongly-owned.
-However, if you look at these examples, you’ll see that each of them only
-guarantees two of these properties. This limits how useful they can be.
-
-
- In DNS and social media, names are globally unique and human-readable, but not
-strongly-owned. The system operator has the
-final say as to what each names resolves to.
-
- Problem : Clients must trust the system to make the right
-choice in what a given name resolves to. This includes trusting that
-no one but the system administrators can make these changes.
-
-
- In Git, branch names are human-meaningful
-and strongly-owned, but not globally unique. Two different Git nodes may resolve the same
-branch name to different unrelated repository states.
-
- Problem : Since names can refer to conflicting state, developers
-have to figure out some other mechanism to resolve ambiguities. In Git’s
-case, the user has to manually intervene.
-
-
- In PGP, names are key IDs. They are
-are globally unique and cryptographically owned, but not human-readable. PGP
-key IDs are derived from the keys they reference.
-
- Problem : These names are difficult for most users to
-remember since they do not carry semantic information relating to their use in the system.
-
-
-
-
-
BNS names have all three properties, and none of these problems. This makes it a
-powerful tool for building all kinds of network applications. With BNS, we
-can do the following and more:
-
-
- Build domain name services where hostnames can’t be hijacked.
- Build social media platforms where user names can’t be stolen by phishers.
- Build version control systems where repository branches do not conflict.
- Build public-key infrastructure where it’s easy for users to discover and
-remember each other’s keys.
-
-
-
How to Use BNS
-
-
BNS names are organized into a global name hierarchy. There are three different
-layers in this hierarchy related to naming:
-
-
-
- Namespaces . These are the top-level names in the hierarchy. An analogy
-to BNS namespaces are DNS top-level domains. Existing BNS namespaces include
-.id, .podcast, and .helloworld. All other names belong to exactly one
-namespace. Anyone can create a namespace, but in order for the namespace
-to be persisted, it must be launched so that anyone can register names in it.
-Namespaces are not owned by their creators.
-
-
- BNS names . These are names whose records are stored directly on the
-blockchain. The ownership and state of these names are controlled by sending
-blockchain transactions. Example names include verified.podcast and
-muneeb.id. Anyone can create a BNS name, as long as the namespace that
-contains it exists already. The state for BNS names is usually stored in the Atlas
-network .
-
-
- BNS subdomains . These are names whose records are stored off-chain,
-but are collectively anchored to the blockchain. The ownership and state for
-these names lives within the Atlas network . While BNS
-subdomains are owned by separate private keys, a BNS name owner must
-broadcast their subdomain state. Example subdomains include jude.personal.id
-and podsaveamerica.verified.podcast. Unlike BNS namespaces and names, the
-state of BNS subdomains is not part of the blockchain consensus rules.
-
-
-
-
A feature comparison matrix summarizing the similarities and differences
-between these name objects is presented below:
-
-
-
-
- Feature
- Namespaces
- BNS names
- BNS Subdomains
-
-
-
-
- Globally unique
- X
- X
- X
-
-
- Human-meaningful
- X
- X
- X
-
-
- Owned by a private key
-
- X
- X
-
-
- Anyone can create
- X
- X
- [1]
-
-
- Owner can update
-
- X
- [1]
-
-
- State hosted on-chain
- X
- X
-
-
-
- State hosted off-chain
-
- X
- X
-
-
- Behavior controlled by consensus rules
- X
- X
-
-
-
- May have an expiration date
-
- X
-
-
-
-
-
-
[1] Requires the cooperation of a BNS name owner to broadcast its transactions
-
-
Creating a Namespace
-
-
There are four steps to creating a namespace:
-
-
-
- Send a NAMESPACE_PREORDER transaction (live example ).
-This is the first step. This registers the salted hash of the namespace with BNS nodes, and burns the
-requisite amount of cryptocurrency. In addition, it proves to the
-BNS nodes that user has honored the BNS consensus rules by including
-a recent consensus hash in the transaction
-(see the section on BNS forks for details).
-
-
- Send a NAMESPACE_REVEAL transaction (live example ).
-This is the second step. This reveals the salt and the namespace ID (pairing it with its
-NAMESPACE_PREORDER), it reveals how long names last in this namespace before
-they expire or must be renewed, and it sets a price function for the namespace
-that determines how cheap or expensive names its will be. The price function takes
-a name in this namespace as input, and outputs the amount of cryptocurrency the
-name will cost (i.e. by examining how long the name is, and whether or not it
-has any vowels or non-alphabet characters). The namespace creator
-has the option to collect name registration fees for the first year of the
-namespace’s existence by setting a namespace creator address .
-
-
- Seed the namespace with NAME_IMPORT transactions (live example ).
-Once the namespace has been revealed, the user has the option to populate it with a set of
-names. Each imported name is given both an owner and some off-chain state.
-This step is optional—namespace creators are not required to import names.
-
-
- Send a NAMESPACE_READY transaction (live example ).
-This is the final step of the process. It launches the namespace, which makes it available to the
-public. Once a namespace is ready, anyone can register a name in it if they
-pay the appropriate amount of cryptocurrency (according to the price funtion
-revealed in step 2).
-
-
-
-
The reason for the NAMESPACE_PREORDER/NAMESPACE_REVEAL pairing is to prevent
-frontrunning. The BNS consensus rules require a NAMESPACE_REVEAL to be
-paired with a previous NAMESPACE_PREORDER sent within the past 24 hours.
-If it did not do this, then a malicious actor could watch the blockchain network
-and race a victim to claim a namespace.
-
-
Namespaces are created on a first-come first-serve basis. If two people try to
-create the same namespace, the one that successfully confirms both the
-NAMESPACE_PREORDER and NAMESPACE_REVEAL wins. The fee burned in the
-NAMESPACE_PREORDER is spent either way.
-
-
Once the user issues the NAMESPACE_PREORDER and NAMESPACE_REVEAL, they have
-1 year before they must send the NAMESPACE_READY transaction. If they do not
-do this, then the namespace they created disappears (along with all the names
-they imported).
-
-
Developers wanting to create their own namespaces should read the namespace
-creation document. It is highly recommended that
-developers follow this tutorial closely, given the large amount of
-cryptocurrency at stake.
-
-
Using Namespaces
-
-
The intention is that each application can create its own BNS
-namespace for its own purposes. Applications can use namespaces for things like:
-
-
- Giving users a SSO system, where each user registers their public key under a
-username. Blockstack applications do this with names in the .id namespace,
-for example.
- Providing a subscription service, where each name is a 3rd party that provides
-a service for users to subscribe to. For example, names in
-.podcast point to podcasts that users of the
-DotPodcast app can subscribe to.
- Implementing software licenses, where each name corresponds to an access key.
-Unlike conventional access keys, access keys implemented as names
-can be sold and traded independently. The licensing fee (paid as a name
-registration) would be set by the developer and sent to a developer-controlled
-blockchain address.
-
-
-
Names within a namespace can serve any purpose the developer wants. The ability
-to collect registration fees for 1 year after creating the namespace not only
-gives developers the incentive to get users to participate in the app, but also
-gives them a way to measure economic activity.
-
-
Developers can query individual namespaces and look up names within them using
-the BNS API. The API offers routes to do the following:
-
-
List all namespaces in existence (reference ).
-
-
$ curl https://core.blockstack.org/v1/namespaces
-[
- "id" ,
- "helloworld" ,
- "podcast"
-]
-
-
-
-
List all names within a namespace (reference )
-
-
$ curl https://core.blockstack.org/v1/namespaces/id/names?page= 0
-[
- "0.id" ,
- "0000.id" ,
- "000000.id" ,
- "000001.id" ,
- "00000111111.id" ,
- "000002.id" ,
- "000007.id" ,
- "0011sro.id" ,
- "007_007.id" ,
- "00n3w5.id" ,
- "00r4zr.id" ,
- "00w1k1.id" ,
- "0101010.id" ,
- "01jack.id" ,
- "06nenglish.id" ,
- "08.id" ,
- "0cool_f.id" ,
- "0dadj1an.id" ,
- "0nelove.id" ,
- "0nename.id"
-...
-]
-
-
-
-
Each page returns a batch of 100 names.
-
-
Get the Cost to Register a Namespace (reference )
-
-
$ curl https://core.blockstack.org/v1/prices/namespaces/test
-{
- "satoshis" : 40000000
-}
-
-
-
-
If you want to register a namespace, please see the namespace creation tutorial .
-
-
Getting the Current Consensus Hash (reference )
-
-
$ curl -sL https://core.blockstack.org/v1/blockchains/bitcoin/consensus
-{
- "consensus_hash" : "98adf31989bd937576aa190cc9f5fa3a"
-}
-
-
-
-
A recent consensus hash is required to create a NAMESPACE_PREORDER transaction. The reference
-BNS clients do this automatically. See the transaction format
-document for details on how the consensus hash is used to construct the
-transaction.
-
-
Resolving BNS Names
-
-
BNS names are bound to both public keys and to about 40Kb of off-chain state.
-The off-chain state is encoded as a DNS zone file ,
-which contains routing information for discovering the user’s Blockstack data
-(such as their profile and app data, which are hosted in the Gaia storage
-system ).
-
-
The blockchain is not used to store this information directly. Instead, the
-blockchain stores the public key hash and the zone file hash . When
-indexing the blockchain, each BNS node builds a database with
-three columns: all the on-chain BNS names that have been registered, each
-name’s public key hash, and each name’s zone file’s hash.
-In addition, each BNS node maintains the transaction history of each name.
-A developer can resolve a name to any configuration it was in at any prior
-point in time.
-
-
Below is an example name table pulled from a live BNS node:
-
-
-
-
- Name
- Public key hash
- Zone File Hash
-
-
-
-
- ryan.id
- 15BcxePn59Y6mYD2fRLCLCaaHScefqW2No
- a455954b3e38685e487efa41480beeb315f4ec65
-
-
- muneeb.id
- 1J3PUxY5uDShUnHRrMyU6yKtoHEUPhKULs
- 37aecf837c6ae9bdc9dbd98a268f263dacd00361
-
-
- jude.id
- 16EMaNw3pkn3v6f2BgnSSs53zAKH4Q8YJg
- b6e99200125e70d634b17fe61ce55b09881bfafd
-
-
- verified.podcast
- 1MwPD6dH4fE3gQ9mCov81L1DEQWT7E85qH
- 6701ce856620d4f2f57cd23b166089759ef6eabd
-
-
- cicero.res_publica.id
- 1EtE77Aa5AA8etzF2irk56vvkS4v7rZ7PE
- 7e4ac75f9d79ba9d5d284fac19617497433b832d
-
-
- podsaveamerica.verified.podcast
- 1MwPD6dH4fE3gQ9mCov81L1DEQWT7E85qH
- 0d6f090db8945aa0e60759f9c866b17645893a95
-
-
-
-
-
In practice, the zone file hash is the RIPEMD160 hash of the SHA256 hash of
-the zone file, and the public key is the base58check-encoded RIPEMD160 hash
-of the double-SHA256 hash of the ECDSA public key (i.e. a Bitcoin address).
-
-
The BNS consensus rules ensure that
-a BNS name can only be registered if it is not already taken, and that only the
-user who owns the name’s private key can change its public key hash or zone file
-hash. This means that a name’s public key and zone file can be stored anywhere,
-since they can be authenticated using the hashes discovered by indexing the
-blockchain under the BNS consensus rules.
-
-
BNS nodes implement a decentralized storage system for zone files called the
-Atlas network . In this system, BNS nodes eagerly replicate
-all the zone files they know about to one another, so that eventually every BNS
-node has a full replica of all zone files.
-
-
The public keys for names are stored off-chain in Gaia .
-The user controls where their public keys are hosted using the zone file
-contents (if they are hosted online anywhere at all).
-
-
Developers can query this table via the BNS API. The API offers routes
-to do the following:
-
-
Look up a name’s public key and zone file (reference )
-
-
$ curl https://core.blockstack.org/v1/names/muneeb.id
-{
- "address" : "1J3PUxY5uDShUnHRrMyU6yKtoHEUPhKULs" ,
- "blockchain" : "bitcoin" ,
- "expire_block" : 599266,
- "last_txid" : "7e16e8688ca0413a398bbaf16ad4b10d3c9439555fc140f58e5ab4e50793c476" ,
- "status" : "registered" ,
- "zonefile" : " $ORIGIN muneeb.id \n $TTL 3600 \n _http._tcp URI 10 1 \" https://gaia.blockstack.org/hub/1J3PUxY5uDShUnHRrMyU6yKtoHEUPhKULs/0/profile.json \"\n " ,
- "zonefile_hash" : "37aecf837c6ae9bdc9dbd98a268f263dacd00361"
-}
-
-
-
-
Note that the zonefile field is given with the off-chain data that hashes
-to the zonefile_hash field.
-
-
List all names the node knows about (reference )
-
-
$ curl https://core.blockstack.org/v1/names?page= 0
-[
- "judecn.id" ,
- "3.id" ,
- "4.id" ,
- "8.id" ,
- "e.id" ,
- "h.id" ,
- "5.id" ,
- "9.id" ,
- "i.id" ,
- "l.id" ,
- "p.id" ,
- "w.id" ,
- "ba.id" ,
- "df.id" ,
-...
-]
-
-
-
-
Each page returns 100 names. While no specific ordering is mandated by the
-protocol, the reference implementation orders names by their order of creation
-in the blockchain.
-
-
Look up the history of states a name was in (reference )
-
-
$ curl https://core.blockstack.org/v1/names/patrickstanley.id/history
-{
- "445838" : [
- {
- "address" : "1occgbip7tFDXX9MvzQhcnTUUjcVX2dYK" ,
- "block_number" : 445838,
- "burn_address" : "1111111111111111111114oLvT2" ,
- "consensus_hash" : "7b696b6f4060b792d41912068944d73b" ,
- "op" : "?" ,
- "op_fee" : 25000,
- "opcode" : "NAME_PREORDER" ,
- "preorder_hash" : "26bf7874706ac761afdd403ed6b3b9578fb01a34" ,
- "sender" : "76a91408d0dd44c1f0a3a4f0957ae95901929d7d66d55788ac" ,
- "sender_pubkey" : "039a8948d339ecbff44cf426cb85d90fce876f1658d385cdc47f007f279be626ea" ,
- "txid" : "6730ae09574d5935ffabe3dd63a9341ea54fafae62fde36c27738e9ee9c4e889" ,
- "vtxindex" : 40
- }
- ] ,
- "445851" : [
- {
- "address" : "17CbHgTgBG3kLedXNneEKBkCTgW2fyrnUD" ,
- "block_number" : 445838,
- "consensus_hash" : null,
- "first_registered" : 445851,
- "importer" : null,
- "importer_address" : null,
- "last_creation_op" : "?" ,
- "last_renewed" : 445851,
- "name" : "patrickstanley.id" ,
- "name_hash128" : "683a3e1ee5f0296833c56e481cf41b77" ,
- "namespace_block_number" : 373601,
- "namespace_id" : "id" ,
- "op" : ":" ,
- "op_fee" : 25000,
- "opcode" : "NAME_REGISTRATION" ,
- "preorder_block_number" : 445838,
- "preorder_hash" : "26bf7874706ac761afdd403ed6b3b9578fb01a34" ,
- "revoked" : false ,
- "sender" : "76a9144401f3be5311585ea519c1cb471a8dc7b02fd6ee88ac" ,
- "sender_pubkey" : "039a8948d339ecbff44cf426cb85d90fce876f1658d385cdc47f007f279be626ea" ,
- "transfer_send_block_id" : null,
- "txid" : "55b8b42fc3e3d23cbc0f07d38edae6a451dfc512b770fd7903725f9e465b2925" ,
- "value_hash" : null,
- "vtxindex" : 54
- }
- ] ,
- "445873" : [
- {
- "address" : "17CbHgTgBG3kLedXNneEKBkCTgW2fyrnUD" ,
- "block_number" : 445838,
- "consensus_hash" : "18b8d69f0182b89ccb1aa536f83be18a" ,
- "first_registered" : 445851,
- "importer" : null,
- "importer_address" : null,
- "last_creation_op" : "?" ,
- "last_renewed" : 445851,
- "name" : "patrickstanley.id" ,
- "name_hash128" : "683a3e1ee5f0296833c56e481cf41b77" ,
- "namespace_block_number" : 373601,
- "namespace_id" : "id" ,
- "op" : "+" ,
- "op_fee" : 25000,
- "opcode" : "NAME_UPDATE" ,
- "preorder_block_number" : 445838,
- "preorder_hash" : "26bf7874706ac761afdd403ed6b3b9578fb01a34" ,
- "revoked" : false ,
- "sender" : "76a9144401f3be5311585ea519c1cb471a8dc7b02fd6ee88ac" ,
- "sender_pubkey" : "039a8948d339ecbff44cf426cb85d90fce876f1658d385cdc47f007f279be626ea" ,
- "transfer_send_block_id" : null,
- "txid" : "dc478659fc684a1a6e1e09901971e82de11f4dfe2b32a656700bf9a3b6030719" ,
- "value_hash" : "02af0ef21161ad06b0923106f40b994b9e4c1614" ,
- "vtxindex" : 95
- }
- ] ,
- "445884" : [
- {
- "address" : "1GZqrVbamkaE6YNveJFWK6cDrCy6bXyS6b" ,
- "block_number" : 445838,
- "consensus_hash" : "18b8d69f0182b89ccb1aa536f83be18a" ,
- "first_registered" : 445851,
- "importer" : null,
- "importer_address" : null,
- "last_creation_op" : "?" ,
- "last_renewed" : 445851,
- "name" : "patrickstanley.id" ,
- "name_hash128" : "683a3e1ee5f0296833c56e481cf41b77" ,
- "namespace_block_number" : 373601,
- "namespace_id" : "id" ,
- "op" : ">>" ,
- "op_fee" : 25000,
- "opcode" : "NAME_TRANSFER" ,
- "preorder_block_number" : 445838,
- "preorder_hash" : "26bf7874706ac761afdd403ed6b3b9578fb01a34" ,
- "revoked" : false ,
- "sender" : "76a914aabffa6dd90d731d3a349f009323bb312483c15088ac" ,
- "sender_pubkey" : null,
- "transfer_send_block_id" : 445875,
- "txid" : "7a0a3bb7d39b89c3638abc369c85b5c028d0a55d7804ba1953ff19b0125f3c24" ,
- "value_hash" : "02af0ef21161ad06b0923106f40b994b9e4c1614" ,
- "vtxindex" : 16
- }
- ]
-}
-
-
-
-
All of the above information is extracted from the blockchain. Each top-level
-field encodes the states the name transitioned to at the given block height (e.g.
-445838, 445851, 445873, adn 445884). At each block height, the name’s zone file
-hashes are returned in the order they were discovered in the blockchain.
-
-
Each name state contains a lot of ancillary data that is used internally by
-other API calls and client libraries. The relevant fields for this document’s
-scope are:
-
-
- address: This is the base58check-encoded public key hash.
- name: This is the name queried.
- value_hash: This is the zone file hash.
- opcode: This is the type of transaction that was processed.
- txid: This is the transaction ID in the underlying blockchain.
-
-
-
The name’s entire history is returned. This includes the history of the name
-under its previous owner, if the name expired and was reregistered.
-
-
Look up the list of names owned by a given public key hash (reference )
-
-
$ curl https://core.blockstack.org/v1/addresses/bitcoin/16EMaNw3pkn3v6f2BgnSSs53zAKH4Q8YJg
-{
- "names" : [
- "judecn.id" ,
- "patrickstanley1.id" ,
- "abcdefgh123456.id" ,
- "duckduckgo_tor.id" ,
- "jude.id" ,
- "blockstacknewyear2017.id" ,
- "jude.statism.id"
- ]
-}
-
-
-
-
Note that this API endpoint includes names and
-subdomains .
-
-
Registering BNS Names
-
-
Registering a BNS name costs cryptocurrency. This cost comes from two sources:
-
-
-
- Transaction fees: These are the fees imposed by the cost of storing the
-transaction data to the blockchain itself. They are independent of BNS, since
-all of the blockchain’s users are competing to have their transactions included
-in the next block. The blockchain’s miners receive the transaction fee.
-
-
- Registration fees: Each BNS namespace imposes an additional fee on how
-much a name costs. The registration fee is sent to the namespace creator
-during the first year that a namespace exists, and is sent to a burn address
-afterwards. The registration fee is different for each name and is
-determined by the namespace itself, but can be queried in advance by the user.
-
-
-
-
Registering a name takes two transactions. They are:
-
-
-
- NAME_PREORDER transaction : This is the first transaction to be sent.
-It tells all BNS nodes the salted hash of the BNS name, and it pays the
-registration fee to the namespace owner’s designated address (or the burn
-address). In addition, it proves to the BNS nodes that the client knows about
-the current state of the system by including a recent consensus hash
-in the transaction (see the section on BNS forks for details).
-
-
- NAME_REGISTRATION transaction : This is the second transaction to be
-sent. It reveals the salt and the name to all BNS nodes, and assigns the name
-an initial public key hash and zone file hash
-
-
-
-
The reason this process takes two transactions is to prevent front-running.
-The BNS consensus rules stipulate that a name can only be registered if its
-matching preorder transaction was sent in the last 24 hours. Because a name
-must be preordered before it is registered, someone watching the blockchain’s
-peer network cannot race a victim to claim the name they were trying to
-register (i.e. the attacker would have needed to send a NAME_PREORDER
-transaction first, and would have had to have sent it no more than 24 hours
-ago).
-
-
Registering a name on top of the Bitcoin blockchain takes 1-2 hours. This is
-because you need to wait for the NAME_PREORDER transaction to be sufficiently
-confirmed before sending the NAME_REGISTRATION transaction. The BNS nodes
-only register the name once both transactions have at least 6 confirmations
-(which itself usually takes about an hour).
-
-
Names are registered on a first-come first-serve basis.
-If two different people try to register the same name at the same time, the
-person who completes the two-step process earliest will receive the name. The
-other person’s NAME_REGISTRATION transaction will be ignored, since it will
-not be considered valid at this point. The registration fee paid by the
-NAME_PREORDER will be lost. However, this situation is rare in practice—
-as of early 2018, we only know of one confirmed instance in the system’s 3+ years
-of operation.
-
-
Fully-qualified names can be between 3 and 37 characters long, and consist of
-the characters a-z, 0-9, +, -, _, and .. This is to prevent
-homograph attacks .
-NAME_REGISTRATION transactions that do not conform to this requirement will be
-ignored.
-
-
Getting a Name’s Registration Fee (reference )
-
-
$ curl -sL https://core.blockstack.org/v1/prices/names/helloworld.id | jq -r ".name_price"
-{
- "btc" : 2.5e-05,
- "satoshis" : 2500
-}
-
-
-
-
Note the use of jq -r to select the "name_price" field. This API
-endpoint may return other ancilliary data regarding transaction fee estimation,
-but this is the only field guaranteed by this specification to be present.
-
-
Getting the Current Consensus Hash (reference )
-
-
$ curl -sL https://core.blockstack.org/v1/blockchains/bitcoin/consensus
-{
- "consensus_hash" : "98adf31989bd937576aa190cc9f5fa3a"
-}
-
-
-
-
The consensus hash must be included in the NAME_PREORDER transaction. The BNS
-clients do this automatically. See the transaction format
-document for details as to how to include this in the
-transaction.
-
-
Registering a Name
-
-
Registration happens through a BNS client, such as the Blockstack
-Browser or
-blockstack.js .
-The reference BNS clients manage a local Bitcoin wallet, calculate transaction fees
-dynamically and automatically, and broadcast both the NAME_PREORDER and
-NAME_REGISTRATION transactions at the right times.
-
-
If you want to make your own registration client, you should see the
-transaction format document.
-
-
Managing BNS Names
-
-
Once you register a BNS name, you have the power to change its zone file hash,
-change its public key hash, destroy it (i.e. render it unresolvable),
-or renew it. The BNS consensus rules ensure that only you, as the owner of
-the name’s private key, have the ability to carry out these operations.
-
-
Each of these operations are executed by sending a specially-formatted
-blockchain transaction to the blockchain, which BNS nodes read and process.
-The operations are listed below:
-
-
-
-
- Transaction Type
- Description
-
-
-
-
- NAME_UPDATE
- This changes the name’s zone file hash. Any 20-byte string is allowed.
-
-
- NAME_TRANSFER
- This changes the name’s public key hash. In addition, the current owner has the option to atomically clear the name’s zone file hash (so the new owner won’t “receive” the zone file).
-
-
- NAME_REVOKE
- This renders a name unresolvable. You should do this if your private key is compromised.
-
-
- NAME_RENEWAL
- This pushes back the name’s expiration date (if it has one), and optionally both sets a new zone file hash and a new public key hash.
-
-
-
-
-
The reference BNS clients—
-blockstack.js and the Blockstack
-Browser —can handle creating
-and sending all of these transactions for you.
-
-
-
-
A NAME_UPDATE transaction changes the name’s zone file hash. You would send
-one of these transactions if you wanted to change the name’s zone file contents.
-For example, you would do this if you want to deploy your own Gaia
-hub and want other people to read from it.
-
-
A NAME_UPDATE transaction is generated from the name, a recent consensus
-hash , and the new zone file hash. The reference clients gather
-this information automatically. See the transaction format
-document for details on how to construct this transaction.
-
-
-
-
A NAME_TRANSFER transaction changes the name’s public key hash. You would
-send one of these transactions if you wanted to:
-
-
- Change your private key
- Send the name to someone else
-
-
-
When transferring a name, you have the option to also clear the name’s zone
-file hash (i.e. set it to null).
-This is useful for when you send the name to someone else, so the
-recipient’s name does not resolve to your zone file.
-
-
The NAME_TRANSFER transaction is generated from the name, a recent consensus
-hash , and the new public key hash. The reference clients gather
-this information automatically. See the transaction format
-document for details on how to construct this transaction.
-
-
-
-
A NAME_REVOKE transaction makes a name unresolvable. The BNS consensus rules
-stipulate that once a name is revoked, no one can change its public key hash or
-its zone file hash. The name’s zone file hash is set to null to prevent it
-from resolving.
-
-
You should only do this if your private key is compromised, or if you want to
-render your name unusable for whatever reason. It is rarely used in practice.
-
-
The NAME_REVOKE operation is generated using only the name. See the
-transaction format document for details on how to construct
-it.
-
-
-
-
Depending in the namespace rules, a name can expire. For example, names in the
-.id namespace expire after 2 years. You need to send a NAME_RENEWAL every
-so often to keep your name.
-
-
A NAME_RENEWAL costs both transaction fees and registration fees. You will
-pay the registration cost of your name to the namespace’s designated burn address when you
-renew it. You can find this fee using the /v1/prices/names/{name} endpoint.
-
-
When a name expires, it enters a month-long “grace period” (5000 blocks). It
-will stop resolving in the grace period, and all of the above operations will
-cease to be honored by the BNS consensus rules. You may, however, send a
-NAME_RENEWAL during this grace period to preserve your name.
-
-
If your name is in a namespace where names do not expire, then you never need to
-use this transaction.
-
-
When you send a NAME_RENEWAL, you have the option of also setting a new public
-key hash and a new zone file hash. See the transaction format
-document for details on how to construct this transaction.
-
-
BNS Subdomains
-
-
BNS names are strongly-owned because the owner of its private key can generate
-valid transactions that update its zone file hash and owner. However, this comes at the
-cost of requiring a name owner to pay for the underlying transaction in the
-blockchain. Moreover, this approach limits the rate of BNS name registrations
-and operations to the underlying blockchain’s transaction bandwidth.
-
-
BNS overcomes this with subdomains. A BNS subdomain is a type of BNS name whose state
-and owner are stored outside of the blockchain, but whose existence and
-operation history are anchored to the
-blockchain. In the example table in the Resolving BNS
-Names section, the names cicero.res_publica.id and
-podsaveamerica.verified.podcast are subdomains.
-
-
Like their on-chain counterparts, subdomains are globally
-unique, strongly-owned, and human-readable. BNS gives them their own name state
-and public keys.
-
-
Unlike on-chain names, subdomains can be created and managed
-cheaply, because they are broadcast to the
-BNS network in batches. A single blockchain transaction can send up to 120
-subdomain operations.
-
-
This is achieved by storing subdomain records in the Atlas Network .
-An on-chain name owner broadcasts subdomain operations by encoding them as
-TXT records within a DNS zone file. To broadcast the zone file,
-the name owner sets the new zone file hash with a NAME_UPDATE transaction and
-replicates the zone file via Atlas. This, in turn, replicates all subdomain
-operations it contains, and anchors the set of subdomain operations to
-an on-chain transaction. The BNS node’s consensus rules ensure that only
-valid subdomain operations from valid NAME_UPDATE transactions will ever be
-stored.
-
-
For example, the name verified.podcast once wrote the zone file hash 247121450ca0e9af45e85a82e61cd525cd7ba023,
-which is the hash of the following zone file:
-
-
$ curl -sL https://core.blockstack.org/v1/names/verified.podcast/zonefile/247121450ca0e9af45e85a82e61cd525cd7ba023 | jq -r '.zonefile'
-$ORIGIN verified.podcast
-$TTL 3600
-1yeardaily TXT "owner=1MwPD6dH4fE3gQ9mCov81L1DEQWT7E85qH" "seqn=0" "parts=1" "zf0=JE9SSUdJTiAxeWVhcmRhaWx5CiRUVEwgMzYwMApfaHR0cC5fdGNwIFVSSSAxMCAxICJodHRwczovL3BoLmRvdHBvZGNhc3QuY28vMXllYXJkYWlseS9oZWFkLmpzb24iCg=="
-2dopequeens TXT "owner=1MwPD6dH4fE3gQ9mCov81L1DEQWT7E85qH" "seqn=0" "parts=1" "zf0=JE9SSUdJTiAyZG9wZXF1ZWVucwokVFRMIDM2MDAKX2h0dHAuX3RjcCBVUkkgMTAgMSAiaHR0cHM6Ly9waC5kb3Rwb2RjYXN0LmNvLzJkb3BlcXVlZW5zL2hlYWQuanNvbiIK"
-10happier TXT "owner=1MwPD6dH4fE3gQ9mCov81L1DEQWT7E85qH" "seqn=0" "parts=1" "zf0=JE9SSUdJTiAxMGhhcHBpZXIKJFRUTCAzNjAwCl9odHRwLl90Y3AgVVJJIDEwIDEgImh0dHBzOi8vcGguZG90cG9kY2FzdC5jby8xMGhhcHBpZXIvaGVhZC5qc29uIgo="
-31thoughts TXT "owner=1MwPD6dH4fE3gQ9mCov81L1DEQWT7E85qH" "seqn=0" "parts=1" "zf0=JE9SSUdJTiAzMXRob3VnaHRzCiRUVEwgMzYwMApfaHR0cC5fdGNwIFVSSSAxMCAxICJodHRwczovL3BoLmRvdHBvZGNhc3QuY28vMzF0aG91Z2h0cy9oZWFkLmpzb24iCg=="
-359 TXT "owner=1MwPD6dH4fE3gQ9mCov81L1DEQWT7E85qH" "seqn=0" "parts=1" "zf0=JE9SSUdJTiAzNTkKJFRUTCAzNjAwCl9odHRwLl90Y3AgVVJJIDEwIDEgImh0dHBzOi8vcGguZG90cG9kY2FzdC5jby8zNTkvaGVhZC5qc29uIgo="
-30for30 TXT "owner=1MwPD6dH4fE3gQ9mCov81L1DEQWT7E85qH" "seqn=0" "parts=1" "zf0=JE9SSUdJTiAzMGZvcjMwCiRUVEwgMzYwMApfaHR0cC5fdGNwIFVSSSAxMCAxICJodHRwczovL3BoLmRvdHBvZGNhc3QuY28vMzBmb3IzMC9oZWFkLmpzb24iCg=="
-onea TXT "owner=1MwPD6dH4fE3gQ9mCov81L1DEQWT7E85qH" "seqn=0" "parts=1" "zf0=JE9SSUdJTiBvbmVhCiRUVEwgMzYwMApfaHR0cC5fdGNwIFVSSSAxMCAxICJodHRwczovL3BoLmRvdHBvZGNhc3QuY28vb25lYS9oZWFkLmpzb24iCg=="
-10minuteteacher TXT "owner=1MwPD6dH4fE3gQ9mCov81L1DEQWT7E85qH" "seqn=0" "parts=1" "zf0=JE9SSUdJTiAxMG1pbnV0ZXRlYWNoZXIKJFRUTCAzNjAwCl9odHRwLl90Y3AgVVJJIDEwIDEgImh0dHBzOi8vcGguZG90cG9kY2FzdC5jby8xMG1pbnV0ZXRlYWNoZXIvaGVhZC5qc29uIgo="
-36questionsthepodcastmusical TXT "owner=1MwPD6dH4fE3gQ9mCov81L1DEQWT7E85qH" "seqn=0" "parts=1" "zf0=JE9SSUdJTiAzNnF1ZXN0aW9uc3RoZXBvZGNhc3RtdXNpY2FsCiRUVEwgMzYwMApfaHR0cC5fdGNwIFVSSSAxMCAxICJodHRwczovL3BoLmRvdHBvZGNhc3QuY28vMzZxdWVzdGlvbnN0aGVwb2RjYXN0bXVzaWNhbC9oZWFkLmpzb24iCg=="
-_http._tcp URI 10 1 "https://dotpodcast.co/"
-
-
-
-
Each TXT record in this zone file encodes a subdomain-creation.
-For example, 1yeardaily.verified.podcast resolves to:
-
-
$ curl https://core.blockstack.org/v1/names/1yeardaily.verified.podcast
-{
- "address" : "1MwPD6dH4fE3gQ9mCov81L1DEQWT7E85qH" ,
- "blockchain" : "bitcoin" ,
- "last_txid" : "d87a22ebab3455b7399bfef8a41791935f94bc97aee55967edd5a87f22cce339" ,
- "status" : "registered_subdomain" ,
- "zonefile_hash" : "e7acc97fd42c48ed94fd4d41f674eddbee5557e3" ,
- "zonefile_txt" : " $ORIGIN 1yeardaily \n $TTL 3600 \n _http._tcp URI 10 1 \" https://ph.dotpodcast.co/1yeardaily/head.json \"\n "
-}
-
-
-
-
This information was extracted from the 1yeardaily TXT resource record in the zone
-file for verified.podcast.
-
-
Subdomain Lifecycle
-
-
Note that 1yeardaily.verified.podcast has a different public key
-hash (address) than verified.podcast. A BNS node will only process a
-subsequent subdomain operation on 1yeardaily.verified.podcast if it includes a
-signature from this address’s private key. verified.podcast cannot generate
-updates; only the owner of 1yeardaily.verified.podcast can do so.
-
-
The lifecycle of a subdomain and its operations is shown in Figure 2.
-
-
subdomain subdomain subdomain
- creation update transfer
-+----------------+ +----------------+ +----------------+
-| cicero | | cicero | | cicero |
-| owner="1Et..." | signed | owner="1Et..." | signed | owner="1cJ..." |
-| zf0="7e4..." |<--------| zf0="111..." |<--------| zf0="111..." |<---- ...
-| seqn=0 | | seqn=1 | | seqn=2 |
-| | | sig="xxxx" | | sig="xxxx" |
-+----------------+ +----------------+ +----------------+
- | | |
- | off-chain | |
-~ ~ ~ ~ | ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~|~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | ~ ~ ~ ~ ~ ~ ~ ...
- | on-chain | |
- V V (zone file hash ) V
-+----------------+ +----------------+ +----------------+
-| res_publica.id | | jude.id | | res_publica.id |
-| NAME_UPDATE |<--------| NAME_UPDATE |<--------| NAME_UPDATE |<---- ...
-+----------------+ +----------------+ +----------------+
- blockchain blockchain blockchain
- block block block
-
-
-Figure 2: Subdomain lifetime with respect to on-chain name operations. A new
-subdomain operation will only be accepted if it has a later "sequence=" number,
-and a valid signature in "sig=" over the transaction body. The "sig=" field
-includes both the public key and signature, and the public key must hash to
-the previous subdomain operation's "addr=" field.
-
-Thesubdomain-creation and subdomain-transfer transactions for
-"cicero.res_publica.id" are broadcast by the owner of "res_publica.id".
-However, any on-chain name ("jude.id" in this case) can broadcast a subdomain
-update for "cicero.res_publica.id".
-
-
-
-
Subdomain operations are ordered by sequence number, starting at 0. Each new
-subdomain operation must include:
-
-
- The next sequence number
- The public key that hashes to the previous subdomain transaction’s address
- A signature from the corresponding private key over the entire subdomain
-operation.
-
-
-
If two correctly-signed but conflicting subdomain operations are discovered
-(i.e. they have the same sequence number), the one that occurs earlier in the
-blockchain’s history is accepted. Invalid subdomain operations are ignored.
-
-
Combined, this ensures that a BNS node with all of the zone files with a given
-subdomain’s operations will be able to determine the valid sequence of
-state-transitions it has undergone, and determine the current zone file and public
-key hash for the subdomain.
-
-
Resolving Subdomains
-
-
Developers interact with subdomains the same way they interact with names.
-Using the BNS API, a developer can:
-
-
Look up a subdomain’s public key and zone file (reference )
-
-
$ curl https://core.blockstack.org/v1/names/aaron.personal.id
-{
- "address" : "1PwztPFd1s2STMv4Ntq6UPBdYgHSBr5pdF" ,
- "blockchain" : "bitcoin" ,
- "last_txid" : "85e8273b0a38d3e9f0af7b4b72faf0907de9f4616afc101caac13e7bbc832394" ,
- "status" : "registered_subdomain" ,
- "zonefile_hash" : "a6dda6b74ffecf85f4a162627d8df59577243813" ,
- "zonefile_txt" : " $ORIGIN aaron.personal.id \n $TTL 3600 \n _https._tcp URI 10 1 \" https://gaia.blockstack.org/hub/1PwztPFd1s2STMv4Ntq6UPBdYgHSBr5pdF/profile.json \"\n "
-}
-
-
-
-
Look up a subdomain’s transaction history (reference )
-
-
$ curl https://core.blockstack.org/v1/names/aaron.personal.id/history
-{
- "509981" : [
- {
- "address" : "1PwztPFd1s2STMv4Ntq6UPBdYgHSBr5pdF" ,
- "block_number" : 509981,
- "domain" : "personal.id" ,
- "name" : "aaron.personal.id" ,
- "sequence" : 0,
- "txid" : "85e8273b0a38d3e9f0af7b4b72faf0907de9f4616afc101caac13e7bbc832394" ,
- "value_hash" : "a6dda6b74ffecf85f4a162627d8df59577243813" ,
- "zonefile" : "JE9SSUdJTiBhYXJvbi5wZXJzb25hbC5pZAokVFRMIDM2MDAKX2h0dHBzLl90Y3AgVVJJIDEwIDEgImh0dHBzOi8vZ2FpYS5ibG9ja3N0YWNrLm9yZy9odWIvMVB3enRQRmQxczJTVE12NE50cTZVUEJkWWdIU0JyNXBkRi9wcm9maWxlLmpzb24iCg=="
- }
- ]
-}
-
-
-
-
Look up the list of names and subdomains owned by a given public key hash (reference )
-
-
$ curl https://core.blockstack.org/v1/addresses/bitcoin/1PwztPFd1s2STMv4Ntq6UPBdYgHSBr5pdF
-{
- "names" : [
- "aaron.personal.id"
- ]
-}
-
-
-
-
Subdomain Creation and Management
-
-
Unlike an on-chain name, a subdomain owner needs an on-chain name owner’s help
-to broadcast their subdomain operations. In particular:
-
- A subdomain-creation transaction can only be processed by the owner of the on-chain
-name that shares its suffix. For example, only the owner of res_publica.id
-can broadcast subdomain-creation transactions for subdomain names ending in
-.res_publica.id.
- A subdomain-transfer transaction can only be broadcast by the owner of the
-on-chain name that created it. For example, the owner of
-cicero.res_publica.id needs the owner of res_publica.id to broadcast a
-subdomain-transfer transaction to change cicero.res_publica.id’s public key.
- In order to send a subdomain-creation or subdomain-transfer, all
-of an on-chain name owner’s zone files must be present in the Atlas network.
-This lets the BNS node prove the absence of any conflicting subdomain-creation and
-subdomain-transfer operations when processing new zone files.
- A subdomain update transaction can be broadcast by any on-chain name owner,
-but the subdomain owner needs to find one who will cooperate. For example,
-the owner of verified.podcast can broadcast a subdomain-update transaction
-created by the owner of cicero.res_publica.id.
-
-
-
That said, to create a subdomain, the subdomain owner generates a
-subdomain-creation operation for their desired name
-and gives it to the on-chain name owner.
-The on-chain name owner then uses Atlas to
-broadcast it to all other BNS nodes.
-
-
Once created, a subdomain owner can use any on-chain name owner to broadcast a
-subdomain-update operation. To do so, they generate and sign the requisite
-subdomain operation and give it to an on-chain name owner, who then packages it
-with other subdomain operations into a DNS zone file
-and sends them all out on the Atlas network.
-
-
If the subdomain owner wants to change the address of their subdomain, they need
-to sign a subdomain-transfer operation and give it to the on-chain name owner
-who created the subdomain. They then package it into a zone file and broadcast
-it.
-
-
Subdomain Registrars
-
-
Because subdomain names are cheap, developers may be inclined to run
-subdomain registrars on behalf of their applications. For example,
-the name personal.id is used to register Blockstack application users without
-requiring them to spend any Bitcoin.
-
-
We supply a reference
-implementation of a BNS Subdomain Registrar
-to help developers broadcast subdomain operations. Users would still own their
-subdomain names; the registrar simply gives developers a convenient way for them
-to register and manage them in the context of a particular application.
-Please see the tutorial on running a subdomain registrar for
-details on how to use it.
-
-
BNS Forks
-
-
BNS effectively uses a public blockchain to store a database log. A BNS peer
-bootstraps itself by downloading and replaying the database log from the
-blockchain, and in doing so, will calculate the same name database state as
-every other (honest) BNS peer that has the same view of the blockchain.
-
-
Crucially, BNS is built on top of a public blockchain that is unaware of BNS’s existence.
-This means that the blockchain peers do not validate BNS transactions. Instead,
-the BNS peer needs to do so, and must know how to reject both invalid transactions
-as well as well-formed transactions from dishonest peers (i.e. peers that do not
-follow the same consensus rules).
-
-
BNS nodes do not directly communicate with one another—by design, the set of
-BNS peers is not enumerable. The only shared communication medium between BNS
-peers is the blockchain.
-
-
To identify and reject invalid and malicious transactions without the blockchain’s help,
-the log of name operations embedded in the blockchain is constructed as a
-fork*-consistent database
-log. Fork*-consistency is a consistency
-model whereby the state
-replicas in all of the nodes exhibit the following properties:
-
-
-
- Each correct peer maintains a history of well-formed, valid state operations. In this
-case, each correct BNS node maintains a copy of the history blockchain transactions
-that encoded well-formed, valid name operations.
-
-
- Each honest peer’s history contains the sequence of all operations that it
-sent. That is, a user’s BNS peer’s transaction log will contain the sequence of all valid
-transactions that the user’s client wrote to the blockchain.
-
-
- If two peers accept operations op and op’ from the same correct client,
-then both of their logs will have the both operations in the same order. If
-op’ was accepted before op , then both peers’ logs are identical up to op’ .
-In BNS, this means that if two peers both accept a given transaction, then it
-means that they have accepted the same sequence of prior transactions.
-
-
-
-
This means that unlike with blockchains,
-there can be multiple long-lived conflicting forks of the BNS database log.
-However, due to fork*-consistency, a correct BNS peer will only process one
-of these forks, and will ignore transactions from peers in other forks. In other words,
-fork*-consistency partitions the set of BNS peers into different fork-sets ,
-where all peers in a fork-set process each other’s transactions, but the
-completely ignore peers in other fork-sets.
-
-
BNS nodes identify which fork set they belong to using a consensus hash . The
-consensus hash is a cryptographic digest of a node’s operation
-history. Each BNS peer calculates a new consensus hash each time it processes a
-new block, and stores the history of consensus hashes for each block it
-processed.
-
-
Two honest BNS peers can quickly determine if they are in the same fork-set by querying
-each other’s consensus hashes for a given block. If they match, then they are
-in the same fork-set (assming no hash collisions).
-
-
A BNS client executes a name operation on a specific fork-set by including a
-recent consensus hash from that fork-set in the blockchain transaction.
-At the same time, the BNS consensus rules state that a transaction can only be
-accepted if it included a recent valid consensus hash.
-This means that all BNS nodes in the client’s desired fork-set will accept
-the transaction, and all other BNS nodes not in the fork-set will ignore it.
-You can see where the consensus hash is included in blockchain transactions by reading
-the transaction wire format document.
-
-
Fork-set Selection
-
-
The blockchain linearizes the history of transactions, which means that
-in general, there exists a fork-set for each distinct set of BNS
-consensus rules. For example, the Blockstack Core 2016 hard fork
-and 2017 hard fork both introduced new consensus
-rules, which means at the time of this writing there are three possible fork-sets:
-the pre-2016 fork-set, the 2016-2017 fork-set, and the post-2017 fork-set.
-The public BNS nodes are always running
-in the fork-set with the latest consensus rules.
-
-
BNS clients are incentivized to communicate with peers in the fork-set that has
-the most use, since this fork-set’s name database will encode name/state
-bindings that are the most widely-accepted and understood by users.
-To identify this fork-set, a BNS client needs to learn one of
-its recent consensus hashes. Once it has a recent consensus hash, it can
-query an untrusted BNS node for a copy of
-its name database, and use the consensus hash to verify that the name database
-was used to generate it.
-
-
How does a BNS node determine whether or not a consensus hash corresponds to the
-most widely-used fork-set? There are two strategies:
-
-
-
- Determine whether or not a characteristic transaction was accepted by the
-widely-used fork-set. If a client knows that a specific transaction belongs to
-the widely-used fork-set and not others, then they can use the consensus hash to
-efficiently determine whether or not a given node belongs to this fork-set.
-
-
- Determine how much “economic activity” exists in a fork-set by inspecting
-the blockchain for burned cryptocurrency tokens. Namespace and name
-registrations are structured in a way that sends cryptocurrency tokens to either
-a well-known burn address, or to an easily-queried pay-to-namespace-creator
-address.
-
-
-
-
Both strategies rely on the fact that the consensus hash is calculated as a
-Merkle skip-list
-over the BNS node’s accepted transactions. A client can use a consensus hash to
-determine whether or not a transaction T was accepted by a node with O(log
-n) time and space complexity. We call the protocol for resolving a consensus hash to a specific transaction
-Simplified Name Verification (SNV). See our paper on the subject
-for details of how SNV works under the hood.
-
-
If the client has a consensus hash and knows of a characteristic transaction in the widely-used fork-set,
-it can use SNV to determine whether or not a node belongs to the fork-set that accepted it.
-
-
If the client knows about multiple conflicting consensus hashes,
-they can still use SNV to determine which one corresponds
-to the most-used fork-set. To do so, the client would use a
-blockchain explorer to find the
-list of transactions that burned cryptocurrency tokens. Each of these
-transactions will be treated as potential characteristic transactions:
-the client would first select the subset of transactions that are well-formed
-BNS transactions, and then use SNV to determine which of them correspond to which
-consensus hashes. The client chooses the consensus hash that corresponds
-to the fork-set with the highest cumulative burn.
-
-
Work is currently underway to automate this process.
-
-
Decentralized Identifiers (DIDs)
-
-
BNS nodes are compliant with the emerging
-Decentralized Identity Foundation protocol
-specification for decentralized identifiers (DIDs).
-
-
Each name in BNS has an associated DID. The DID format for BNS is:
-
-
did:stack:v0:{address}-{index}
-
-
-
-
Where:
-
- { address } is an on-chain public key hash (e.g. a Bitcoin address).
- { index } refers to the nth name this address created.
-
-
-
For example, the DID for personal.id is
-did:stack:v0:1dARRtzHPAFRNE7Yup2Md9w18XEQAtLiV-0, because the name
-personal.id was the first-ever name created by
-1dARRtzHPAFRNE7Yup2Md9w18XEQAtLiV.
-
-
As another example, the DID for jude.id is did:stack:v0:16EMaNw3pkn3v6f2BgnSSs53zAKH4Q8YJg-1.
-Here, the address 16EMaNw3pkn3v6f2BgnSSs53zAKH4Q8YJg had created one earlier
-name in history prior to this one (which happens to be abcdefgh123456.id).
-
-
The purpose of a DID is to provide an eternal identifier for a public key.
-The public key may change, but the DID will not.
-
-
Blockstack Core implements a DID method of its own
-in order to be compatible with other systems that use DIDs for public key resolution.
-In order for a DID to be resolvable, all of the following must be true for a
-name:
-
-
- The name must exist
- The name’s zone file hash must be the hash of a well-formed DNS zone file
- The DNS zone file must be present in the BNS Atlas Network
- The DNS zone file must contain a URI resource record that points to a signed
-JSON Web Token
- The public key that signed the JSON Web Token (and is included with it) must
-hash to the address that owns the name
-
-
-
Not all names will have DIDs that resolve to public keys. However, names created by the Blockstack
-Browser will have DIDs that
-do.
-
-
Developers can programmatically resolve DIDs via the Python API:
-
-
>>> import blockstack
->>> blockstack.lib.client.resolve_DID('did:stack:v0:16EMaNw3pkn3v6f2BgnSSs53zAKH4Q8YJg-1', hostport='https://node.blockstack.org:6263')
-{'public_key': '020fadbbcea0ff3b05f03195b41cd991d7a0af8bd38559943aec99cbdaf0b22cc8'}
-
-
-
A RESTful API is under development.
-
-
DID Encoding for Subdomains
-
-
Every name and subdomain in BNS has a DID. The encoding is slightly different
-for subdomains, so the software can determine which code-path to take.
-
-
-
- For on-chain BNS names, the { address } is the same as the Bitcoin address
-that owns the name. Currently, both version byte 0 and version byte 5
-addresses are supported (i.e. addresses starting with 1 or 3, meaning p2pkh and
-p2sh addresses).
-
-
- For off-chain BNS subdomains, the { address } has version byte 63 for
-subdomains owned by a single private key, and version byte 50 for subdomains
-owned by a m-of-n set of private keys. That is, subdomain DID addresses start
-with S or M, respectively.
-
-
-
-
The { index } field for a subdomain’s DID is distinct from the { index } field
-for a BNS name’s DID, even if the same created both names and subdomains.
-For example, the name abcdefgh123456.id has the DID did:stack:v0:16EMaNw3pkn3v6f2BgnSSs53zAKH4Q8YJg-0,
-because it was the first name created by 16EMaNw3pkn3v6f2BgnSSs53zAKH4Q8YJg.
-However, 16EMaNw3pkn3v6f2BgnSSs53zAKH4Q8YJg also created jude.statism.id
-as its first subdomain name. The DID for jude.statism.id is
-did:stack:v0:SSXMcDiCZ7yFSQSUj7mWzmDcdwYhq97p2i-0. Note that the address
-SSXMcDiCZ7yFSQSUj7mWzmDcdwYhq97p2i encodes the same public key hash as the address
-16EMaNw3pkn3v6f2BgnSSs53zAKH4Q8YJg (the only difference between these two
-strings is that the first is base58check-encoded with version byte 0, and the
-second is encoded with version byte 63).
-
-
You can see this play out in practice with the following code snippit:
-
-
>>> import blockstack
->>> blockstack . lib . client . get_name_record ( 'jude.statism.id' , hostport = 'https://node.blockstack.org:6263' )[ 'address' ]
-u'16EMaNw3pkn3v6f2BgnSSs53zAKH4Q8YJg'
->>> import virtualchain
->>> virtualchain . address_reencode ( '16EMaNw3pkn3v6f2BgnSSs53zAKH4Q8YJg' , version_byte = 63 )
-'SSXMcDiCZ7yFSQSUj7mWzmDcdwYhq97p2i'
->>> blockstack . lib . client . resolve_DID ( 'did:stack:v0:SSXMcDiCZ7yFSQSUj7mWzmDcdwYhq97p2i-0' , hostport = 'https://node.blockstack.org:6263' )
-{ 'public_key' : '020fadbbcea0ff3b05f03195b41cd991d7a0af8bd38559943aec99cbdaf0b22cc8' }
-
-
-
-
Summary
-
-
BNS is a decentralized naming system that produces names that are
-globally-unique, human-readable, and strongly-owned. It does so by embedding a
-database log within a public blockchain like Bitcoin, and replaying it locally
-to calculate the state and owner of each name. In doing so, a BNS node provides
-a full replica of all of the network’s state, which gives it the ability to
-service queries like prior name states and name historys.
-
-
BNS groups names by namespaces in order to provide different ways to register
-and use names, and furthermore implements subdomains to provide a cheap,
-scalable way to register many names for the cost of a single blockchain
-transaction.
-
-
Blockstack Core is the
-reference implementation of BNS, and provides a public BNS node with online
-documentation at https://core.blockstack.org.
-
-
Appendix 1: Feature Comparison
-
-
BNS is not the only naming system in wide-spread use, nor is it the only
-decentralized naming system that implements human-readable,
-globally-unique, and strongly-owned names. The following feature table
-describes how BNS differs from other naming systems
-
-
-
-
- Feature
- BNS
- ENS
- DNS
- Namecoin
-
-
-
-
- Globally unique names
- X
- X
- X
- X
-
-
- Human-readable names
- X
- X
- X
- X
-
-
- Strongly-owned names
- X
- X
-
- X
-
-
- Names are enumerable
- X
-
-
- X
-
-
- Registration times
- 1-2 hours
- ~1 week
- ~1 day
- 1-2 hours
-
-
- Subdomain registration times
- 1 hour (instant with #750 )
- varies
- instant
- ~1 hour
-
-
- Anyone can make a TLD/namespace
- X
- [1]
-
- [1]
-
-
- TLD/Namespace owners get registration fees
- X
-
- X
-
-
-
- TLD/Namespace can be seeded with initial names
- X
-
- X
-
-
-
- Portable across blockchains
- X
-
- N/A
-
-
-
- Off-chain names
- X
-
- N/A
-
-
-
- Off-chain name state
- X
- X
- N/A
-
-
-
- Name provenance
- X
- X
-
- X
-
-
- DID support
- X
-
-
-
-
-
- Turing-complete namespace rules
-
- X
- X
-
-
-
- Miners are rewarded for participating
- [1]
-
- N/A
- X
-
-
-
-
-
[1] Requires support in higher-level applications. These systems are not aware
-of the existence of namespaces/TLDs at the protocol level.
-
-
[2] Blockstack Core destroys the underlying blockchain token to pay for
-registration fees when there is no pay-to-namespace-creator address set in the
-name’s namespace. This has the effect of making the blockchain miners’ holdings
-slightly more valuable.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Related Articles
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Blockstack
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/_site/core/naming/manage.html b/_site/core/naming/manage.html
deleted file mode 100644
index 9c8e1b5197..0000000000
--- a/_site/core/naming/manage.html
+++ /dev/null
@@ -1,579 +0,0 @@
-
-
-
-
-
-
-
-
-
Manage BNS Names | Blockstack
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Manage BNS Names
-
-
-
-
-
-
-
-
This section teaches you how to manage your namespace, it contains the
-following sections:
-
-
-
-
Overview of management
-
-
Once you register a BNS name, you have the power to change its zone file hash,
-change its public key hash, destroy it (i.e. render it unresolvable),
-or renew it. The BNS consensus rules ensure that only you, as the owner of
-the name’s private key, have the ability to carry out these operations.
-
-
Each of these operations are executed by sending a specially-formatted
-blockchain transaction to the blockchain, which BNS nodes read and process.
-The operations are listed below:
-
-
-
-
- Transaction Type
- Description
-
-
-
-
- NAME_UPDATE
- This changes the name’s zone file hash. Any 20-byte string is allowed.
-
-
- NAME_TRANSFER
- This changes the name’s public key hash. In addition, the current owner has the option to atomically clear the name’s zone file hash (so the new owner won’t “receive” the zone file).
-
-
- NAME_REVOKE
- This renders a name unresolvable. You should do this if your private key is compromised.
-
-
- NAME_RENEWAL
- This pushes back the name’s expiration date (if it has one), and optionally both sets a new zone file hash and a new public key hash.
-
-
-
-
-
The reference BNS clients—
-blockstack.js and the Blockstack
-Browser —can handle creating
-and sending all of these transactions for you.
-
-
-
-
A NAME_UPDATE transaction changes the name’s zone file hash. You would send
-one of these transactions if you wanted to change the name’s zone file contents.
-For example, you would do this if you want to deploy your own Gaia
-hub and want other people to read from it.
-
-
A NAME_UPDATE transaction is generated from the name, a recent consensus
-hash , and the new zone file hash. The reference clients gather
-this information automatically. See the transaction format
-document for details on how to construct this transaction.
-
-
-
-
A NAME_TRANSFER transaction changes the name’s public key hash. You would
-send one of these transactions if you wanted to:
-
-
- Change your private key
- Send the name to someone else
-
-
-
When transferring a name, you have the option to also clear the name’s zone
-file hash (i.e. set it to null).
-This is useful for when you send the name to someone else, so the
-recipient’s name does not resolve to your zone file.
-
-
The NAME_TRANSFER transaction is generated from the name, a recent consensus
-hash , and the new public key hash. The reference clients gather
-this information automatically. See the transaction format
-document for details on how to construct this transaction.
-
-
-
-
A NAME_REVOKE transaction makes a name unresolvable. The BNS consensus rules
-stipulate that once a name is revoked, no one can change its public key hash or
-its zone file hash. The name’s zone file hash is set to null to prevent it
-from resolving.
-
-
You should only do this if your private key is compromised, or if you want to
-render your name unusable for whatever reason. It is rarely used in practice.
-
-
The NAME_REVOKE operation is generated using only the name. See the
-transaction format document for details on how to construct
-it.
-
-
-
-
Depending in the namespace rules, a name can expire. For example, names in the
-.id namespace expire after 2 years. You need to send a NAME_RENEWAL every
-so often to keep your name.
-
-
A NAME_RENEWAL costs both transaction fees and registration fees. You will
-pay the registration cost of your name to the namespace’s designated burn address when you
-renew it. You can find this fee using the /v1/prices/names/{name} endpoint.
-
-
When a name expires, it enters a month-long “grace period” (5000 blocks). It
-will stop resolving in the grace period, and all of the above operations will
-cease to be honored by the BNS consensus rules. You may, however, send a
-NAME_RENEWAL during this grace period to preserve your name.
-
-
If your name is in a namespace where names do not expire, then you never need to
-use this transaction.
-
-
When you send a NAME_RENEWAL, you have the option of also setting a new public
-key hash and a new zone file hash. See the transaction format
-document for details on how to construct this transaction.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Related Articles
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Blockstack
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/_site/core/naming/namespaces.html b/_site/core/naming/namespaces.html
deleted file mode 100644
index a6d0c5fb1e..0000000000
--- a/_site/core/naming/namespaces.html
+++ /dev/null
@@ -1,593 +0,0 @@
-
-
-
-
-
-
-
-
-
Understand Namespaces | Blockstack
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Understand Namespaces
-
-
-
-
-
-
-
-
Namespaces are the top-level naming objects in BNS.
-
-
They control a few properties about the names within them:
-
- How expensive they are to register
- How long they last before they have to be renewed
- Who (if anyone) receives the name registration fees
- Who is allowed to seed the namespace with its initial names.
-
-
-
At the time of this writing, by far the largest BNS namespace is the .id
-namespace. Names in the .id namespace are meant for resolving user
-identities. Short names in .id are more expensive than long names, and have
-to be renewed by their owners every two years. Name registration fees are not
-paid to anyone in particular—they are instead sent to a “black hole” where
-they are rendered unspendable (the intention is to discourage ID sqautters).
-
-
Unlike DNS, anyone can create a namespace and set its properties. Namespaces
-are created on a first-come first-serve basis, and once created, they last
-forever.
-
-
However, creating a namespace is not free. The namespace creator must burn
-cryptocurrency to do so. The shorter the namespace, the more cryptocurrency
-must be burned (i.e. short namespaces are more valuable than long namespaces).
-For example, it cost Blockstack PBC 40 BTC to create the .id namespace in 2015
-(in transaction
-5f00b8e609821edd6f3369ee4ee86e03ea34b890e242236cdb66ef6c9c6a1b281).
-
-
Namespaces can be between 1 and 19 characters long, and are composed of the
-characters a-z, 0-9, -, and _.
-
-
Namespace Organization
-
-
BNS names are organized into a global name hierarchy. There are three different
-layers in this hierarchy related to naming:
-
-
-
- Namespaces . These are the top-level names in the hierarchy. An analogy
-to BNS namespaces are DNS top-level domains. Existing BNS namespaces include
-.id, .podcast, and .helloworld. All other names belong to exactly one
-namespace. Anyone can create a namespace, but in order for the namespace
-to be persisted, it must be launched so that anyone can register names in it.
-Namespaces are not owned by their creators.
-
-
- BNS names . These are names whose records are stored directly on the
-blockchain. The ownership and state of these names are controlled by sending
-blockchain transactions. Example names include verified.podcast and
-muneeb.id. Anyone can create a BNS name, as long as the namespace that
-contains it exists already. The state for BNS names is usually stored in the Atlas
-network .
-
-
- BNS subdomains . These are names whose records are stored off-chain,
-but are collectively anchored to the blockchain. The ownership and state for
-these names lives within the Atlas network . While BNS
-subdomains are owned by separate private keys, a BNS name owner must
-broadcast their subdomain state. Example subdomains include jude.personal.id
-and podsaveamerica.verified.podcast. Unlike BNS namespaces and names, the
-state of BNS subdomains is not part of the blockchain consensus rules.
-
-
-
-
A feature comparison matrix summarizing the similarities and differences
-between these name objects is presented below:
-
-
-
-
- Feature
- Namespaces
- BNS names
- BNS Subdomains
-
-
-
-
- Globally unique
- X
- X
- X
-
-
- Human-meaningful
- X
- X
- X
-
-
- Owned by a private key
-
- X
- X
-
-
- Anyone can create
- X
- X
- [1]
-
-
- Owner can update
-
- X
- [1]
-
-
- State hosted on-chain
- X
- X
-
-
-
- State hosted off-chain
-
- X
- X
-
-
- Behavior controlled by consensus rules
- X
- X
-
-
-
- May have an expiration date
-
- X
-
-
-
-
-
-
[1] Requires the cooperation of a BNS name owner to broadcast its transactions
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Related Articles
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Blockstack
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/_site/core/naming/pickname.html b/_site/core/naming/pickname.html
deleted file mode 100644
index 4d45fdee06..0000000000
--- a/_site/core/naming/pickname.html
+++ /dev/null
@@ -1,625 +0,0 @@
-
-
-
-
-
-
-
-
-
Choose a name | Blockstack
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Choose a name
-
-
-
-
-
-
-
-
This section explains how to choose and create a namespace, it contains the
-following sections:
-
-
-
-
Intended uses for a namespace
-
-
The intention is that each application can create its own BNS
-namespace for its own purposes. Applications can use namespaces for things like:
-
-
- Giving users a SSO system, where each user registers their public key under a
-username. Blockstack applications do this with names in the .id namespace,
-for example.
- Providing a subscription service, where each name is a 3rd party that provides
-a service for users to subscribe to. For example, names in
-.podcast point to podcasts that users of the
-DotPodcast app can subscribe to.
- Implementing software licenses, where each name corresponds to an access key.
-Unlike conventional access keys, access keys implemented as names
-can be sold and traded independently. The licensing fee (paid as a name
-registration) would be set by the developer and sent to a developer-controlled
-blockchain address.
-
-
-
Names within a namespace can serve any purpose the developer wants. The ability
-to collect registration fees for 1 year after creating the namespace not only
-gives developers the incentive to get users to participate in the app, but also
-gives them a way to measure economic activity.
-
-
Developers can query individual namespaces and look up names within them using
-the BNS API.
-
-
List all namespaces in existence (reference ).
-
-
$ curl https://core.blockstack.org/v1/namespaces
-[
- "id" ,
- "helloworld" ,
- "podcast"
-]
-
-
-
-
List all names within a namespace (reference )
-
-
$ curl https://core.blockstack.org/v1/namespaces/id/names?page= 0
-[
- "0.id" ,
- "0000.id" ,
- "000000.id" ,
- "000001.id" ,
- "00000111111.id" ,
- "000002.id" ,
- "000007.id" ,
- "0011sro.id" ,
- "007_007.id" ,
- "00n3w5.id" ,
- "00r4zr.id" ,
- "00w1k1.id" ,
- "0101010.id" ,
- "01jack.id" ,
- "06nenglish.id" ,
- "08.id" ,
- "0cool_f.id" ,
- "0dadj1an.id" ,
- "0nelove.id" ,
- "0nename.id"
-...
-]
-
-
-
-
Each page returns a batch of 100 names.
-
-
Get the Cost to Register a Namespace (reference )
-
-
$ curl https://core.blockstack.org/v1/prices/namespaces/test
-{
- "satoshis" : 40000000
-}
-
-
-
-
If you want to register a namespace, please see the namespace creation tutorial .
-
-
Getting the Current Consensus Hash (reference )
-
-
$ curl -sL https://core.blockstack.org/v1/blockchains/bitcoin/consensus
-{
- "consensus_hash" : "98adf31989bd937576aa190cc9f5fa3a"
-}
-
-
-
-
A recent consensus hash is required to create a NAMESPACE_PREORDER transaction. The reference
-BNS clients do this automatically. See the transaction format
-document for details on how the consensus hash is used to construct the
-transaction.
-
-
Create a namespace
-
-
There are four steps to creating a namespace:
-
-
-
- Send a NAMESPACE_PREORDER transaction (live example ).
-This is the first step. This registers the salted hash of the namespace with BNS nodes, and burns the
-requisite amount of cryptocurrency. In addition, it proves to the
-BNS nodes that user has honored the BNS consensus rules by including
-a recent consensus hash in the transaction
-(see the section on BNS forks for details).
-
-
- Send a NAMESPACE_REVEAL transaction (live example ).
-This is the second step. This reveals the salt and the namespace ID (pairing it with its
-NAMESPACE_PREORDER), it reveals how long names last in this namespace before
-they expire or must be renewed, and it sets a price function for the namespace
-that determines how cheap or expensive names its will be. The price function takes
-a name in this namespace as input, and outputs the amount of cryptocurrency the
-name will cost (i.e. by examining how long the name is, and whether or not it
-has any vowels or non-alphabet characters). The namespace creator
-has the option to collect name registration fees for the first year of the
-namespace’s existence by setting a namespace creator address .
-
-
- Seed the namespace with NAME_IMPORT transactions (live example ).
-Once the namespace has been revealed, the user has the option to populate it with a set of
-names. Each imported name is given both an owner and some off-chain state.
-This step is optional—namespace creators are not required to import names.
-
-
- Send a NAMESPACE_READY transaction (live example ).
-This is the final step of the process. It launches the namespace, which makes it available to the
-public. Once a namespace is ready, anyone can register a name in it if they
-pay the appropriate amount of cryptocurrency (according to the price funtion
-revealed in step 2).
-
-
-
-
The reason for the NAMESPACE_PREORDER/NAMESPACE_REVEAL pairing is to prevent
-frontrunning. The BNS consensus rules require a NAMESPACE_REVEAL to be
-paired with a previous NAMESPACE_PREORDER sent within the past 24 hours.
-If it did not do this, then a malicious actor could watch the blockchain network
-and race a victim to claim a namespace.
-
-
Namespaces are created on a first-come first-serve basis. If two people try to
-create the same namespace, the one that successfully confirms both the
-NAMESPACE_PREORDER and NAMESPACE_REVEAL wins. The fee burned in the
-NAMESPACE_PREORDER is spent either way.
-
-
Once the user issues the NAMESPACE_PREORDER and NAMESPACE_REVEAL, they have
-1 year before they must send the NAMESPACE_READY transaction. If they do not
-do this, then the namespace they created disappears (along with all the names
-they imported).
-
-
Developers wanting to create their own namespaces should read the namespace
-creation document. It is highly recommended that
-developers follow this tutorial closely, given the large amount of
-cryptocurrency at stake.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Related Articles
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Blockstack
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/_site/core/naming/register.html b/_site/core/naming/register.html
deleted file mode 100644
index 22a458ce2d..0000000000
--- a/_site/core/naming/register.html
+++ /dev/null
@@ -1,575 +0,0 @@
-
-
-
-
-
-
-
-
-
Register a name | Blockstack
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Register a name
-
-
-
-
-
-
-
-
This section explains registering BNS names and provides instructions for methods
-you can use to understandt the cost of namespace registration.
-
-
-
-
Understand registration
-
-
Registering a BNS name costs cryptocurrency. This cost comes from two sources:
-
-
-
- Transaction fees: These are the fees imposed by the cost of storing the
-transaction data to the blockchain itself. They are independent of BNS, since
-all of the blockchain’s users are competing to have their transactions included
-in the next block. The blockchain’s miners receive the transaction fee.
-
-
- Registration fees: Each BNS namespace imposes an additional fee on how
-much a name costs. The registration fee is sent to the namespace creator
-during the first year that a namespace exists, and is sent to a burn address
-afterwards. The registration fee is different for each name and is
-determined by the namespace itself, but can be queried in advance by the user.
-
-
-
-
Registering a name takes two transactions. They are:
-
-
-
- NAME_PREORDER transaction : This is the first transaction to be sent.
-It tells all BNS nodes the salted hash of the BNS name, and it pays the
-registration fee to the namespace owner’s designated address (or the burn
-address). In addition, it proves to the BNS nodes that the client knows about
-the current state of the system by including a recent consensus hash
-in the transaction (see the section on BNS forks for details).
-
-
- NAME_REGISTRATION transaction : This is the second transaction to be
-sent. It reveals the salt and the name to all BNS nodes, and assigns the name
-an initial public key hash and zone file hash
-
-
-
-
The reason this process takes two transactions is to prevent front-running.
-The BNS consensus rules stipulate that a name can only be registered if its
-matching preorder transaction was sent in the last 24 hours. Because a name
-must be preordered before it is registered, someone watching the blockchain’s
-peer network cannot race a victim to claim the name they were trying to
-register (i.e. the attacker would have needed to send a NAME_PREORDER
-transaction first, and would have had to have sent it no more than 24 hours
-ago).
-
-
Registering a name on top of the Bitcoin blockchain takes 1-2 hours. This is
-because you need to wait for the NAME_PREORDER transaction to be sufficiently
-confirmed before sending the NAME_REGISTRATION transaction. The BNS nodes
-only register the name once both transactions have at least 6 confirmations
-(which itself usually takes about an hour).
-
-
Names are registered on a first-come first-serve basis.
-If two different people try to register the same name at the same time, the
-person who completes the two-step process earliest will receive the name. The
-other person’s NAME_REGISTRATION transaction will be ignored, since it will
-not be considered valid at this point. The registration fee paid by the
-NAME_PREORDER will be lost. However, this situation is rare in practice—
-as of early 2018, we only know of one confirmed instance in the system’s 3+ years
-of operation.
-
-
Fully-qualified names can be between 3 and 37 characters long, and consist of
-the characters a-z, 0-9, +, -, _, and .. This is to prevent
-homograph attacks .
-NAME_REGISTRATION transactions that do not conform to this requirement will be
-ignored.
-
-
Getting a Name’s Registration Fee (reference )
-
-
$ curl -sL https://core.blockstack.org/v1/prices/names/helloworld.id | jq -r ".name_price"
-{
- "btc" : 2.5e-05,
- "satoshis" : 2500
-}
-
-
-
-
Note the use of jq -r to select the "name_price" field. This API
-endpoint may return other ancilliary data regarding transaction fee estimation,
-but this is the only field guaranteed by this specification to be present.
-
-
Getting the Current Consensus Hash (reference )
-
-
$ curl -sL https://core.blockstack.org/v1/blockchains/bitcoin/consensus
-{
- "consensus_hash" : "98adf31989bd937576aa190cc9f5fa3a"
-}
-
-
-
-
The consensus hash must be included in the NAME_PREORDER transaction. The BNS
-clients do this automatically. See the transaction format
-document for details as to how to include this in the
-transaction.
-
-
Registering a Name
-
-
Registration happens through a BNS client, such as the Blockstack
-Browser or
-blockstack.js .
-The reference BNS clients manage a local Bitcoin wallet, calculate transaction fees
-dynamically and automatically, and broadcast both the NAME_PREORDER and
-NAME_REGISTRATION transactions at the right times.
-
-
If you want to make your own registration client, you should see the
-transaction format document.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Related Articles
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Blockstack
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/_site/core/naming/resolving.html b/_site/core/naming/resolving.html
deleted file mode 100644
index c88e7d7e23..0000000000
--- a/_site/core/naming/resolving.html
+++ /dev/null
@@ -1,745 +0,0 @@
-
-
-
-
-
-
-
-
-
Resolve a name | Blockstack
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Resolve a name
-
-
-
-
-
-
-
-
This section explains resolving BNS names and provides instructions for methods
-you can use to accomplish namespace resolution.
-
-
-
-
Understand resolution
-
-
BNS names are bound to both public keys and to about 40Kb of off-chain state.
-The off-chain state is encoded as a DNS zone file ,
-which contains routing information for discovering the user’s Blockstack data
-(such as their profile and app data, which are hosted in the Gaia storage
-system ).
-
-
The blockchain is not used to store this information directly. Instead, the
-blockchain stores the public key hash and the zone file hash . When
-indexing the blockchain, each BNS node builds a database with
-three columns: all the on-chain BNS names that have been registered, each
-name’s public key hash, and each name’s zone file’s hash.
-In addition, each BNS node maintains the transaction history of each name.
-A developer can resolve a name to any configuration it was in at any prior
-point in time.
-
-
Below is an example name table pulled from a live BNS node:
-
-
-
-
- Name
- Public key hash
- Zone File Hash
-
-
-
-
- ryan.id
- 15BcxePn59Y6mYD2fRLCLCaaHScefqW2No
- a455954b3e38685e487efa41480beeb315f4ec65
-
-
- muneeb.id
- 1J3PUxY5uDShUnHRrMyU6yKtoHEUPhKULs
- 37aecf837c6ae9bdc9dbd98a268f263dacd00361
-
-
- jude.id
- 16EMaNw3pkn3v6f2BgnSSs53zAKH4Q8YJg
- b6e99200125e70d634b17fe61ce55b09881bfafd
-
-
- verified.podcast
- 1MwPD6dH4fE3gQ9mCov81L1DEQWT7E85qH
- 6701ce856620d4f2f57cd23b166089759ef6eabd
-
-
- cicero.res_publica.id
- 1EtE77Aa5AA8etzF2irk56vvkS4v7rZ7PE
- 7e4ac75f9d79ba9d5d284fac19617497433b832d
-
-
- podsaveamerica.verified.podcast
- 1MwPD6dH4fE3gQ9mCov81L1DEQWT7E85qH
- 0d6f090db8945aa0e60759f9c866b17645893a95
-
-
-
-
-
In practice, the zone file hash is the RIPEMD160 hash of the SHA256 hash of
-the zone file, and the public key is the base58check-encoded RIPEMD160 hash
-of the double-SHA256 hash of the ECDSA public key (i.e. a Bitcoin address).
-
-
The BNS consensus rules ensure that
-a BNS name can only be registered if it is not already taken, and that only the
-user who owns the name’s private key can change its public key hash or zone file
-hash. This means that a name’s public key and zone file can be stored anywhere,
-since they can be authenticated using the hashes discovered by indexing the
-blockchain under the BNS consensus rules.
-
-
BNS nodes implement a decentralized storage system for zone files called the
-Atlas network . In this system, BNS nodes eagerly replicate
-all the zone files they know about to one another, so that eventually every BNS
-node has a full replica of all zone files.
-
-
The public keys for names are stored off-chain in Gaia .
-The user controls where their public keys are hosted using the zone file
-contents (if they are hosted online anywhere at all).
-
-
Developers can query this table via the BNS API. The API offers routes
-to do the following:
-
-
Look up a name’s public key and zone file (reference )
-
-
$ curl https://core.blockstack.org/v1/names/muneeb.id
-{
- "address" : "1J3PUxY5uDShUnHRrMyU6yKtoHEUPhKULs" ,
- "blockchain" : "bitcoin" ,
- "expire_block" : 599266,
- "last_txid" : "7e16e8688ca0413a398bbaf16ad4b10d3c9439555fc140f58e5ab4e50793c476" ,
- "status" : "registered" ,
- "zonefile" : " $ORIGIN muneeb.id \n $TTL 3600 \n _http._tcp URI 10 1 \" https://gaia.blockstack.org/hub/1J3PUxY5uDShUnHRrMyU6yKtoHEUPhKULs/0/profile.json \"\n " ,
- "zonefile_hash" : "37aecf837c6ae9bdc9dbd98a268f263dacd00361"
-}
-
-
-
-
Note that the zonefile field is given with the off-chain data that hashes
-to the zonefile_hash field.
-
-
List all names the node knows about (reference )
-
-
$ curl https://core.blockstack.org/v1/names?page= 0
-[
- "judecn.id" ,
- "3.id" ,
- "4.id" ,
- "8.id" ,
- "e.id" ,
- "h.id" ,
- "5.id" ,
- "9.id" ,
- "i.id" ,
- "l.id" ,
- "p.id" ,
- "w.id" ,
- "ba.id" ,
- "df.id" ,
-...
-]
-
-
-
-
Each page returns 100 names. While no specific ordering is mandated by the
-protocol, the reference implementation orders names by their order of creation
-in the blockchain.
-
-
Look up the history of states a name was in (reference )
-
-
$ curl https://core.blockstack.org/v1/names/patrickstanley.id/history
-{
- "445838" : [
- {
- "address" : "1occgbip7tFDXX9MvzQhcnTUUjcVX2dYK" ,
- "block_number" : 445838,
- "burn_address" : "1111111111111111111114oLvT2" ,
- "consensus_hash" : "7b696b6f4060b792d41912068944d73b" ,
- "op" : "?" ,
- "op_fee" : 25000,
- "opcode" : "NAME_PREORDER" ,
- "preorder_hash" : "26bf7874706ac761afdd403ed6b3b9578fb01a34" ,
- "sender" : "76a91408d0dd44c1f0a3a4f0957ae95901929d7d66d55788ac" ,
- "sender_pubkey" : "039a8948d339ecbff44cf426cb85d90fce876f1658d385cdc47f007f279be626ea" ,
- "txid" : "6730ae09574d5935ffabe3dd63a9341ea54fafae62fde36c27738e9ee9c4e889" ,
- "vtxindex" : 40
- }
- ] ,
- "445851" : [
- {
- "address" : "17CbHgTgBG3kLedXNneEKBkCTgW2fyrnUD" ,
- "block_number" : 445838,
- "consensus_hash" : null,
- "first_registered" : 445851,
- "importer" : null,
- "importer_address" : null,
- "last_creation_op" : "?" ,
- "last_renewed" : 445851,
- "name" : "patrickstanley.id" ,
- "name_hash128" : "683a3e1ee5f0296833c56e481cf41b77" ,
- "namespace_block_number" : 373601,
- "namespace_id" : "id" ,
- "op" : ":" ,
- "op_fee" : 25000,
- "opcode" : "NAME_REGISTRATION" ,
- "preorder_block_number" : 445838,
- "preorder_hash" : "26bf7874706ac761afdd403ed6b3b9578fb01a34" ,
- "revoked" : false ,
- "sender" : "76a9144401f3be5311585ea519c1cb471a8dc7b02fd6ee88ac" ,
- "sender_pubkey" : "039a8948d339ecbff44cf426cb85d90fce876f1658d385cdc47f007f279be626ea" ,
- "transfer_send_block_id" : null,
- "txid" : "55b8b42fc3e3d23cbc0f07d38edae6a451dfc512b770fd7903725f9e465b2925" ,
- "value_hash" : null,
- "vtxindex" : 54
- }
- ] ,
- "445873" : [
- {
- "address" : "17CbHgTgBG3kLedXNneEKBkCTgW2fyrnUD" ,
- "block_number" : 445838,
- "consensus_hash" : "18b8d69f0182b89ccb1aa536f83be18a" ,
- "first_registered" : 445851,
- "importer" : null,
- "importer_address" : null,
- "last_creation_op" : "?" ,
- "last_renewed" : 445851,
- "name" : "patrickstanley.id" ,
- "name_hash128" : "683a3e1ee5f0296833c56e481cf41b77" ,
- "namespace_block_number" : 373601,
- "namespace_id" : "id" ,
- "op" : "+" ,
- "op_fee" : 25000,
- "opcode" : "NAME_UPDATE" ,
- "preorder_block_number" : 445838,
- "preorder_hash" : "26bf7874706ac761afdd403ed6b3b9578fb01a34" ,
- "revoked" : false ,
- "sender" : "76a9144401f3be5311585ea519c1cb471a8dc7b02fd6ee88ac" ,
- "sender_pubkey" : "039a8948d339ecbff44cf426cb85d90fce876f1658d385cdc47f007f279be626ea" ,
- "transfer_send_block_id" : null,
- "txid" : "dc478659fc684a1a6e1e09901971e82de11f4dfe2b32a656700bf9a3b6030719" ,
- "value_hash" : "02af0ef21161ad06b0923106f40b994b9e4c1614" ,
- "vtxindex" : 95
- }
- ] ,
- "445884" : [
- {
- "address" : "1GZqrVbamkaE6YNveJFWK6cDrCy6bXyS6b" ,
- "block_number" : 445838,
- "consensus_hash" : "18b8d69f0182b89ccb1aa536f83be18a" ,
- "first_registered" : 445851,
- "importer" : null,
- "importer_address" : null,
- "last_creation_op" : "?" ,
- "last_renewed" : 445851,
- "name" : "patrickstanley.id" ,
- "name_hash128" : "683a3e1ee5f0296833c56e481cf41b77" ,
- "namespace_block_number" : 373601,
- "namespace_id" : "id" ,
- "op" : ">>" ,
- "op_fee" : 25000,
- "opcode" : "NAME_TRANSFER" ,
- "preorder_block_number" : 445838,
- "preorder_hash" : "26bf7874706ac761afdd403ed6b3b9578fb01a34" ,
- "revoked" : false ,
- "sender" : "76a914aabffa6dd90d731d3a349f009323bb312483c15088ac" ,
- "sender_pubkey" : null,
- "transfer_send_block_id" : 445875,
- "txid" : "7a0a3bb7d39b89c3638abc369c85b5c028d0a55d7804ba1953ff19b0125f3c24" ,
- "value_hash" : "02af0ef21161ad06b0923106f40b994b9e4c1614" ,
- "vtxindex" : 16
- }
- ]
-}
-
-
-
-
All of the above information is extracted from the blockchain. Each top-level
-field encodes the states the name transitioned to at the given block height (e.g.
-445838, 445851, 445873, adn 445884). At each block height, the name’s zone file
-hashes are returned in the order they were discovered in the blockchain.
-
-
Each name state contains a lot of ancillary data that is used internally by
-other API calls and client libraries. The relevant fields for this document’s
-scope are:
-
-
- address: This is the base58check-encoded public key hash.
- name: This is the name queried.
- value_hash: This is the zone file hash.
- opcode: This is the type of transaction that was processed.
- txid: This is the transaction ID in the underlying blockchain.
-
-
-
The name’s entire history is returned. This includes the history of the name
-under its previous owner, if the name expired and was reregistered.
-
-
Look up the list of names owned by a given public key hash (reference )
-
-
$ curl https://core.blockstack.org/v1/addresses/bitcoin/16EMaNw3pkn3v6f2BgnSSs53zAKH4Q8YJg
-{
- "names" : [
- "judecn.id" ,
- "patrickstanley1.id" ,
- "abcdefgh123456.id" ,
- "duckduckgo_tor.id" ,
- "jude.id" ,
- "blockstacknewyear2017.id" ,
- "jude.statism.id"
- ]
-}
-
-
-
-
Note that this API endpoint includes names and
-subdomains .
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Related Articles
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Blockstack
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/_site/core/naming/subdomains.html b/_site/core/naming/subdomains.html
deleted file mode 100644
index ea8d246713..0000000000
--- a/_site/core/naming/subdomains.html
+++ /dev/null
@@ -1,715 +0,0 @@
-
-
-
-
-
-
-
-
-
BNS Subdomains | Blockstack
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- BNS Subdomains
-
-
-
-
-
-
-
-
This section explains BNS subdomains and provides instructions for methods
-you can use to work with them. The following topics are included:
-
-
-
-
Overview of subdomains
-
-
BNS names are strongly-owned because the owner of its private key can generate
-valid transactions that update its zone file hash and owner. However, this comes at the
-cost of requiring a name owner to pay for the underlying transaction in the
-blockchain. Moreover, this approach limits the rate of BNS name registrations
-and operations to the underlying blockchain’s transaction bandwidth.
-
-
BNS overcomes this with subdomains. A BNS subdomain is a type of BNS name whose state
-and owner are stored outside of the blockchain, but whose existence and
-operation history are anchored to the
-blockchain. In the example table in the Resolving BNS
-Names section, the names cicero.res_publica.id and
-podsaveamerica.verified.podcast are subdomains.
-
-
Like their on-chain counterparts, subdomains are globally
-unique, strongly-owned, and human-readable. BNS gives them their own name state
-and public keys.
-
-
Unlike on-chain names, subdomains can be created and managed
-cheaply, because they are broadcast to the
-BNS network in batches. A single blockchain transaction can send up to 120
-subdomain operations.
-
-
This is achieved by storing subdomain records in the Atlas Network .
-An on-chain name owner broadcasts subdomain operations by encoding them as
-TXT records within a DNS zone file. To broadcast the zone file,
-the name owner sets the new zone file hash with a NAME_UPDATE transaction and
-replicates the zone file via Atlas. This, in turn, replicates all subdomain
-operations it contains, and anchors the set of subdomain operations to
-an on-chain transaction. The BNS node’s consensus rules ensure that only
-valid subdomain operations from valid NAME_UPDATE transactions will ever be
-stored.
-
-
For example, the name verified.podcast once wrote the zone file hash 247121450ca0e9af45e85a82e61cd525cd7ba023,
-which is the hash of the following zone file:
-
-
$ curl -sL https://core.blockstack.org/v1/names/verified.podcast/zonefile/247121450ca0e9af45e85a82e61cd525cd7ba023 | jq -r '.zonefile'
-$ORIGIN verified.podcast
-$TTL 3600
-1yeardaily TXT "owner=1MwPD6dH4fE3gQ9mCov81L1DEQWT7E85qH" "seqn=0" "parts=1" "zf0=JE9SSUdJTiAxeWVhcmRhaWx5CiRUVEwgMzYwMApfaHR0cC5fdGNwIFVSSSAxMCAxICJodHRwczovL3BoLmRvdHBvZGNhc3QuY28vMXllYXJkYWlseS9oZWFkLmpzb24iCg=="
-2dopequeens TXT "owner=1MwPD6dH4fE3gQ9mCov81L1DEQWT7E85qH" "seqn=0" "parts=1" "zf0=JE9SSUdJTiAyZG9wZXF1ZWVucwokVFRMIDM2MDAKX2h0dHAuX3RjcCBVUkkgMTAgMSAiaHR0cHM6Ly9waC5kb3Rwb2RjYXN0LmNvLzJkb3BlcXVlZW5zL2hlYWQuanNvbiIK"
-10happier TXT "owner=1MwPD6dH4fE3gQ9mCov81L1DEQWT7E85qH" "seqn=0" "parts=1" "zf0=JE9SSUdJTiAxMGhhcHBpZXIKJFRUTCAzNjAwCl9odHRwLl90Y3AgVVJJIDEwIDEgImh0dHBzOi8vcGguZG90cG9kY2FzdC5jby8xMGhhcHBpZXIvaGVhZC5qc29uIgo="
-31thoughts TXT "owner=1MwPD6dH4fE3gQ9mCov81L1DEQWT7E85qH" "seqn=0" "parts=1" "zf0=JE9SSUdJTiAzMXRob3VnaHRzCiRUVEwgMzYwMApfaHR0cC5fdGNwIFVSSSAxMCAxICJodHRwczovL3BoLmRvdHBvZGNhc3QuY28vMzF0aG91Z2h0cy9oZWFkLmpzb24iCg=="
-359 TXT "owner=1MwPD6dH4fE3gQ9mCov81L1DEQWT7E85qH" "seqn=0" "parts=1" "zf0=JE9SSUdJTiAzNTkKJFRUTCAzNjAwCl9odHRwLl90Y3AgVVJJIDEwIDEgImh0dHBzOi8vcGguZG90cG9kY2FzdC5jby8zNTkvaGVhZC5qc29uIgo="
-30for30 TXT "owner=1MwPD6dH4fE3gQ9mCov81L1DEQWT7E85qH" "seqn=0" "parts=1" "zf0=JE9SSUdJTiAzMGZvcjMwCiRUVEwgMzYwMApfaHR0cC5fdGNwIFVSSSAxMCAxICJodHRwczovL3BoLmRvdHBvZGNhc3QuY28vMzBmb3IzMC9oZWFkLmpzb24iCg=="
-onea TXT "owner=1MwPD6dH4fE3gQ9mCov81L1DEQWT7E85qH" "seqn=0" "parts=1" "zf0=JE9SSUdJTiBvbmVhCiRUVEwgMzYwMApfaHR0cC5fdGNwIFVSSSAxMCAxICJodHRwczovL3BoLmRvdHBvZGNhc3QuY28vb25lYS9oZWFkLmpzb24iCg=="
-10minuteteacher TXT "owner=1MwPD6dH4fE3gQ9mCov81L1DEQWT7E85qH" "seqn=0" "parts=1" "zf0=JE9SSUdJTiAxMG1pbnV0ZXRlYWNoZXIKJFRUTCAzNjAwCl9odHRwLl90Y3AgVVJJIDEwIDEgImh0dHBzOi8vcGguZG90cG9kY2FzdC5jby8xMG1pbnV0ZXRlYWNoZXIvaGVhZC5qc29uIgo="
-36questionsthepodcastmusical TXT "owner=1MwPD6dH4fE3gQ9mCov81L1DEQWT7E85qH" "seqn=0" "parts=1" "zf0=JE9SSUdJTiAzNnF1ZXN0aW9uc3RoZXBvZGNhc3RtdXNpY2FsCiRUVEwgMzYwMApfaHR0cC5fdGNwIFVSSSAxMCAxICJodHRwczovL3BoLmRvdHBvZGNhc3QuY28vMzZxdWVzdGlvbnN0aGVwb2RjYXN0bXVzaWNhbC9oZWFkLmpzb24iCg=="
-_http._tcp URI 10 1 "https://dotpodcast.co/"
-
-
-
-
Each TXT record in this zone file encodes a subdomain-creation.
-For example, 1yeardaily.verified.podcast resolves to:
-
-
$ curl https://core.blockstack.org/v1/names/1yeardaily.verified.podcast
-{
- "address" : "1MwPD6dH4fE3gQ9mCov81L1DEQWT7E85qH" ,
- "blockchain" : "bitcoin" ,
- "last_txid" : "d87a22ebab3455b7399bfef8a41791935f94bc97aee55967edd5a87f22cce339" ,
- "status" : "registered_subdomain" ,
- "zonefile_hash" : "e7acc97fd42c48ed94fd4d41f674eddbee5557e3" ,
- "zonefile_txt" : " $ORIGIN 1yeardaily \n $TTL 3600 \n _http._tcp URI 10 1 \" https://ph.dotpodcast.co/1yeardaily/head.json \"\n "
-}
-
-
-
-
This information was extracted from the 1yeardaily TXT resource record in the zone
-file for verified.podcast.
-
-
Subdomain Lifecycle
-
-
Note that 1yeardaily.verified.podcast has a different public key
-hash (address) than verified.podcast. A BNS node will only process a
-subsequent subdomain operation on 1yeardaily.verified.podcast if it includes a
-signature from this address’s private key. verified.podcast cannot generate
-updates; only the owner of 1yeardaily.verified.podcast can do so.
-
-
The lifecycle of a subdomain and its operations is shown in Figure 2.
-
-
subdomain subdomain subdomain
- creation update transfer
-+----------------+ +----------------+ +----------------+
-| cicero | | cicero | | cicero |
-| owner="1Et..." | signed | owner="1Et..." | signed | owner="1cJ..." |
-| zf0="7e4..." |<--------| zf0="111..." |<--------| zf0="111..." |<---- ...
-| seqn=0 | | seqn=1 | | seqn=2 |
-| | | sig="xxxx" | | sig="xxxx" |
-+----------------+ +----------------+ +----------------+
- | | |
- | off-chain | |
-~ ~ ~ ~ | ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~|~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | ~ ~ ~ ~ ~ ~ ~ ...
- | on-chain | |
- V V (zone file hash ) V
-+----------------+ +----------------+ +----------------+
-| res_publica.id | | jude.id | | res_publica.id |
-| NAME_UPDATE |<--------| NAME_UPDATE |<--------| NAME_UPDATE |<---- ...
-+----------------+ +----------------+ +----------------+
- blockchain blockchain blockchain
- block block block
-
-
-Figure 2: Subdomain lifetime with respect to on-chain name operations. A new
-subdomain operation will only be accepted if it has a later "sequence=" number,
-and a valid signature in "sig=" over the transaction body. The "sig=" field
-includes both the public key and signature, and the public key must hash to
-the previous subdomain operation's "addr=" field.
-
-Thesubdomain-creation and subdomain-transfer transactions for
-"cicero.res_publica.id" are broadcast by the owner of "res_publica.id".
-However, any on-chain name ("jude.id" in this case) can broadcast a subdomain
-update for "cicero.res_publica.id".
-
-
-
-
Subdomain operations are ordered by sequence number, starting at 0. Each new
-subdomain operation must include:
-
-
- The next sequence number
- The public key that hashes to the previous subdomain transaction’s address
- A signature from the corresponding private key over the entire subdomain
-operation.
-
-
-
If two correctly-signed but conflicting subdomain operations are discovered
-(i.e. they have the same sequence number), the one that occurs earlier in the
-blockchain’s history is accepted. Invalid subdomain operations are ignored.
-
-
Combined, this ensures that a BNS node with all of the zone files with a given
-subdomain’s operations will be able to determine the valid sequence of
-state-transitions it has undergone, and determine the current zone file and public
-key hash for the subdomain.
-
-
Resolving Subdomains
-
-
Developers interact with subdomains the same way they interact with names.
-Using the BNS API, a developer can:
-
-
Look up a subdomain’s public key and zone file (reference )
-
-
$ curl https://core.blockstack.org/v1/names/aaron.personal.id
-{
- "address" : "1PwztPFd1s2STMv4Ntq6UPBdYgHSBr5pdF" ,
- "blockchain" : "bitcoin" ,
- "last_txid" : "85e8273b0a38d3e9f0af7b4b72faf0907de9f4616afc101caac13e7bbc832394" ,
- "status" : "registered_subdomain" ,
- "zonefile_hash" : "a6dda6b74ffecf85f4a162627d8df59577243813" ,
- "zonefile_txt" : " $ORIGIN aaron.personal.id \n $TTL 3600 \n _https._tcp URI 10 1 \" https://gaia.blockstack.org/hub/1PwztPFd1s2STMv4Ntq6UPBdYgHSBr5pdF/profile.json \"\n "
-}
-
-
-
-
Look up a subdomain’s transaction history (reference )
-
-
$ curl https://core.blockstack.org/v1/names/aaron.personal.id/history
-{
- "509981" : [
- {
- "address" : "1PwztPFd1s2STMv4Ntq6UPBdYgHSBr5pdF" ,
- "block_number" : 509981,
- "domain" : "personal.id" ,
- "name" : "aaron.personal.id" ,
- "sequence" : 0,
- "txid" : "85e8273b0a38d3e9f0af7b4b72faf0907de9f4616afc101caac13e7bbc832394" ,
- "value_hash" : "a6dda6b74ffecf85f4a162627d8df59577243813" ,
- "zonefile" : "JE9SSUdJTiBhYXJvbi5wZXJzb25hbC5pZAokVFRMIDM2MDAKX2h0dHBzLl90Y3AgVVJJIDEwIDEgImh0dHBzOi8vZ2FpYS5ibG9ja3N0YWNrLm9yZy9odWIvMVB3enRQRmQxczJTVE12NE50cTZVUEJkWWdIU0JyNXBkRi9wcm9maWxlLmpzb24iCg=="
- }
- ]
-}
-
-
-
-
Look up the list of names and subdomains owned by a given public key hash (reference )
-
-
$ curl https://core.blockstack.org/v1/addresses/bitcoin/1PwztPFd1s2STMv4Ntq6UPBdYgHSBr5pdF
-{
- "names" : [
- "aaron.personal.id"
- ]
-}
-
-
-
-
Subdomain Creation and Management
-
-
Unlike an on-chain name, a subdomain owner needs an on-chain name owner’s help
-to broadcast their subdomain operations. In particular:
-
- A subdomain-creation transaction can only be processed by the owner of the on-chain
-name that shares its suffix. For example, only the owner of res_publica.id
-can broadcast subdomain-creation transactions for subdomain names ending in
-.res_publica.id.
- A subdomain-transfer transaction can only be broadcast by the owner of the
-on-chain name that created it. For example, the owner of
-cicero.res_publica.id needs the owner of res_publica.id to broadcast a
-subdomain-transfer transaction to change cicero.res_publica.id’s public key.
- In order to send a subdomain-creation or subdomain-transfer, all
-of an on-chain name owner’s zone files must be present in the Atlas network.
-This lets the BNS node prove the absence of any conflicting subdomain-creation and
-subdomain-transfer operations when processing new zone files.
- A subdomain update transaction can be broadcast by any on-chain name owner,
-but the subdomain owner needs to find one who will cooperate. For example,
-the owner of verified.podcast can broadcast a subdomain-update transaction
-created by the owner of cicero.res_publica.id.
-
-
-
That said, to create a subdomain, the subdomain owner generates a
-subdomain-creation operation for their desired name
-and gives it to the on-chain name owner.
-The on-chain name owner then uses Atlas to
-broadcast it to all other BNS nodes.
-
-
Once created, a subdomain owner can use any on-chain name owner to broadcast a
-subdomain-update operation. To do so, they generate and sign the requisite
-subdomain operation and give it to an on-chain name owner, who then packages it
-with other subdomain operations into a DNS zone file
-and sends them all out on the Atlas network.
-
-
If the subdomain owner wants to change the address of their subdomain, they need
-to sign a subdomain-transfer operation and give it to the on-chain name owner
-who created the subdomain. They then package it into a zone file and broadcast
-it.
-
-
Subdomain Registrars
-
-
Because subdomain names are cheap, developers may be inclined to run
-subdomain registrars on behalf of their applications. For example,
-the name personal.id is used to register Blockstack application users without
-requiring them to spend any Bitcoin.
-
-
We supply a reference
-implementation of a BNS Subdomain Registrar
-to help developers broadcast subdomain operations. Users would still own their
-subdomain names; the registrar simply gives developers a convenient way for them
-to register and manage them in the context of a particular application.
-Please see the tutorial on running a subdomain registrar for
-details on how to use it.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Related Articles
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Blockstack
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/_site/core/naming/tutorial_creation.html b/_site/core/naming/tutorial_creation.html
deleted file mode 100644
index 3ab7dc0b75..0000000000
--- a/_site/core/naming/tutorial_creation.html
+++ /dev/null
@@ -1,1098 +0,0 @@
-
-
-
-
-
-
-
-
-
Creating a Namespace | Blockstack
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Creating a Namespace
-
-
-
-
-
-
-
-
This tutorial teaches you how to create your namespace, it contains the
-following sections:
-
-
-
-
Creating namespaces is expensive.
-Be sure to test your namespace in our integration test
-framework
-first! It will let you simulate any valid namespace configuration
-you want at no risk to you.
-
-
- WARNING : If you intend to create a namespace, you must read this document
-in its entirety . You should also install the test framework and experiment
-with your namespace’s parameters. FAILURE TO DO SO MAY RESULT IN IRRECOVERABLE
-LOSS OF FUNDS.
-
-
-
Before you begin
-
-
Some basic familiarity with how Bitcoin works is required to
-understand this tutorial. This includes:
-
-
- knowing the difference between mainnet, testnet, and regtest
- knowing about compressed and uncompressed ECDSA public keys
- knowing about base58-check encoding
- knowing how Bitcoin transactions are structured
- knowing how UTXOs work
-
-
-
Creating a namespace is a three-step process. The first step is to preorder
-the namespace, which broadcasts a salted hash of the namespace ID. The second
-step is to reveal the namespace, which exposes the namespace ID and price
-function to the blockchain. The final step is to ready the namespace, which
-allows anyone to register names within it.
-
-
In between the reveal and ready steps, the namespace creator will have a
-“lock” on the namespace that lasts for about 1 year. During this time period,
-the namespace creator can import names. The import transaction lets the
-namespace creator assign the name a zone file and an owner in one step.
-
-
Before Trying This in Production…
-
-
Setting up the Test Environment
-
-
In this example, we will use the test framework to create a private Bitcoin
-blockchain on your computer, and then create a Blockstack namespace on it.
-This will let you experiment with different namespace parameters
-without spending actual BTC. The test framework uses bitcoind -regtest,
-so all of the commands you’ll run here will work identically on
-mainnet.
-
-
To install the test framework, please follow these
-instructions .
-Once you have the test framework installed, you should run the namespace_check test in --interactive-web mode.
-This will create an empty .test namespace and leave the test scenario running
-once it finishes. You will be able to fund addresses and create new blocks via
-your Web browser or via curl, as will be explained below. Also, you’ll be able to use the
-blockstack utility to interact with your private blockchain and namespaces.
-
-
The test setup command is as follows. This will launch the namespace_check
-test scenario, and open a web server on port 3001.
-
$ blockstack-test-scenario --interactive-web 3001 blockstack_integration_tests.scenarios.namespace_check
-
-
-
-
When the test is ready for us to experiment, you should see the following:
-
-
An empty namespace called 'test' has been created
- Feel free to experiment with other namespaces
-
- Available keys with a balance:
- * 6e50431b955fe73f079469b24f06480aee44e4519282686433195b3c4b5336ef01
- * c244642ce0b4eb68da8e098facfcad889e3063c36a68b7951fb4c085de49df1b01
- * f4c3907cb5769c28ff603c145db7fc39d7d26f69f726f8a7f995a40d3897bb5201
- * 8f87d1ea26d03259371675ea3bd31231b67c5df0012c205c154764a124f5b8fe01
- * bb68eda988e768132bc6c7ca73a87fb9b0918e9a38d3618b74099be25f7cab7d01
- * 2,3,6f432642c087c2d12749284d841b02421259c4e8178f25b91542c026ae6ced6d01,65268e6267b14eb52dc1ccc500dc2624a6e37d0a98280f3275413eacb1d2915d01,cdabc10f1ff3410082448b708c0f860a948197d55fb612cb328d7a5cc07a6c8a01
- * 2,3,4c3ab2a0704dfd9fdc319cff2c3629b72ebda1580316c7fddf9fad1baa323e9601,75c9f091aa4f0b1544a59e0fce274fb1ac29d7f7e1cd020b66f941e5d260617b01,d62af1329e541871b244c4a3c69459e8666c40b683ffdcb504aa4adc6a559a7701
- * 2,3,4b396393ca030b21bc44a5eba1bb557d04be1bfe974cbebc7a2c82b4bdfba14101,d81d4ef8123852403123d416b0b4fb25bcf9fa80e12aadbc08ffde8c8084a88001,d0482fbe39abd9d9d5c7b21bb5baadb4d50188b684218429f3171da9de206bb201
- * 2,3,836dc3ac46fbe2bcd379d36b977969e5b6ef4127e111f2d3e2e7fb6f0ff1612e01,1528cb864588a6a5d77eda548fe81efc44180982e180ecf4c812c6be9788c76a01,9955cfdac199b8451ccd63ec5377a93df852dc97ea01afc47db7f870a402ff0501
-
-
-
-
You can determine that the test framework is live by going to
-http://localhost:3001 in your Web browser. From there, you can generate
-blocks in the test framework’s bitcoind node and you can fund any address in
-the test framework.
-
-
Finally, you can use the blockstack-test-env command to set up your shell
-environment variables so blockstack will interact with this test (instead of
-mainnet). To do so, run the following in your shell:
-
-
$ . $( which blockstack-test-env) namespace_check
- |blockstack-test namespace_check| $
-
-
-
-
You can verify that the environment variables by verifying that your $PS1
-variable includes the name of your test (as shown above), and that some other
-BLOCKSTACK_-prefixed variables are set:
-
-
|blockstack-test namespace_check| $ env | grep BLOCKSTACK
- BLOCKSTACK_OLD_PS1 = \u @\h :\w $
- BLOCKSTACK_TESTNET = 1
- BLOCKSTACK_EPOCH_1_END_BLOCK = 1
- BLOCKSTACK_EPOCH_2_END_BLOCK = 2
- BLOCKSTACK_TEST = 1
- BLOCKSTACK_DEBUG = 1
- BLOCKSTACK_CLIENT_CONFIG = /tmp/blockstack-run-scenario.blockstack_integration_tests.scenarios.namespace_check/client/client.ini
-
-
-
-
Registering a Namespace
-
-
Suppose we’re going to create the hello namespace. The key
-6e50431b955fe73f079469b24f06480aee44e4519282686433195b3c4b5336ef01 will be the key that
-pays for the namespace. The key
-c244642ce0b4eb68da8e098facfcad889e3063c36a68b7951fb4c085de49df1b01 will be the key that
-creates the namespace. The creator key will be used to import names and
-declare the namespace ready. The payment key will be used to both pay for the
-namespace and receive name registration and renewal fees for the first year of
-the namespace’s lifetime.
-
-
In this example, we will set these keys as environment variables:
-
-
|blockstack-test namespace_check| $ export PAYMENT_PKEY = "6e50431b955fe73f079469b24f06480aee44e4519282686433195b3c4b5336ef01"
- |blockstack-test namespace_check| $ export CREATOR_PKEY = "c244642ce0b4eb68da8e098facfcad889e3063c36a68b7951fb4c085de49df1b01"
-
-
-
-
Multisig Namespace Payment
-
-
If you want to use a multisig address to pay for your namespace (and collect
-name registration fees), then instead of using
-6e50431b955fe73f079469b24f06480aee44e4519282686433195b3c4b5336ef01, you should
-use a string formatted as m,n,pk1,pk2,...,pk_n. m is the number of
-signatures required, n is the number of private keys, and pk1,pk2,...,pk_n
-are the private keys.
-
-
For example, you can use the following as your PAYMENT_PKEY to have a 2-of-3
-multisig script pay for your namespace and collect name registration fees:
-
-
|blockstack-test namespace_check| $ export PAYMENT_PKEY = "2,3,6f432642c087c2d12749284d841b02421259c4e8178f25b91542c026ae6ced6d01,65268e6267b14eb52dc1ccc500dc2624a6e37d0a98280f3275413eacb1d2915d01,cdabc10f1ff3410082448b708c0f860a948197d55fb612cb328d7a5cc07a6c8a01"
-
-
-
-
Namespace preorder
-
-
The command to preorder the namespace would be:
-
-
|blockstack-test namespace_check| $ blockstack namespace_preorder hello " $PAYMENT_PKEY " " $CREATOR_PKEY "
-
-
-
-
You will be given a set of instructions on how to proceed to reveal and
-launch the namespace. READ THEM CAREFULLY . You will be prompted to
-explicitly acknowledge that you understand the main points of the instructions,
-and that you understand the risks.
-
-
The command outputs some necessary information at the very end of its execution.
-In particular, you will need to remember the transaction ID of the namespace
-preorder. The command will help you do so.
-
-
Here is a sample output:
-
-
|blockstack-test namespace_check| $ blockstack namespace_preorder hello " $PAYMENT_PKEY " " $CREATOR_PKEY "
-
- <...snip...>
-
- Remember this transaction ID: b40dd1375ef63e5a40ee60d790ec6dccd06efcbac99d0cd5f3b07502a4ab05ac
- You will need it for ` blockstack namespace_reveal`
-
- Wait until b40dd1375ef63e5a40ee60d790ec6dccd06efcbac99d0cd5f3b07502a4ab05ac has six ( 6) confirmations. Then, you can reveal ` hello` with:
-
- $ blockstack namespace_reveal "hello" "6e50431b955fe73f079469b24f06480aee44e4519282686433195b3c4b5336ef01" "c244642ce0b4eb68da8e098facfcad889e3063c36a68b7951fb4c085de49df1b01" "b40dd1375ef63e5a40ee60d790ec6dccd06efcbac99d0cd5f3b07502a4ab05ac"
-
- {
- "status" : true ,
- "success" : true ,
- "transaction_hash" : "b40dd1375ef63e5a40ee60d790ec6dccd06efcbac99d0cd5f3b07502a4ab05ac"
- }
-
-
-
-
If all goes well, you will get back a transaction hash (in this case, b40dd1375ef63e5a40ee60d790ec6dccd06efcbac99d0cd5f3b07502a4ab05ac).
-To get Blockstack to process it, you will need to mine some blocks in the test framework (by default,
-Blockstack will only accept a transaction that has 6 confirmations). To do
-this, simply go to http://localhost:3001 and generate at least 6 blocks. If you
-observe the test log, you will see the Blockstack node process and accept it.
-
-
Note that when you do this live, you should wait for
-at least 10 confirmations before sending the reveal transaction, just to be
-safe.
-
-
Namespace reveal
-
-
The command to reveal a preordered namespace is more complicated, since it
-describes the price curve.
-
-
This command is interactive . The command to invoke it is as follows:
-
-
|blockstack-test namespace_check| $ blockstack namespace_reveal hello " $PAYMENT_PKEY " " $CREATOR_PKEY " "b40dd1375ef63e5a40ee60d790ec6dccd06efcbac99d0cd5f3b07502a4ab05ac"
-
-
-
-
When running the command, you will see the namespace creation wizard prompt you
-with the price curve and the current values:
-
-
Name lifetimes (blocks): infinite
-Price coefficient: 4
-Price base: 4
-Price bucket exponents: [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
-Non-alpha discount: 2
-No-vowel discount: 5
-Burn or receive fees? Receive to mr6nrMvvh44sR5MiX929mMXP5hqgaTr6fx
-
-Name price formula:
-(UNIT_COST = 10.0 satoshi):
- buckets[min(len(name)-1, 15)]
- UNIT_COST * coeff * base
-cost(name) = -----------------------------------------------------
- max(nonalpha_discount, no_vowel_discount)
-
-
-Name price table:
-| length | price | price, nonalpha | price, no vowel | price, both |
---------------------------------------------------------------------------
-| 1 | 42949672960 | 8589934592 | 8589934592 | 8589934592 |
-| 2 | 10737418240 | 5368709120 | 2147483648 | 2147483648 |
-| 3 | 2684354560 | 1342177280 | 536870912 | 536870912 |
-| 4 | 671088640 | 335544320 | 134217728 | 134217728 |
-| 5 | 167772160 | 83886080 | 33554432 | 33554432 |
-| 6 | 41943040 | 20971520 | 8388608 | 8388608 |
-| 7 | 10485760 | 5242880 | 2097152 | 2097152 |
-| 8 | 2621440 | 1310720 | 524288 | 524288 |
-| 9 | 655360 | 327680 | 131072 | 131072 |
-| 10 | 163840 | 81920 | 32768 | 32768 |
-| 11 | 40960 | 20480 | 8192 | 8192 |
-| 12 | 10240 | 5120 | 2048 | 2048 |
-| 13 | 2560 | 1280 | 512 | 512 |
-| 14 | 640 | 320 | 128 | 128 |
-| 15 | 160 | 80 | 32 | 32 |
-| 16+ | 40 | 20 | 10 | 10 |
-
-
-What would you like to do?
-(0) Set name lifetime in blocks (positive integer between 1 and 4294967295, or "infinite")
-(1) Set price coefficient (positive integer between 1 and 255)
-(2) Set base price (positive integer between 1 and 255)
-(3) Set price bucket exponents (16 comma-separated integers, each between 1 and 15)
-(4) Set non-alphanumeric character discount (positive integer between 1 and 15)
-(5) Set no-vowel discount (positive integer between 1 and 15)
-(6) Toggle collecting name fees (True: receive fees; False: burn fees)
-(7) Show name price formula
-(8) Show price table
-(9) Done
-
-(1-9)
-
-
-
-
All prices are in the “fundamental unit” of the underlying blockchain (i.e.
-satoshis).
-
-
As the formula describes, the name’s price is a function of:
-
-
- a fixed unit cost (UNIT_COST)
- a multiplicative constant coefficient (coeff)
- a fixed exponential base (base)
- a 16-element list of price buckets, indexed by the length of the name (buckets)
- a discount for having non-alphnumeric letters (nonalpha_discount)
- a discount for having no vowels in the name (no_vowel_discount)
-
-
-
You can use options 1 through 8 to play with the pricing function and examine
-the name costs in the price table. Enter 9 to send the transaction itself.
-
-
Once you’re happy, you can issue the namespace-reveal transaction. As with the
-namespace-preorder transaction, you will get back a transaction hash, and your transaction will be
-unconfirmed. Simply go to http://localhost:3001 to generate some more blocks
-to confirm your namespace-reveal.
-
-
Once you have confirmed your namespace-reveal transaction, you can
-begin to populate your namespace with some initial names.
-
-
Collecting Name Fees
-
-
Blockstack 0.17 introduced the ability to create a namespace such that for the
-first year of its existence (54595 blocks), all name registration and renewal
-fees will be sent to the address of the payment key . In this example,
-this is the address mr6nrMvvh44sR5MiX929mMXP5hqgaTr6fx.
-
-
The alternative is to
-have all namespace fees sent to an unspendable burn address
-(1111111111111111111114oLvT2). This is the case for the .id namespace,
-for example.
-
-
After the year has passed, all future name registrations and renewal fees
-will be sent to the unspendable burn address. This is to disincentivize
-namespace squatters.
-
-
Warnings
-
-
- You must issue this command within 144 blocks of the namespace-preorder transaction. Otherwise, the preorder will expire and you will need to start over from scratch.
-
-
-
Importing names
-
-
After sending the reveal transaction, you can populate your namespace with
-some initial names. You can do so with the name_import command.
-
-
Suppose we want to import the name example.hello and assign it to an owner
-whose public key address is ms6Y32bcL5zhA57e8tf7awgVZuPxV8Xg8N. Suppose also
-that you wanted to give example.hello an initial zone file stored at
-/var/blockstack/zone_files/example.hello. To do so, you would issue the
-following command:
-
-
|blockstack-test namespace_check| $ blockstack name_import example.hello ms6Y32bcL5zhA57e8tf7awgVZuPxV8Xg8N /var/blockstack/zone_files/example.hello " $CREATOR_PKEY "
-
-
-
-
By default, you must use the private key you used to reveal the namespace
-to import names (this is $CREATOR_PKEY in this example).
-
-
As with namespace-preorder and namespace-reveal, the transaction this command
-generates will be unconfirmed. Simply go to http://localhost:3001 to generate
-some blocks to confirm it.
-
-
You can check the progress of the transaction with blockstack info, as follows:
-
-
|blockstack-test namespace_check| $ blockstack info
- {
- "cli_version" : "0.17.0.8" ,
- "consensus_hash" : "b10fdd38a20a7e46555ce3a7f68cf95c" ,
- "last_block_processed" : 694,
- "last_block_seen" : 694,
- "queues" : {
- "name_import" : [
- {
- "confirmations" : 1,
- "name" : "example.hello" ,
- "tx_hash" : "10f7dcd9d6963ef5d20d010f731d5d2ddb76163a083b9d7a2b9fd4515c7fe58c"
- }
- ]
- } ,
- "server_alive" : true ,
- "server_host" : "localhost" ,
- "server_port" : 16264,
- "server_version" : "0.17.0.8"
- }
-
-
-
-
The confirmation field indicates how deep in the blockchain the transaction is
-at the time. Generating more blocks will increase its number of confirmations.
-
-
When you do this live,
-YOU SHOULD LEAVE YOUR COMPUTER RUNNING UNTIL THE name_import QUEUE IS EMPTY .
-Blockstack’s background API daemon will monitor the transactions and upload the
-name’s zone file to the Blockstack Atlas network once it is confirmed.
-But to do so, your computer must remain online. If you do not do this, then
-the name will not have a zone file and will be unusable in the higher layers of
-Blockstack-powered software (including Blockstack applications). However,
-if your computer does go offline or reboots, you can recover by
-restarting the Blockstack API daemon (with
-blockstack api start). The daemon itself will pick up where it left off, and
-replicate all zone files that have confirmed transactions.
-
-
After the zone file is uploaded, the name will be public and resolvable. You can re-import the
-same name over and over, and give it a different address and/or zone file. Like
-all other names, the Blockstack Atlas network will accept and propagate zone
-files for imported names.
-
-
The owner of the address ms6Y32bcL5zhA57e8tf7awgVZuPxV8Xg8N will not be
-able to issue any transactions for the name example.hello until the namespace
-creator has sent the ready transaction.
-
-
Using multiple private keys for NAME_IMPORT
-
-
Bitcoin itself imposes limits on how fast you can send transactions from the
-same key (limited by a maximum UTXO-chain length). To work around this,
-Blockstack lets you import names by using up to 300 private keys. The private
-keys you can use are BIP32 unhardened children of the namespace reveal key (i.e.
-$CREATOR_PKEY in this example).
-
-
The first name you import must use the namespace reveal private key
-($CREATOR_PKEY in this example). However, all future names you import in this
-namespace can use one of the 300 BIP32 keys.
-
-
To get the list of keys you can use, you can use the make_import_keys command:
-
-
|blockstack-test namespace_check| $ blockstack make_import_keys example hello " $CREATOR_PKEY "
- aeda50305ada40aaf53f2d8921aa717f1ec71a0a3b9b4c6397b3877f6d45c46501 ( n4DVTuLLv5J1Yc17AoRYY1GtxDAuLGAESr)
- 92ff179901819a1ec7d32997ce3bb0d9a913895d5850cc05146722847128549201 ( mib2KNBGR4az8GiUmusBZexVBqb9YB2gm5)
- cc5b6a454e2b614bfa18f4deb9a8e179ab985634d63b7fedfaa59573472d209b01 ( mxE2iqV4jdpn4K349Gy424TvZp6MPqSXve)
- 9b0265e0ac8c3c24fe1d79a734b3661ec2b5c0c2619bb6342356572b8235910101 ( n4rGz8hkXTscUGWCwZvahrkEh6LHZVQUoa)
- e2585af250404b7918cf6c91c6fa67f3401c0d1ae66df2fafa8fa132f4b9350f01 ( moGNpEpighqc6FnkqyNVJA9xtfTiStr5YU)
- {
- "status" : true
- }
-
-
-
-
(NOTE: in the test environment, you get only 5 keys in order to save time).
-
-
You can use any of these keys to import names.
-
-
Trying it out
-
-
Here’s an example walkthrough of how to try this out in the test framework:
-
-
- Import the first name, creating a zone file in the process:
-
-
-
|blockstack-test namespace_check| $ cat > /var/blockstack/zone_files/example.hello <<EOF
- > $ORIGIN example.hello
- > $TTL 3600
- > _file URI 10 1 "file:///home/blockstack-test/example.hello"
- > EOF
- |blockstack-test namespace_check| $ blockstack name_import example.hello ms6Y32bcL5zhA57e8tf7awgVZuPxV8Xg8N /var/blockstack/zone_files/example.hello "$CREATOR_PKEY"
- Import cost breakdown:
- {
- "name_import_tx_fee": {
- "btc": 0.0003342,
- "satoshis": 33420
- },
- "total_estimated_cost": {
- "btc": 0.0003342,
- "satoshis": 33420
- },
- "total_tx_fees": 33420
- }
- Importing name 'example.hello' to be owned by 'ms6Y32bcL5zhA57e8tf7awgVZuPxV8Xg8N' with zone file hash '05c302430f4ed0a24470abf9df7e264d517fd389'
- Proceed? (y/N) y
- {
- "status": true,
- "success": true,
- "transaction_hash": "bd875f00f63bcb718bb22782c88c3edcbed79663f2f9152deab328c48746f103",
- "value_hash": "05c302430f4ed0a24470abf9df7e264d517fd389"
- }
-
-
-
-
- Advance the test framework blockchain, so the indexer knows which import keys to expect:
-
-
-
# NOTE: you can also do this by going to http://localhost:3001 in your Web browser
- |blockstack-test namespace_check| $ curl -X POST http://localhost:3001/nextblock
-
-
-
-
- Make import keys:
-
-
-
|blockstack-test namespace_check| $ blocksatck make_import_keys hello " $CREATOR_PKEY "
- aeda50305ada40aaf53f2d8921aa717f1ec71a0a3b9b4c6397b3877f6d45c46501 ( n4DVTuLLv5J1Yc17AoRYY1GtxDAuLGAESr)
- 92ff179901819a1ec7d32997ce3bb0d9a913895d5850cc05146722847128549201 ( mib2KNBGR4az8GiUmusBZexVBqb9YB2gm5)
- cc5b6a454e2b614bfa18f4deb9a8e179ab985634d63b7fedfaa59573472d209b01 ( mxE2iqV4jdpn4K349Gy424TvZp6MPqSXve)
- 9b0265e0ac8c3c24fe1d79a734b3661ec2b5c0c2619bb6342356572b8235910101 ( n4rGz8hkXTscUGWCwZvahrkEh6LHZVQUoa)
- e2585af250404b7918cf6c91c6fa67f3401c0d1ae66df2fafa8fa132f4b9350f01 ( moGNpEpighqc6FnkqyNVJA9xtfTiStr5YU)
- {
- "status" : true
- }
-
-
-
-
- Fill up one of the addresses in the test framework, so we can fund NAME_IMPORT transactions with it:
-
-
-
# NOTE: you can also do this by going to http://localhost:3001 in your Web browser
- |blockstack-test namespace_check| $ curl -X POST -F 'addr=n4DVTuLLv5J1Yc17AoRYY1GtxDAuLGAESr' -F 'value=100000000' 'http://localhost:3001/sendfunds'
-
-
-
-
- Import another name, with the child private key we just funded:
-
-
-
|blockstack-test namespace_check| $ cat > /tmp/example.hello.zonefile <<EOF
- > $ORIGIN example2.hello
- > $TTL 3600
- > _file URI 10 1 "file:///home/blockstack-test/example2.hello"
- > EOF
- |blockstack-test namespace_check| $ blockstack name_import example2.hello n3sFkNfBQPWS25G12DqDEqHRPiqHotAkEb /tmp/example.hello.zonefile aeda50305ada40aaf53f2d8921aa717f1ec71a0a3b9b4c6397b3877f6d45c46501
- Import cost breakdown:
- {
- "name_import_tx_fee": {
- "btc": 0.0003342,
- "satoshis": 33420
- },
- "total_estimated_cost": {
- "btc": 0.0003342,
- "satoshis": 33420
- },
- "total_tx_fees": 33420
- }
- Importing name 'example2.hello' to be owned by 'n3sFkNfBQPWS25G12DqDEqHRPiqHotAkEb' with zone file hash '0649bc0b457f54c564d054ce20dc3745a0c4f0c0'
- Proceed? (y/N) y
- {
- "status": true,
- "success": true,
- "transaction_hash": "496a6c2aaccedd98a8403c2e61ff3bdeff221a58bf0e9c362fcae981353f459f",
- "value_hash": "0649bc0b457f54c564d054ce20dc3745a0c4f0c0"
- }
-
-
-
-
- Advance the blockchain again:
-
-
-
# NOTE: you can also do this by going to http://localhost:3001 in your Web browser
- |blockstack-test namespace_check| $ curl -X POST http://localhost:3001/nextblock
-
-
-
-
- See that the names are processing:
-
-
-
|blockstack-test namespace_check| $ blockstack info
- {
- "cli_version" : "0.17.0.8" ,
- "consensus_hash" : "2a055beeaedcaa1365ab2671a0254a03" ,
- "last_block_processed" : 711,
- "last_block_seen" : 711,
- "queues" : {
- "name_import" : [
- {
- "confirmations" : 2,
- "name" : "example.hello" ,
- "tx_hash" : "bd875f00f63bcb718bb22782c88c3edcbed79663f2f9152deab328c48746f103" ,
- } ,
- {
- "confirmations" : 1,
- "name" : "example2.hello" ,
- "tx_hash" : "496a6c2aaccedd98a8403c2e61ff3bdeff221a58bf0e9c362fcae981353f459f"
- }
- ]
- } ,
- "server_alive" : true ,
- "server_host" : "localhost" ,
- "server_port" : 16264,
- "server_version" : "0.17.0.8"
- }
-
-
-
-
- Confirm all the transactions:
-
-
-
# NOTE: you can also do this by going to http://localhost:3001 in your Web browser
- |blockstack-test namespace_check| $ for i in $( seq 1 10) ; do curl -X POST http://localhost:3001/nextblock
-
-
-
-
- Look up name zone files to confirm they were replicated to the test framework’s Atlas network:
-
-
-
|blockstack-test namespace_check| $ blockstack info
- {
- "cli_version" : "0.17.0.8" ,
- "consensus_hash" : "ad247c1d5ff239a65db0736951078f17" ,
- "last_block_processed" : 721,
- "last_block_seen" : 721,
- "queues" : {} ,
- "server_alive" : true ,
- "server_host" : "localhost" ,
- "server_port" : 16264,
- "server_version" : "0.17.0.8"
- }
- |blockstack-test namespace_check| $ blockstack get_name_zonefile example.hello
- $ORIGIN example.hello
- $TTL 3600
- _file URI 10 1 "file:///home/blockstack-test/example.hello"
-
- |blockstack-test namespace_check| $ blockstack get_name_zonefile example2.hello
- $ORIGIN example2.hello
- $TTL 3600
- _file URI 10 1 "file:///home/blockstack-test/example2.hello"
-
-
-
-
Now, these names are imported and once the NAMESPACE_READY transaction is
-sent, the name owners can proceed to issue name operations.
-
-
Warnings
-
-
- The first private key you use must be the same one you used to create the namespace ($CREATOR_KEY).
- You may only use the 300 private keys described above to import names.
- You must complete all NAME_IMPORT transactions within 52595 blocks of the NAMESPACE_REVEAL transaction (about 1 year).
-
-
-
Launching a Namespace
-
-
Once you have pre-populated your namespace with all of the initial names, you
-have to make it ready so anyone can register a name. If you do not do this
-within 1 year of the reveal transaction, then your namespace and all of the
-names will disappear, and someone else will be able to register it.
-
-
To make a namespace ready, you use the creator private key as follows:
-
-
|blockstack-test namespace_check| $ blockstack namespace_ready hello " $CREATOR_PKEY "
-
-
-
-
Warnings
-
-
- You must send the NAMESPACE_READY transaction within 52595 blocks (about 1 year) of the NAMESPACE_REVEAL transaction.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Related Articles
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Blockstack
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/_site/core/naming/tutorial_subdomains.html b/_site/core/naming/tutorial_subdomains.html
deleted file mode 100644
index d9999244d8..0000000000
--- a/_site/core/naming/tutorial_subdomains.html
+++ /dev/null
@@ -1,792 +0,0 @@
-
-
-
-
-
-
-
-
-
Subdomain Design and Implementation | Blockstack
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Subdomain Design and Implementation
-
-
-
-
-
-
-
-
Subdomains allow us to provide names to end users cheaply (and quickly). This
-tutorial explains you how to create, register, and run a subdomain register, it
-contains the following sections:
-
-
-
-
Strong subdomain ownership
-
-
For those who are new to this concept, it’s a model where domains can
-permanently, cryptographically delegate subdomains to particular keys,
-relinquishing their ability to revoke the names or change the name
-resolution details.
-
-
These names will be indicated with an ., e.g., foo.bar.id
-
-
Overall Design
-
-
We can do this today with a special indexer & resolver endpoint and
-without any changes to the core protocol.
-
-
We can do this by having a zone file record for each subdomain i
-containing the following information:
-
-
- An owner address addr
- A sequence number N
- A zonefile
- A signature S of the above
-
-
-
The signature S_i must be verifiable with the address in the
-(N-1) th entry for subdomain i .
-
-
-
-
For now, the resolver will use an TXT record per subdomain to define
-this information. The entry name will be $(subdomain).
-
-
We’ll use the format of RFC 1464
-for the TXT entry. We’ll have the following strings with identifiers:
-
-
- parts : this specifies the number of pieces that the
-zonefile has been chopped into. TXT strings can only be 255 bytes,
-so we chop up the zonefile.
- zf{n} : part n of the zonefile, base64 encoded
- owner : the owner address delegated to operate the subdomain
- seqn : the sequence number
- sig : signature of the above data.
-
-
-
$ORIGIN bar.id
-$TTL 3600
-pubkey TXT "pubkey:data:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
-registrar URI 10 1 "bsreg://foo.com:8234"
-aaron TXT "owner=33VvhhSQsYQyCVE2VzG3EHa9gfRCpboqHy" "seqn=0" "parts=1" "zf0=JE9SSUdJTiBhYXJvbgokVFRMIDM2MDAKbWFpbiBVUkkgMSAxICJwdWJrZXk6ZGF0YTowMzAyYWRlNTdlNjNiMzc1NDRmOGQ5Nzk4NjJhNDlkMDBkYmNlMDdmMjkzYmJlYjJhZWNmZTI5OTkxYTg3Mzk4YjgiCg=="
-
-
-
-
The registrar entry indicates how to contact the registrar service
-for clients of the domain wishing to register or modify their entry.
-
-
Operations per Zonefile
-
-
At 4kb zonefile size, we can only fit around 20 updates per zonefile.
-
-
Domain Operator Endpoint
-
-
The directory subdomain_registrar/ contains our code for running a
-subdomain registrar. It can be executed by running:
-
-
$ blockstack-subdomain-registrar start foo.id
-
-
-
-
Here, foo.id is the domain for which subdomains will be associated.
-
-
Configuration and Registration Files
-
-
Configuration of the subdomain registrar is done through ~/.blockstack_subdomains/config.ini
-
-
The sqlite database which stores the registrations is located alongside the config ~/.blockstack_subdomains/registrar.db.
-
-
You can change the location of the config file (and the database), by setting the environment variable BLOCKSTACK_SUBDOMAIN_CONFIG
-
-
Register Subdomain
-
-
Subdomain registrations can be submitted to this endpoint using a REST
-API.
-
-
-
-
The schema for registration is:
-
-
{
- 'type' : 'object',
- 'properties' : {
- 'name' : {
- 'type': 'string',
- 'pattern': '([a-z0-9\-_+]{3,36 } )$'
- },
- 'owner_address' : {
- 'type': 'string',
- 'pattern': schemas.OP_ADDRESS_PATTERN
- } ,
- 'zonefile' : {
- 'type' : 'string',
- 'maxLength' : blockstack_constants.RPC_MAX_ZONEFILE_LEN
- }
- },
- 'required': [
- 'name' , 'owner_address' , 'zonefile'
- ] ,
- 'additionalProperties' : True
- }
-
-
-
-
The registrar will:
-
-
- Check if the subdomain foo exists already on the domain.
- Add the subdomain to the queue.
-
-
-
On success, this returns 202 and the message
-
-
{ "status" : "true" , "message" : "Subdomain registration queued." }
-
-
-
-
When the registrar wakes up to prepare a transaction, it packs the queued
-registrations together and issues an UPDATE.
-
-
Check subdomain registration status
-
-
A user can check on the registration status of their name via querying the
-registrar.
-
-
This is an API call:
-
GET /status/{subdomain}
-
-
-
-
The registrar checks if the subdomain has propagated (i.e., the
-registration is completed), in which case the following is returned:
-
-
{ "status" : "Subdomain already propagated" }
-
-
-
-
Or, if the subdomain has already been submitted in a transaction:
-
-
{ "status" : "Your subdomain was registered in transaction 09a40d6ea362608c68da6e1ebeb3210367abf7aa39ece5fd57fd63d269336399 -- it should propagate on the network once it has 6 confirmations." }
-
-
-
-
If the subdomain still hasn’t been submitted yet:
-
-
{ "status" : "Subdomain is queued for update and should be announced within the next few blocks." }
-
-
-
-
If an error occurred trying to submit the UPDATE transaction, this endpoint will return an error
-message in the "error" key of a JSON object.
-
-
Updating Entries
-
-
The subdomain registrar does not currently support updating subdomain entries.
-
-
Resolver Behavior
-
-
When a lookup like foo.bar.id hits the resolver, the resolver will need to:
-
-
- Lookup the zonefile history of bar.id
- Fetch all these zonefiles and filter by operations on foo
- Verify that all foo operations are correct
- Return the latest record for foo
- Do a profile lookup for foo.bar.id by fetching the URLs in the entry.
-Note , this spec does not define a priority order for fetching those URLs.
-
-
-
Supported Core / Resolver Endpoints
-
-
Generally, domain endpoints are not aware of subdomains (only endpoints
-aware of subdomains is /v1/users/<foo.bar.tld>,
-/v1/names/<foo.bar.tld>, and /v1/addresses/bitcoin/<foo.bar.tld>)
-The endpoints which are subdomain aware are marked as such in
-[api-specs.md], the cli command blockstack lookup is subdomain
-aware.
-
-
This means that search is not yet supported.
-
-
The lookups work just like normal – it returns the user’s
-profile object:
-
-
$ curl -H "Authorization: bearer blockstack_integration_test_api_password" -H "Origin: http://localhost:3000" http://localhost:16268/v1/users/bar.foo.id -v -s | python -m json.tool
-* Trying 127.0.0.1...
-* Connected to localhost (127.0.0.1) port 16268 (#0)
-> GET /v1/users/bar.foo.id HTTP/1.1
-> Host: localhost:16268
-> User-Agent: curl/7.50.1
-> Accept: */*
-> Authorization: bearer blockstack_integration_test_api_password
-> Origin: http://localhost:3000
->
-* HTTP 1.0, assume close after body
-< HTTP/1.0 200 OK
-< Server: SimpleHTTP/0.6 Python/2.7.12+
-< Date: Thu, 03 Aug 2017 14:39:16 GMT
-< content-type: application/json
-< Access-Control-Allow-Origin: *
-<
-{ [66 bytes data]
-* Closing connection 0
-{
- "bar": {
- "@type": "Person",
- "description": "Lorem Ipsum Bazorem"
- }
-}
-
-
-
-
Name info lookups are also supported (this should enable authenticating logins
-with blockstack.js, but I will need to double check).
-
-
$ curl -H "Authorization: bearer XXXX" -H "Origin: http://localhost:3000" http://localhost:6270/v1/names/created_equal.self_evident_truth.id -s | python -m json.tool
-{
- "address": "1AYddAnfHbw6bPNvnsQFFrEuUdhMhf2XG9",
- "blockchain": "bitcoin",
- "expire_block": -1,
- "last_txid": "0bacfd5a3e0ec68723d5948d6c1a04ad0de1378c872d45fa2276ebbd7be230f7",
- "satus": "registered_subdomain",
- "zonefile_hash": "48fc1b351ce81cf0a9fd9b4eae7a3f80e93c0451",
- "zonefile_txt": "$ORIGIN created_equal\n$TTL 3600\n_https._tcp URI 10 1 \"https://www.cs.princeton.edu/~ablankst/created_equal.json\"\n_file URI 10 1 \"file:///tmp/created_equal.json\"\n"
-}
-
-
-
-
Subdomain Caching
-
-
A resolver caches a subdomain’s state by keeping a database of all
-the current subdomain records. This database is automatically updated
-when a new zonefile for a particularly domain is seen by the resolver
-(this is performed lazily).
-
-
Testing Subdomain Registrar and Resolution
-
-
You can run a subdomain registrar and resolver with blockstack-core in
-regtest mode as follows:
-
-
IMAGE = $( docker run -dt -p 3000:3000 -p 6270:6270 -p 16269:16269 -p 18332:18332 -e BLOCKSTACK_TEST_CLIENT_RPC_PORT = 6270 -e BLOCKSTACK_TEST_CLIENT_BIND = 0.0.0.0 -e BLOCKSTACK_TEST_BITCOIND_ALLOWIP = 172.17.0.0/16 quay.io/blockstack/integrationtests:master blockstack-test-scenario --interactive 2 blockstack_integration_tests.scenarios.browser_env)
-
-
-
-
Once you see Test finished; doing checks in that container’s logs, the
-registrar has started and is ready to accept requests. (We recommend
-following the docker instructions below for running this test in
-Docker, as it will fetch the source code for the registrar and set the
-correct environment variables for it to run).
-
-
Once this environment has started, you can issue a registration request from curl:
-
-
curl -X POST -H 'Content-Type: application/json' --data '{"zonefile": "$ORIGIN baz\n$TTL 3600\n_file URI 10 1 \"file:///tmp/baz.profile.json\"\n", "name": "baz", "owner_address": "14x2EMRz1gf16UzGbxZh2c6sJg4A8wcHLD"}' http://localhost:3000/register/
-
-
-
-
This registers baz.foo.id – you can check the registrar’s status with
-
-
curl http://localhost:3000/status/baz
-
-
-
-
The API endpoints /v1/users/<foo.bar.tld>,
-/v1/names/<foo.bar.tld>, and /v1/addresses/bitcoin/<foo.bar.tld> all work, so if you query the core API, you’ll get a response.
-
-
For example:
-
-
curl http://localhost:6270/v1/names/baz.foo.id | python -m json.tool
-
-
-
-
Will return:
-
{
- "address" : "1Nup2UcbVuVoDZeZCtR4vjSkrvTi8toTqc" ,
- "blockchain" : "bitcoin" ,
- "expire_block" : -1 ,
- "last_txid" : "43bbcbd8793cdc52f1b0bd2713ed136f4f104a683a9fd5c89911a57a8c4b28b6" ,
- "satus" : "registered_subdomain" ,
- "zonefile_hash" : "e7e3aada18c9ac5189f1c54089e987f58c0fa51e" ,
- "zonefile_txt" : "$ORIGIN bar\n$TTL 3600\n_file URI 10 1 \"file:///tmp/baz.profile.json\"\n"
- }
-
-
-
-
Running an interactive testing environment with the Subdomain Registrar service
-
-
Follow the instructions here to download the regtesting Docker image.
-
-
Since the subdomain registrar service runs on port 3000, we need to do two things to expose this endpoint to interact with it from the browser:
-
- Open port 3000 with -p 3000:3000
-
-
-
Here’s the full command you’d run to start the interactive testing scenario:
-
-
IMAGE = $( docker run -dt -p 3000:3000 -p 6270:6270 -p 16269:16269 -p 18332:18332 -e BLOCKSTACK_TEST_CLIENT_RPC_PORT = 6270 -e BLOCKSTACK_TEST_CLIENT_BIND = 0.0.0.0 -e BLOCKSTACK_TEST_BITCOIND_ALLOWIP = 172.17.0.0/16 quay.io/blockstack/integrationtests:master blockstack-test-scenario --interactive 2 blockstack_integration_tests.scenarios.browser_env)
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Related Articles
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Blockstack
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/_site/core/resolver.md b/_site/core/resolver.md
deleted file mode 100644
index 50b00abb46..0000000000
--- a/_site/core/resolver.md
+++ /dev/null
@@ -1,33 +0,0 @@
-# Blockstack Resolver
-
-During 2014-2016, Bockstack resolver was a separate service (like DNS resolvers).
-It was merged into the Blockstack API in early 2017.
-
-The following (legacy) API call is still being supported by the Blockstack API:
-
-```
-http://localhost:5000/v2/users/fredwilson
-```
-
-And you can see a legacy resolver in action at http://resolver.onename.com/v2/users/fredwilson
-
-## Cron Job for Namespaces
-
-**Note: the instructions below need updating.**
-
-Currently, the resolver indexes all valid names in a local file which can be
-populated by running
-> $ ./refresh_names.sh
-
-On a production deployment, you should add a crond job to periodically run this
-script. You can edit your crontab file by:
-> $ crontab -e
-
-Here is a sample crontab file that runs the refresh script every two hours:
-```
-SHELL=/bin/bash
-HOME=/home/ubuntu
-
-#This is a comment
-0 */2 * * * /home/ubuntu/resolver/resolver/refresh_names.sh
-```
diff --git a/_site/core/search.md b/_site/core/search.md
deleted file mode 100644
index 73b480686b..0000000000
--- a/_site/core/search.md
+++ /dev/null
@@ -1,184 +0,0 @@
-# Search
-
-The search subsystem for Blockstack Core creates an index for data associated
-with registered names in namespaces and makes that data searchable.
-
-The search subsystem is currently meant to index the .id namespace but can
-be easily expanded to include other namespaces.
-
-Currently there are two types of indexes to handle search queries:
-
-* Substring search on usernames, full names, twitter_handle (powered by MongoDB)
-* Raw Lucene index which handles searching extended data e.g., bio.
-
-Search will currently return upto a max of 20 results (can be less depending on the query)
-with data that follows structure of [blockstack IDs](https://github.com/blockstack/blockstack):
-
-In early 2017, the search subsystem was ported over to the new API system, where support for search is provided by the endpoint:
-
-```
-http://localhost:5000/search?query=
-```
-
-This document describes how to setup the search subsystem to respond at that endpoint.
-
-# Installation
-
-- **Step 1:** First, make sure you have [virtualenv installed](http://docs.python-guide.org/en/latest/dev/virtualenvs/).
-Then, setup the API and search subsystem:
-```
-$ sudo apt-get install -y mongodb memcached python-dev libmemcached-dev zlib1g-dev nginx
-$ sudo pip install uwsgi
-$ git clone https://github.com/blockstack/blockstack-core.git --branch api
-$ cd blockstack-core/
-$ sudo pip install .
-$ sudo pip install -r api/requirements.txt
-$ sudo mkdir /var/blockstack-search && sudo chown $USER:$USER /var/blockstack-search
-```
-
-- **Step 2:** Make sure you have Blockstack Core running locally (see [instructions](https://github.com/blockstack/blockstack-core/blob/master/README.md#quick-start)). We highly
-recommend using a local node because the search subsystem issues thousands of calls to
-Blockstack Core for re-indexing and remote nodes can slow down performance.
-
-- **Step 3:** Fetch the data for the .id namespace and respective profiles. Note, you may want to redirect stderr to a file, as there is a lot of debug output.
-
-```
-$ cd api/
-
-$ python -m search.fetch_data --fetch_namespace
-
-$ python -m search.fetch_data --fetch_profiles
-```
-
-- **Step 4:** Create the search index:
-
-```
-python -m search.basic_index --refresh
-```
-
-- **Step 5:** Enable search API endpoint:
-
-```
-$ sed -i 's/SEARCH_API_ENDPOINT_ENABLED \= False/SEARCH_API_ENDPOINT_ENABLED \= True/' config.py
-```
-
-# Usage
-
-You can quickly test the search index from the command line:
-
-```
-python -m search.substring_search --search_name "Fred Wil"
-python -m search.substring_search --search_twitter fredwil
-```
-
-You can also use the search API end-point:
-
-> curl -G {machine_ip}:port/search/name -d "query=muneeb"
-
-Sample Response:
-
-```
-{
- "people": [
- {
- "profile": {
- "website": [
- {
- "url": "http://muneebali.com",
- "@type": "WebSite"
- }
- ],
- "name": "Muneeb Ali",
- "address": {
- "addressLocality": "New York, NY",
- "@type": "PostalAddress"
- },
- "image": [
- {
- "contentUrl": "https://s3.amazonaws.com/dx3/muneeb",
- "@type": "ImageObject",
- "name": "cover"
- },
- {
- "contentUrl": "https://s3.amazonaws.com/kd4/muneeb",
- "@type": "ImageObject",
- "name": "avatar"
- }
- ],
- "@type": "Person",
- "description": "Co-founder of Blockstack. Interested in distributed systems and blockchains. Previously, PhD at Princeton."
- },
- "username": "muneeb"
- },
- {
- "profile": {
- "message": "This blockchain ID is reserved for Muneeb Ali. If this is you, please email support@onename.com to claim it for free.",
- "status": "reserved"
- },
- "username": "muneebali"
- },
- {
- "profile": {
- "cover": {
- "url": "https://s3.amazonaws.com/97p/HHE.jpg"
- },
- "v": "0.2"
- },
- "username": "muneebali1"
- }
-
- ]
-}
-```
-
-## Enabling Elastic Search
-
-### Requirements:
-
-```
-sudo apt-get install mongodb
-sudo apt-get install memcached libmemcached-dev
-sudo apt-get install python2.7-dev
-pip install -r requirements.txt
-```
-
-### Elastic Search
-
-Elastic Search library is not in github and resides at unix/lib/elastic
-
-the current version we're using is *0.90.2*. Download from:
-
-> wget https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-0.90.2.zip
-
-before installing pylimbmc make sure [memcached](memcached.md) is installed.
-
-Ensure that mongodb and elastic search are running
-starting elastic search:
-
-```
-$elasticsearch (on mac)
-bin/elasticsearch -d (on linux)
-```
-
-To test if elastic search is running:
-
-> curl -X GET http://localhost:9200/
-
-returns:
-
-```
-{
- "ok" : true,
- "status" : 200,
- "name" : "Angler",
- "version" : {
- "number" : "0.90.2",
- "snapshot_build" : false,
- "lucene_version" : "4.3.1"
- },
-```
-
-Create Index:
-
-> python create_search_index.py --create_index
-
diff --git a/_site/core/setup_core_portal.md b/_site/core/setup_core_portal.md
deleted file mode 100644
index bd1dc80e48..0000000000
--- a/_site/core/setup_core_portal.md
+++ /dev/null
@@ -1,114 +0,0 @@
-# Install Script
-
-We provide a [script](../images/scripts/ubuntu-17.04.sh) which will
-perform all the steps outlined in this doc (except for creating a protocol handler -- see the bottom of the doc). The script creates a virtualenv of
-Blockstack Core and installs Browser in a subdirectory. It additionally creates some
-scripts for starting Core and Browser together.
-
-However, if you'd like to customize your install, step through it
-yourself, or you are on a different distro, continue on with this doc!
-
-# Setting up Blockstack Core API Service
-
-Install required binaries in Ubuntu:
-
-```
-sudo apt update && sudo apt-get install -y python-pip python-dev libssl-dev libffi-dev rng-tools curl build-essential
-```
-
-
-If you'd like to use a virtualenv to install Blockstack, you can do that
-
-```
-pip install virtualenv
-virtualenv --python=python2.7 ~/.blockstack.venv/ && source ~/.blockstack.venv/bin/activate
-```
-
-Let's install virtualchain 0.14.3 and blockstack 0.14.3
-
-```
-sudo apt install git
-pip install git+https://github.com/blockstack/virtualchain.git@rc-0.14.3
-pip install git+https://github.com/blockstack/blockstack-core.git@rc-0.14.3
-```
-
-Get Blockstack core configured with default settings and choose your Bitcoin wallet password
-```
-blockstack setup -y --password BITCOIN_WALLET_PASSWORD --debug
-```
-
-# Setting up Blockstack Browser Node Application
-
-Install NodeJS through NodeSource PPA
-
-```
-curl -sL https://deb.nodesource.com/setup_7.x | sudo -E bash -
-sudo apt install -y nodejs
-```
-
-Download Blockstack Browser and install its dependencies
-
-```
-git clone https://github.com/blockstack/blockstack-browser.git -bv0.11.1
-cd blockstack-browser
-npm install node-sass
-npm install
-```
-
-Note that `blockstack-browser` depends on `node-sass` which can sometimes install strangely on Linux, running `npm install node-sass` before trying to install the other dependencies solves that problem.
-
-# Running Blockstack Browser
-
-Now we're ready to run our Core API service and start the Browser node app.
-
-First, start the Core API service.
-
-```
-blockstack api start -y --password BITCOIN_WALLET_PASSWORD --debug
-```
-
-Start the CORS proxy.
-
-```
-npm run dev-proxy &
-```
-
-Start the Node Application
-
-```
-npm run dev
-```
-
-Then you can open `http://localhost:3000/` in your browser to get to the Blockstack Browser.
-
-
-You can copy your api password to your clipboard with this command:
-```
-grep api_password ~/.blockstack/client.ini | sed 's/api_password = //g' | xclip -selection clipboard
-```
-
-## Setting up a protocol handler
-
-If you'd like your browser to automatically handle links with the `blockstack:` protocol specifier, you will need to register a protocol handler with your desktop environment. In Ubuntu/Gnome, this can be done by creating a file
-
-`~/.local/share/applications/blockstack.desktop`
-
-With the following contents:
-
-```
-[Desktop Entry]
-Type=Application
-Terminal=false
-Exec=bash -c 'xdg-open http://localhost:3000/auth?authRequest=$(echo "%u" | sed s,blockstack:////*,,)'
-Name=Blockstack-Browser
-MimeType=x-scheme-handler/blockstack;
-```
-
-Then you need to make this file executable, and register it as a protocol handler.
-
-```
-$ chmod +x ~/.local/share/applications/blockstack.desktop
-$ xdg-mime default blockstack.desktop x-scheme-handler/blockstack
-```
-
-Now, `blockstack:` protocol URLs should get handled by your Blockstack Browser. If you're running Browser in your browser's private mode, you may have to copy and paste the link, as this protocol handler will try to open in a regular browser window.
diff --git a/_site/core/wire-format.md b/_site/core/wire-format.md
deleted file mode 100644
index 5f45ee8c1b..0000000000
--- a/_site/core/wire-format.md
+++ /dev/null
@@ -1,492 +0,0 @@
-This page is for organizations who want to be able to create and send name operation transactions to the blockchain(s) Blockstack supports.
-
-# Bitcoin
-
-This section describes the transaction formats for the Bitcoin blockchain.
-
-## Transaction format
-
-Each Bitcoin transaction for Blockstack contains signatures from two sets of keys: the name owner, and the payer. The owner `scriptSig` and `scriptPubKey` fields are generated from the key(s) that own the given name. The payer `scriptSig` and `scriptPubKey` fields are used to *subsidize* the operation. The owner keys do not pay for any operations; the owner keys only control the minimum amount of BTC required to make the transaction standard. The payer keys only pay for the transaction's fees, and (when required) they pay the name fee.
-
-This construction is meant to allow the payer to be wholly separate from the owner. The principal that owns the name can fund their own transactions, or they can create a signed transaction that carries out the desired operation and request some other principal (e.g. a parent organization) to actually pay for and broadcast the transaction.
-
-The general transaction layout is as follows:
-
-| **Inputs** | **Outputs** |
-| ------------------------ | ----------------------- |
-| Owner scriptSig (1) | `OP_RETURN ` (2) |
-| Payment scriptSig | Owner scriptPubKey (3) |
-| Payment scriptSig... (4) |
-| ... (4) | ... (5) |
-
-(1) The owner `scriptSig` is *always* the first input.
-(2) The `OP_RETURN` script that describes the name operation is *always* the first output.
-(3) The owner `scriptPubKey` is *always* the second output.
-(4) The payer can use as many payment inputs as (s)he likes.
-(5) At most one output will be the "change" `scriptPubKey` for the payer.
-Different operations require different outputs.
-
-## Payload Format
-
-Each Blockstack transaction in Bitcoin describes the name operation within an `OP_RETURN` output. It encodes name ownership, name fees, and payments as `scriptPubKey` outputs. The specific operations are described below.
-
-Each `OP_RETURN` payload *always* starts with the two-byte string `id` (called the "magic" bytes in this document), followed by a one-byte `op` that describes the operation.
-
-### NAME_PREORDER
-
-Op: `?`
-
-Description: This transaction commits to the *hash* of a name. It is the first
-transaction of two transactions that must be sent to register a name in BNS.
-
-Example: [6730ae09574d5935ffabe3dd63a9341ea54fafae62fde36c27738e9ee9c4e889](https://www.blocktrail.com/BTC/tx/6730ae09574d5935ffabe3dd63a9341ea54fafae62fde36c27738e9ee9c4e889)
-
-`OP_RETURN` wire format:
-```
- 0 2 3 23 39
- |-----|--|--------------------------------------------------|--------------|
- magic op hash_name(name.ns_id,script_pubkey,register_addr) consensus hash
-```
-
-Inputs:
-* Payment `scriptSig`'s
-
-Outputs:
-* `OP_RETURN` payload
-* Payment `scriptPubkey` script for change
-* `p2pkh` `scriptPubkey` to the burn address (0x00000000000000000000000000000000000000)
-
-Notes:
-* `register_addr` is a base58check-encoded `ripemd160(sha256(pubkey))` (i.e. an address). This address **must not** have been used before in the underlying blockchain.
-* `script_pubkey` is either a `p2pkh` or `p2sh` compiled Bitcoin script for the payer's address.
-
-### NAME_REGISTRATION
-
-Op: `:`
-
-Description: This transaction reveals the name whose hash was announced by a
-previous `NAME_PREORDER`. It is the second of two transactions that must be
-sent to register a name in BNS.
-
-Example: [55b8b42fc3e3d23cbc0f07d38edae6a451dfc512b770fd7903725f9e465b2925](https://www.blocktrail.com/BTC/tx/55b8b42fc3e3d23cbc0f07d38edae6a451dfc512b770fd7903725f9e465b2925)
-
-`OP_RETURN` wire format (2 variations allowed):
-
-Variation 1:
-```
- 0 2 3 39
- |----|--|-----------------------------|
- magic op name.ns_id (37 bytes)
-```
-
-Variation 2:
-```
- 0 2 3 39 59
- |----|--|----------------------------------|-------------------|
- magic op name.ns_id (37 bytes, 0-padded) value
-```
-
-Inputs:
-* Payer `scriptSig`'s
-
-Outputs:
-* `OP_RETURN` payload
-* `scriptPubkey` for the owner's address
-* `scriptPubkey` for the payer's change
-
-Notes:
-
-* Variation 1 simply registers the name. Variation 2 will register the name and
-set a name value simultaneously. This is used in practice to set a zone file
-hash for a name without the extra `NAME_UPDATE` transaction.
-* Both variations are supported. Variation 1 was designed for the time when
- Bitcoin only supported 40-byte `OP_RETURN` outputs.
-
-### NAME_RENEWAL
-
-Op: `:`
-
-Description: This transaction renews a name in BNS. The name must still be
-registered and not expired, and owned by the transaction sender.
-
-Example: [e543211b18e5d29fd3de7c0242cb017115f6a22ad5c6d51cf39e2b87447b7e65](https://www.blocktrail.com/BTC/tx/e543211b18e5d29fd3de7c0242cb017115f6a22ad5c6d51cf39e2b87447b7e65)
-
-`OP_RETURN` wire format (2 variations allowed):
-
-Variation 1:
-```
- 0 2 3 39
- |----|--|-----------------------------|
- magic op name.ns_id (37 bytes)
-```
-
-Variation 2:
-```
- 0 2 3 39 59
- |----|--|----------------------------------|-------------------|
- magic op name.ns_id (37 bytes, 0-padded) value
-```
-
-Inputs:
-
-* Payer `scriptSig`'s
-
-Outputs:
-
-* `OP_RETURN` payload
-* `scriptPubkey` for the owner's addess. This can be a different address than
- the current name owner (in which case, the name is renewed and transferred).
-* `scriptPubkey` for the payer's change
-* `scriptPubkey` for the burn address (to pay the name cost)
-
-Notes:
-
-* This transaction is identical to a `NAME_REGISTRATION`, except for the presence of the fourth output that pays for the name cost (to the burn address).
-* Variation 1 simply renews the name. Variation 2 will both renew the name and
- set a new name value (in practice, the hash of a new zone file).
-* Both variations are supported. Variation 1 was designed for the time when
- Bitcoin only supported 40-byte `OP_RETURN` outputs.
-* This operation can be used to transfer a name to a new address by setting the
- second output (the first `scriptPubkey`) to be the `scriptPubkey` of the new
- owner key.
-
-### NAME_UPDATE
-
-Op: `+`
-
-Description: This transaction sets the name state for a name to the given
-`value`. In practice, this is used to announce new DNS zone file hashes to the [Atlas
-network](atlas_network.md).
-
-Example: [e2029990fa75e9fc642f149dad196ac6b64b9c4a6db254f23a580b7508fc34d7](https://www.blocktrail.com/BTC/tx/e2029990fa75e9fc642f149dad196ac6b64b9c4a6db254f23a580b7508fc34d7)
-
-`OP_RETURN` wire format:
-```
- 0 2 3 19 39
- |-----|--|-----------------------------------|-----------------------|
- magic op hash128(name.ns_id,consensus hash) zone file hash
-```
-
-Note that `hash128(name.ns_id, consensus hash)` is the first 16 bytes of a SHA256 hash over the name concatenated to the hexadecimal string of the consensus hash (not the bytes corresponding to that hex string).
-See the [Method Glossary](#method-glossary) below.
-
-Example: `hash128("jude.id" + "8d8762c37d82360b84cf4d87f32f7754") == "d1062edb9ec9c85ad1aca6d37f2f5793"`.
-
-Inputs:
-* owner `scriptSig`
-* payment `scriptSig`'s
-
-Outputs:
-* `OP_RETURN` payload
-* owner's `scriptPubkey`
-* payment `scriptPubkey` change
-
-### NAME_TRANSFER
-
-Op: `>`
-
-Description: This transaction changes the public key hash that owns the name in
-BNS.
-
-Example: [7a0a3bb7d39b89c3638abc369c85b5c028d0a55d7804ba1953ff19b0125f3c24](https://www.blocktrail.com/BTC/tx/7a0a3bb7d39b89c3638abc369c85b5c028d0a55d7804ba1953ff19b0125f3c24)
-
-`OP_RETURN` wire format:
-```
- 0 2 3 4 20 36
- |-----|--|----|-------------------|---------------|
- magic op keep hash128(name.ns_id) consensus hash
- data?
-```
-
-Inputs:
-
-* Owner `scriptSig`
-* Payment `scriptSig`'s
-
-Outputs:
-
-* `OP_RETURN` payload
-* new name owner's `scriptPubkey`
-* old name owner's `scriptPubkey`
-* payment `scriptPubkey` change
-
-Notes:
-
-* The `keep data?` byte controls whether or not the name's 20-byte value is preserved. This value is either `>` to preserve it, or `~` to delete it.
-
-### NAME_REVOKE
-
-Op: `~`
-
-Description: This transaction destroys a registered name. Its name state value
-in BNS will be cleared, and no further transactions will be able to affect the
-name until it expires (if its namespace allows it to expire at all).
-
-Example: [eb2e84a45cf411e528185a98cd5fb45ed349843a83d39fd4dff2de47adad8c8f](https://www.blocktrail.com/BTC/tx/eb2e84a45cf411e528185a98cd5fb45ed349843a83d39fd4dff2de47adad8c8f)
-
-`OP_RETURN` wire format:
-```
- 0 2 3 39
- |----|--|-----------------------------|
- magic op name.ns_id (37 bytes)
-```
-
-Inputs:
-
-* owner `scriptSig`
-* payment `scriptSig`'s
-
-Outputs:
-
-* `OP_RETURN` payload
-* owner `scriptPubkey`
-* payment `scriptPubkey` change
-
-### ANNOUNCE
-
-Op: `#`
-
-Description: This transaction does not affect any names in BNS, but it allows a
-user to send a message to other BNS nodes. In order for the message to be
-received, the following must be true:
-
-* The sender must have a BNS name
-* The BNS nodes must list the sender's BNS name as being a "trusted message
- sender"
-* The message must have already been propagated through the [Atlas
- network](atlas_network.md). This transaction references it by content hash.
-
-`OP_RETURN` wire format:
-
-```
- 0 2 3 23
- |----|--|-----------------------------|
- magic op ripemd160(sha256(message))
-```
-
-Inputs:
-
-* The payer `scriptSig`'s
-
-Outputs:
-
-* `OP_RETURN` payload
-* change `scriptPubKey`
-
-Notes:
-
-* The payer key should be an owner key for an existing name, since Blockstack users can subscribe to announcements from specific name-owners.
-
-### NAMESPACE_PREORDER
-
-Op: `*`
-
-Description: This transaction announces the *hash* of a new namespace. It is the
-first of three transactions that must be sent to create a namespace.
-
-Example: [5f00b8e609821edd6f3369ee4ee86e03ea34b890e242236cdb66ef6c9c6a1b28](https://www.blocktrail.com/BTC/tx/5f00b8e609821edd6f3369ee4ee86e03ea34b890e242236cdb66ef6c9c6a1b28)
-
-`OP_RETURN` wire format:
-```
- 0 2 3 23 39
- |-----|---|-----------------------------------------|----------------|
- magic op hash_name(ns_id,script_pubkey,reveal_addr) consensus hash
-```
-
-Inputs:
-
-* Namespace payer `scriptSig`
-
-Outputs:
-
-* `OP_RETURN` payload
-* Namespace payer `scriptPubkey` change address
-* `p2pkh` script to the burn address `1111111111111111111114oLvT2`, whose public key hash is 0x00000000000000000000000000000000
-
-Notes:
-
-* The `reveal_addr` field is the address of the namespace revealer public key. The revealer private key will be used to generate `NAME_IMPORT` transactions.
-
-### NAMESPACE_REVEAL
-
-Op: `&`
-
-Description: This transaction reveals the namespace ID and namespace rules
-for a previously-anounced namespace hash (sent by a previous `NAMESPACE_PREORDER`).
-
-Example: [ab54b1c1dd5332dc86b24ca2f88b8ca0068485edf0c322416d104c5b84133a32](https://www.blocktrail.com/BTC/tx/ab54b1c1dd5332dc86b24ca2f88b8ca0068485edf0c322416d104c5b84133a32)
-
-`OP_RETURN` wire format:
-```
- 0 2 3 7 8 9 10 11 12 13 14 15 16 17 18 20 39
- |-----|---|--------|-----|-----|----|----|----|----|----|-----|-----|-----|--------|----------|-------------------------|
- magic op life coeff. base 1-2 3-4 5-6 7-8 9-10 11-12 13-14 15-16 nonalpha version namespace ID
- bucket exponents no-vowel
- discounts
-```
-
-Inputs:
-
-* Namespace payer `scriptSig`s
-
-Outputs:
-
-* `OP_RETURN` payload
-* namespace revealer `scriptPubkey`
-* namespace payer change `scriptPubkey`
-
-Notes:
-
-* This transaction must be sent within 1 day of the `NAMESPACE_PREORDER`
-* The second output (with the namespace revealer) **must** be a `p2pkh` script
-* The address of the second output **must** be the `reveal_addr` in the `NAMESPACE_PREORDER`
-
-Pricing:
-
-The rules for a namespace are as follows:
-
- * a name can fall into one of 16 buckets, measured by length. Bucket 16 incorporates all names at least 16 characters long.
- * the pricing structure applies a multiplicative penalty for having numeric characters, or punctuation characters.
- * the price of a name in a bucket is ((coeff) * (base) ^ (bucket exponent)) / ((numeric discount multiplier) * (punctuation discount multiplier))
-
-Example:
-* base = 10
-* coeff = 2
-* nonalpha discount: 10
-* no-vowel discount: 10
-* buckets 1, 2: 9
-* buckets 3, 4, 5, 6: 8
-* buckets 7, 8, 9, 10, 11, 12, 13, 14: 7
-* buckets 15, 16+:
-
-With the above example configuration, the following are true:
-
-* The price of "john" would be 2 * 10^8, since "john" falls into bucket 4 and has no punctuation or numerics.
-* The price of "john1" would be 2 * 10^6, since "john1" falls into bucket 5 but has a number (and thus receives a 10x discount)
-* The price of "john_1" would be 2 * 10^6, since "john_1" falls into bucket 6 but has a number and punctuation (and thus receives a 10x discount)
-* The price of "j0hn_1" would be 2 * 10^5, since "j0hn_1" falls into bucket 6 but has a number and punctuation and lacks vowels (and thus receives a 100x discount)
-
-
-### NAME_IMPORT
-
-Op: `;`
-
-Description: This transaction registers a name and some name state into a
-namespace that has been revealed, but not been launched. Only the namespace
-creator can import names. See the [namespace creation
-tutorial](namespace_creation.md) for details.
-
-Example: [c698ac4b4a61c90b2c93dababde867dea359f971e2efcf415c37c9a4d9c4f312](https://www.blocktrail.com/BTC/tx/c698ac4b4a61c90b2c93dababde867dea359f971e2efcf415c37c9a4d9c4f312)
-
-`OP_RETURN` wire format:
-```
- 0 2 3 39
- |----|--|-----------------------------|
- magic op name.ns_id (37 bytes)
-```
-
-Inputs:
-
-* The namespace reveal `scriptSig` (with the namespace revealer's public key), or one of its first 300 extended public keys
-* Any payment inputs
-
-Outputs:
-
-* `OP_RETURN` payload
-* recipient `scriptPubKey`
-* zone file hash (using the 20-byte hash in a standard `p2pkh` script)
-* payment change `scriptPubKey`
-
-Notes:
-
-* These transactions can only be sent between the `NAMESPACE_REVEAL` and `NAMESPACE_READY`.
-* The first `NAME_IMPORT` transaction **must** have a `scriptSig` input that matches the `NAMESPACE_REVEAL`'s second output (i.e. the reveal output).
-* Any subsequent `NAME_IMPORT` transactions **may** have a `scriptSig` input whose public key is one of the first 300 extended public keys from the `NAMESPACE_REVEAL`'s `scriptSig` public key.
-
-### NAMESPACE_READY
-
-Op: `!`
-
-Description: This transaction launches a namesapce. Only the namespace creator
-can send this transaction. Once sent, anyone can register names in the
-namespace.
-
-Example: [2bf9a97e3081886f96c4def36d99a677059fafdbd6bdb6d626c0608a1e286032](https://www.blocktrail.com/BTC/tx/2bf9a97e3081886f96c4def36d99a677059fafdbd6bdb6d626c0608a1e286032)
-
-`OP_RETURN` wire format:
-```
-
- 0 2 3 4 23
- |-----|--|--|------------|
- magic op . ns_id
-```
-
-Inputs:
-* Namespace revealer's `scriptSig`s
-
-Outputs:
-* `OP_RETURN` payload
-* Change output to the namespace revealer's `p2pkh` script
-
-Notes:
-* This transaction must be sent within 1 year of the corresponding `NAMESPACE_REVEAL` to be accepted.
-
-## Method Glossary
-
-Some hashing primitives are used to construct the wire-format representation of each name operation. They are enumerated here:
-
-```
-B40_REGEX = '^[a-z0-9\-_.+]*$'
-
-def is_b40(s):
- return isinstance(s, str) and re.match(B40_REGEX, s) is not None
-
-def b40_to_bin(s):
- if not is_b40(s):
- raise ValueError('{} must only contain characters in the b40 char set'.format(s))
- return unhexlify(charset_to_hex(s, B40_CHARS))
-
-def hexpad(x):
- return ('0' * (len(x) % 2)) + x
-
-def charset_to_hex(s, original_charset):
- return hexpad(change_charset(s, original_charset, B16_CHARS))
-
-def bin_hash160(s, hex_format=False):
- """ s is in hex or binary format
- """
- if hex_format and is_hex(s):
- s = unhexlify(s)
- return hashlib.new('ripemd160', bin_sha256(s)).digest()
-
-def hex_hash160(s, hex_format=False):
- """ s is in hex or binary format
- """
- if hex_format and is_hex(s):
- s = unhexlify(s)
- return hexlify(bin_hash160(s))
-
-def hash_name(name, script_pubkey, register_addr=None):
- """
- Generate the hash over a name and hex-string script pubkey.
- Returns the hex-encoded string RIPEMD160(SHA256(x)), where
- x is the byte string composed of the concatenation of the
- binary
- """
- bin_name = b40_to_bin(name)
- name_and_pubkey = bin_name + unhexlify(script_pubkey)
-
- if register_addr is not None:
- name_and_pubkey += str(register_addr)
-
- # make hex-encoded hash
- return hex_hash160(name_and_pubkey)
-
-def hash128(data):
- """
- Hash a string of data by taking its 256-bit sha256 and truncating it to the
- first 16 bytes
- """
- return hexlify(bin_sha256(data)[0:16])
-```
-
diff --git a/_site/feed.xml b/_site/feed.xml
deleted file mode 100644
index 5760fa90b9..0000000000
--- a/_site/feed.xml
+++ /dev/null
@@ -1,49 +0,0 @@
-Jekyll 2018-09-04T10:14:49-07:00 https://zbabystack.netlify.com/ Blockstack Docs Blockstack Site tags 2017-05-25T00:00:00-07:00 2017-05-25T00:00:00-07:00 https://zbabystack.netlify.com/2017/05/25/post63 <p>https://zbabystack.netlify.com/assets/posts/</p>
-
-<p>/2017/05/25/post63.html</p>
-
-<p>Musce libero nunc, dignissim quis turpis quis, semper vehicula dolor. Suspendisse tincidunt consequat quam, ac posuere leo dapibus id. Cras fringilla convallis elit, at eleifend mi interam.</p>
-
-<p>Nulla non sollicitudin. Morbi sit amet laoreet ipsum, vel pretium mi. Morbi varius, tellus in accumsan blandit, elit ligula eleifend velit, luctus mattis ante nulla condimentum nulla. Etiam vestibulum risus vel arcu elementum eleifend. Cras at dolor eget urna varius faucibus tempus in elit.</p>
-
-<h2 id="image-lightbox-example">Image Lightbox Example</h2>
-<p>Nunc porta malesuada porta. Etiam tristique vestibulum dolor at ultricies. Proin hendrerit sapien sed erat fermentum, at commodo velit consectetur.</p>
-
-<figure data-uk-lightbox="animation: slide">
- <!-- <a class="uk-inline" href="https://zbabystack.netlify.com/assets/posts/image1.png" caption="Image in lightbox"> -->
- <a class="uk-inline" href="/assets/posts/image1.png" caption="Image in lightbox">
- <!-- <img src="https://zbabystack.netlify.com/assets/posts/image1.png" alt="Alt for image"> -->
- <img src="/assets/posts/image1.png" alt="Alt for image" />
- <div class="uk-position-center">
- <span data-uk-overlay-icon=""></span>
- </div>
- </a>
- <figcaption data-uk-grid="" class="uk-flex-right"><span class="uk-width-auto">Image in lightbox</span></figcaption>
-</figure>
-
-<p>Etiam vestibulum risus vel arcu elementum eleifend. Cras at dolor eget urna varius faucibus tempus in elit. Cras a dui imperdiet, tempus metus quis, pharetra turpis. Phasellus at massa sit amet ante semper fermentum sed eget lectus. Quisque id dictum magna, et dapibus turpis.</p>
-
-<h2 id="example-of-code-block">Example Of Code Block</h2>
-<p>In accumsan lacus ac neque maximus dictum. Phasellus eleifend leo id mattis bibendum. Curabitur et purus turpis. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;</p>
-
-<div class="language-html highlighter-rouge"><pre class="highlight"><code><span class="nt"><head></span>
- <span class="nt"><meta</span> <span class="na">charset=</span><span class="s">"utf-8"</span><span class="nt">></span>
- <span class="nt"><meta</span> <span class="na">http-equiv=</span><span class="s">"X-UA-Compatible"</span> <span class="na">content=</span><span class="s">"IE=edge"</span><span class="nt">></span>
- <span class="nt"><meta</span> <span class="na">name=</span><span class="s">"viewport"</span> <span class="na">content=</span><span class="s">"width=device-width, initial-scale=1"</span><span class="nt">></span>
- <span class="nt"><link</span> <span class="na">rel=</span><span class="s">"stylesheet"</span> <span class="na">href=</span><span class="s">"/assets/css/main.css"</span><span class="nt">></span>
- <span class="nt"><link</span> <span class="na">rel=</span><span class="s">"shortcut icon"</span> <span class="na">type=</span><span class="s">"image/png"</span> <span class="na">href=</span><span class="s">"/assets/img/favicon.png"</span> <span class="nt">></span>
- <span class="nt"><script </span><span class="na">src=</span><span class="s">"/assets/js/main.js"</span><span class="nt">></script></span>
-<span class="nt"></head></span>
-</code></pre>
-</div>
-
-<h2 id="text-and-quote">Text and Quote</h2>
-<p>Cras at dolor eget urna varius faucibus tempus in elit. Cras a dui imperdiet, tempus metus quis, pharetra turpis. Phasellus at massa sit amet ante semper fermentum sed eget lectus. Quisque id dictum magna turpis.</p>
-
-<blockquote>
- <p>Etiam vestibulum risus vel arcu elementum eleifend. Cras at dolor eget urna varius faucibus tempus in elit. Cras a dui imperdiet</p>
-</blockquote>
-
-<p>In accumsan lacus ac neque maximus dictum. Phasellus eleifend leo id mattis bibendum. Curabitur et purus turpis. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;</p>
-
-<p>Etiam in fermentum mi. Sed et tempor felis, eu aliquet nisi. Nam eget ullamcorper arcu. Nunc porttitor nisl a dolor blandit, eget consequat sem maximus. Phasellus lacinia quam porta orci malesuada, vel tincidunt.</p> John Black Site tags
\ No newline at end of file
diff --git a/_site/index.html b/_site/index.html
deleted file mode 100644
index d09b38fbd9..0000000000
--- a/_site/index.html
+++ /dev/null
@@ -1,422 +0,0 @@
-
-
-
-
-
-
-
-
-Blockstack | Docs
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Welcome to the documentation on everything Blockstack.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Browse by topic or technology category
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Evaluate Blockstack
-
-
Learn about the technology behind Blockstack. Understand the value it offers and how it provides it.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Use the New Internet
-
-
Learn about the New Internet and its applications. Create an identity and learn how to use it.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Build Apps and Earn Money
-
-
Learn how to build an application that earns with Blockstack.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Use the Naming Service
-
-
Managing your account, create new users and exporting data
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Implement Authentication
-
-
Managing your account, creating new users and exporting data
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Implement Storage with GAIA
-
-
Backend storage drivers and interactions between developer APIs and the Gaia service.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Didn't find an answer to your question?
-
Get in touch with us and we will be happy to respond!
-
Contact Us
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Blockstack
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/_site/ios/images/add-action.gif b/_site/ios/images/add-action.gif
deleted file mode 100644
index 6854281cb8..0000000000
Binary files a/_site/ios/images/add-action.gif and /dev/null differ
diff --git a/_site/ios/images/app-flow.png b/_site/ios/images/app-flow.png
deleted file mode 100644
index fa8b85a3bd..0000000000
Binary files a/_site/ios/images/app-flow.png and /dev/null differ
diff --git a/_site/ios/images/blockstack-icon.png b/_site/ios/images/blockstack-icon.png
deleted file mode 100644
index 243615bb9f..0000000000
Binary files a/_site/ios/images/blockstack-icon.png and /dev/null differ
diff --git a/_site/ios/images/blockstack-signin.png b/_site/ios/images/blockstack-signin.png
deleted file mode 100644
index 081d505034..0000000000
Binary files a/_site/ios/images/blockstack-signin.png and /dev/null differ
diff --git a/_site/ios/images/choose-new-options.png b/_site/ios/images/choose-new-options.png
deleted file mode 100644
index 9f1876fd88..0000000000
Binary files a/_site/ios/images/choose-new-options.png and /dev/null differ
diff --git a/_site/ios/images/create-restore.png b/_site/ios/images/create-restore.png
deleted file mode 100644
index 914b26e5b3..0000000000
Binary files a/_site/ios/images/create-restore.png and /dev/null differ
diff --git a/_site/ios/images/final-app.png b/_site/ios/images/final-app.png
deleted file mode 100644
index 81f7997e46..0000000000
Binary files a/_site/ios/images/final-app.png and /dev/null differ
diff --git a/_site/ios/images/image-set-0.png b/_site/ios/images/image-set-0.png
deleted file mode 100644
index ed8d7fa77e..0000000000
Binary files a/_site/ios/images/image-set-0.png and /dev/null differ
diff --git a/_site/ios/images/image-set-1.png b/_site/ios/images/image-set-1.png
deleted file mode 100644
index e8f271fae6..0000000000
Binary files a/_site/ios/images/image-set-1.png and /dev/null differ
diff --git a/_site/ios/images/indicator.png b/_site/ios/images/indicator.png
deleted file mode 100644
index 96282709ca..0000000000
Binary files a/_site/ios/images/indicator.png and /dev/null differ
diff --git a/_site/ios/images/main-storyboard.png b/_site/ios/images/main-storyboard.png
deleted file mode 100644
index e00e985b0e..0000000000
Binary files a/_site/ios/images/main-storyboard.png and /dev/null differ
diff --git a/_site/ios/images/open-as.png b/_site/ios/images/open-as.png
deleted file mode 100644
index 00e77f6989..0000000000
Binary files a/_site/ios/images/open-as.png and /dev/null differ
diff --git a/_site/ios/images/open-xcworkspace.png b/_site/ios/images/open-xcworkspace.png
deleted file mode 100644
index c8d8f4be4e..0000000000
Binary files a/_site/ios/images/open-xcworkspace.png and /dev/null differ
diff --git a/_site/ios/images/running-app.png b/_site/ios/images/running-app.png
deleted file mode 100644
index 9838c05f8c..0000000000
Binary files a/_site/ios/images/running-app.png and /dev/null differ
diff --git a/_site/ios/images/single-view-app.png b/_site/ios/images/single-view-app.png
deleted file mode 100644
index f2c7f08dea..0000000000
Binary files a/_site/ios/images/single-view-app.png and /dev/null differ
diff --git a/_site/ios/images/splash.png b/_site/ios/images/splash.png
deleted file mode 100644
index 134d062d86..0000000000
Binary files a/_site/ios/images/splash.png and /dev/null differ
diff --git a/_site/ios/images/url-type.png b/_site/ios/images/url-type.png
deleted file mode 100644
index b222e37c09..0000000000
Binary files a/_site/ios/images/url-type.png and /dev/null differ
diff --git a/_site/ios/images/view-editors.gif b/_site/ios/images/view-editors.gif
deleted file mode 100644
index 2003f79342..0000000000
Binary files a/_site/ios/images/view-editors.gif and /dev/null differ
diff --git a/_site/ios/tutorial.html b/_site/ios/tutorial.html
deleted file mode 100644
index ba9d43f482..0000000000
--- a/_site/ios/tutorial.html
+++ /dev/null
@@ -1,1180 +0,0 @@
-
-
-
-
-
-
-
-
-iOS SDK Tutorial (Pre-release) | Blockstack
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- iOS SDK Tutorial (Pre-release)
-
-
-
-
-
-
-
-
This tutorial teaches you how to create a decentralized application using
-Blockstack’s iOS SDK using the following content:
-
-
-
-
This tutorial was extensively tested using XCode 9.3 on a MacBook Air
-running High Sierra 10.13.4. If your environment is different, you may encounter
-slight or even major discrepancies when performing the procedures in this
-tutorial. Please join the Blockstack community Slack and post questions or comments to
-the #support channel.
-
-
Finally, this tutorial is written for all levels from the beginner to the most
-experienced. For best results, beginners should follow the guide as written. It
-is expected that the fast or furiously brilliant will skip ahead and improvise
-on this material at will. God speed one and all.
-
-
If you prefer, you can skip working through the tutorial all together. Instead,
-you can download the final project code and import it
-into XCode to review it.
-
-
Understand the sample application flow
-
-
When complete, the sample application is a simple hello-world display. It is
-intended for user on an iOS phone.
-
-
-
-
Only users with an existing blockstack.id can run your
-final sample application. When complete, users interact with the sample
-application by doing the following:
-
-
-
-
Set up your environment
-
-
This sample application requires two code bases, a BlockStack hello-blockstack web
-application and a hello-ios iOS application. You use the iOS application to run the
-web application on an iOS device.
-
-
Before you start developing the sample, there are a few elements you need in
-your environment.
-
-
Install XCode
-
-
If you are an experienced iOS developer and already have an iOS
-development environment on your workstation, you can use that and skip this
-step. However, you may need to adjust the remaining instructions for your
-environment.
-
-
Follow the installation instructions to download and XCode for your operating system.
-Depending on your network connection, this can take between 15-30 minutes.
-
-
Do you have npm?
-
-
The Blockstack code in this tutorial relies on the npm dependency manager.
-Before you begin, verify you have installed npm using the which command to
-verify.
-
-
$ which npm
-/usr/local/bin/npm
-
-
-
-
If you don’t find npm in your system, install
-it .
-
-
Install the CocoaPods 1.6.0.beta.1 dependency manager
-
-
The sample application only runs on devices with iOS 11.0 or higher. You install
-the Blockstack iOS SDK through the CocoaPods dependency manager. You must use
-the 1.6.0.beta.1 version of CocoaPods or newer to avoid an incapability
-between Cocoapods and XCode.
-
-
Before starting the tutorial, confirm you have installed CocoaPods.
-
-
$ pod --version
-1.6.0.beta.1
-
-
-
-
If you don’t have the CocoaPods beta version, install it:
-
-
sudo gem install cocoapods -v 1.6.0.beta.1
-
-
-
-
Use npm to install Yeoman and the Blockstack App Generator
-
-
You use npm to install Yeoman. Yeoman is a generic scaffolding system that
-helps users rapidly start new projects and streamline the maintenance of
-existing projects.
-
-
-
- Install Yeoman.
-
-
-
-
- Install the Blockstack application generator.
-
- npm install -g generator-blockstack
-
-
- Build the Blockstack hello-world
-
-
-
-
In this section, you build a Blockstack hello-world application. Then, you
-modify the hello-world to interact with the iOS app via a redirect.
-
-
Generate and launch your hello-blockstack application
-
-
In this section, you build an initial React.js application called
-hello-blockstack.
-
-
-
- Create a hello-blockstack directory.
-
- mkdir hello-blockstack
-
-
-
-
- Change into your new directory.
-
-
-
-
- Use Yeoman and the Blockstack application generator to create your initial hello-blockstack application.
-
-
-
- You should see several interactive prompts.
-
- $ yo blockstack:react
- ==========================================================================
- We are constantly looking for ways to make yo better!
- May we anonymously report usage statistics to improve the tool over time ?
- More info: https://github.com/yeoman/insight & http://yeoman.io
- ========================================================================== No
-
- _-----_ ╭──────────────────────────╮
- | | │ Welcome to the │
- |--( o) --| │ Blockstack app │
- ` ---------´ │ generator! │
- ( _´U` _ ) ╰──────────────────────────╯
- /___A___\ /
- | ~ |
- __'.___.' __
- ´ ` |° ´ Y `
-
- ? Are you ready to build a Blockstack app in React? ( Y/n)
-
-
-
-
- Respond to the prompts to populate the initial app.
-
- After the process completes successfully, you see a prompt similar to the following:
-
- [ fsevents] Success:
- "/Users/theuser/repos/hello-blockstack/node_modules/fsevents/lib/binding/Release/node-v59-darwin-x64/fse.node"
- is installed via remote npm notice created a lockfile as package-lock.json.
- You should commit this file. added 1060 packages in 26.901s
-
-
-
-
- Run the initial application.
-
- npm start
-
- > hello-blockstack@0.0.0 start /Users/moxiegirl/repos/hello-blockstack
- > webpack-dev-server
-
- Project is running at http://localhost:8080/
- webpack output is served from /
- 404s will fallback to /index.html
- Hash: 4d2312ba236a4b95dc3a
- Version: webpack 2.7.0
- Time: 2969ms
- Asset Size Chunks Chunk Names
- ....
- Child html-webpack-plugin for "index.html" :
- chunk { 0} index.html 541 kB [ entry] [ rendered]
- [ 0] ./~/lodash/lodash.js 540 kB { 0} [ built]
- [ 1] ./~/html-webpack-plugin/lib/loader.js!./src/index.html 533 bytes { 0} [ built]
- [ 2] ( webpack) /buildin/global.js 509 bytes { 0} [ built]
- [ 3] ( webpack) /buildin/module.js 517 bytes { 0} [ built]
- webpack: Compiled successfully.
-
-
-
- The system opens a browser displaying your running application.
-
-
-
-
-
-
At this point, the browser is running a Blockstack server on your local host.
- This is for testing your applications only.
-
-
-
- Choose Sign in with Blockstack
-
- The system displays a prompt allowing you to create a new Blockstack ID or restore an existing one.
-
-
-
-
- Follow the prompts appropriate to your situation.
-
- If you are restoring an existing ID, you may see a prompt about your user
- being nameless, ignore it. At this point you have only a single application
- on your test server. So, you should see this single application, with your
- own blockstack.id display name, once you are signed in:
-
-
-
-
-
-
Add a redirect end point to your application
-
-
When a user opens the webapp from the Blockstack browser on an iOS phone,
-you want the web app to redirect the user to your iOS application. The work
-you do here will allow it.
-
-
-
- From the terminal command line, change directory to the root of your web
-application directory.
-
-
- Use the touch command to add a redirect endpoint to your application.
-
- This endpoint on the web version of your app will redirect iOS users back
-to your mobile app.
-
- $ touch public/redirect.html
-
-
-
-
- Open redirect.html and add code to the endpoint.
-
- <!DOCTYPE html>
- <html>
- <head>
- <title> Hello, Blockstack!</title>
- <script>
- function getParameterByName ( name ) {
- var match = RegExp ( '[?&]' + name + '=([^&]*)' ). exec ( window . location . search );
- return match && decodeURIComponent ( match [ 1 ]. replace ( / \+ /g , ' ' ));
- }
-
- var authResponse = getParameterByName ( 'authResponse' )
- window . location = "myblockstackapp:" + authResponse
- </script>
- <body>
- </body>
- </html>
-
-
-
- Blockstack apps are identified by their domain names. The endpoint will
- receive a get request with the query parameter authResponse=XXXX and
- should redirect the browser to myblockstackapp:XXXX.
-
- myblockstackapp: is custom protocol handler. The handler should be unique
- to your application. Your app’s web-based authentication uses this handler
- to redirect the user back to your iOS app. Later, you’ll add a reference
- to this handler in your iOS application.
-
- Close and save the redirect.html file.
- Ensure your Blockstack compiles successfully.
-
-
-
Build the hello-blockstack-ios
-
-
Now, you build an iOS application that can access and run your Blockstack web
-application on a mobile device.
-
-
Create an XCode Project
-
-
This tutorial uses XCode 9.3, you can use another version but be aware that some
-menu items and therefore these procedures may be differœent on your version.
-
-
- Launch the XCode interface.
- Choose Create new XCode project .
- Select iOS .
-
- Select Single View Page .
-
-
-
-
- Choose options for your new project for your project.
-
-
-
-
- Press Next .
-
- The system prompts you for a location to store your code.
-
- Save your project.
- Close XCode.
-
-
-
Add and edit a Podfile
-
-
To use CocoaPods you need to define the XCode target to link them to.
-So for example if you are writing an iOS app, it would be the name of your app.
-Create a target section by writing target ‘$TARGET_NAME’ do and an end a few
-lines after.
-
-
- Open a terminal window on your workstation.
-
- Navigate to and change directory into the root of your project directory.
-
- $ cd hello - blockstack - ios
-
-
-
-
- Create a Podfile.
-
-
-
- The command creates a Podfile in the directory.
-
- Open the Podfile for editing.
-
- Add a line stating the Blockstack dependency.
-
- # Uncomment the next line to define a global platform for your project
-# platform :ios, '9.0'
-
-target 'hello-blockstack-ios' do
- # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
- use_frameworks!
-
- # Pods for hello-blockstack-ios
- pod 'Blockstack'
-
- target 'hello-blockstack-iosTests' do
- inherit! :search_paths
- # Pods for testing
- end
-end
-
-
-
- Save and close the Podfile.
-
-
-
Install Blockstack SDK and open the pod project
-
-
- Close your new XCode project.
- Change to the root of your hello-blockstack-is project.
-
- Initialize the project with Cocoapods.
-
- $ pod install
- Analyzing dependencies
- Downloading dependencies
- Installing Blockstack (0.2.0)
- Installing CryptoSwift (0.11.0)
- Generating Pods project
- Integrating client project
-
- [!] Please close any current XCode sessions and use `hello-blockstack-ios.xcworkspace` for this project from now on.
- Sending stats
- Pod installation complete! There is 1 dependency from the Podfile and 2 total pods installed.
-
- [!] Automatically assigning platform `ios` with version `11.4` on target `hello-blockstack-ios` because no platform was specified. Please specify a platform for this target in your Podfile. See `https://guides.cocoapods.org/syntax/podfile.html#platform`.
-
-
-
- This command creates a number of files
-
-
- Review the files that the pod installation created:
-
- $ ls
-Podfile hello-blockstack-ios hello-blockstack-iosTests
-Podfile.lock hello-blockstack-ios.xcodeproj
-Pods hello-blockstack-ios.xcworkspace
-
-
-
- Start XCode and choose Open another project .
-
- Choose the .xcworkspace file created in your project folder.
-
-
-
- When you open the workspace you’ll see a warning indicator at the top in the
- project title.
-
- Click the signal to reveal the warning.
-
- Click Update to recommented settings .
-
-
-
-
- Choose Perform Changes and Continue when prompted.
-
- The indicator disappears.
-
-
-
-
Choose a custom protocol handler
-
-
You’ll need to choose a custom protocol handler that is unique to your app. This
-is so that your app’s web-based authentication redirect.html endpoint can redirect
-the user back to your iOS app. In this example, you use myblockstackapp://.
-
-
- Open the .xcworkspace file in XCode if it isn’t open already.
- Select the top node of your project.
- Select the Info tab in XCode.
- Scroll to URL Types and press + (plus) sign.
- Enter an Identifier and URL Schemes value.
-
- Set the Role to Editor .
-
- When you are done the type appears as follows:
-
-
-
-
-
-
Add a splash screen
-
-
All iOS applications require a splash page.
-
-
- Select Assets.xcassets
- Move your cursor into the area below Appicon.
-
- Right click and choose New Image Set
-
-
-
-
- Download the Blockstack icon.
-
-
-
-
- Drag the downloaded file into the 3X position in your new Images folder.
-
-
-
- Select the LaunchScreen.storyboard.
-
- Choose Open As > Source Code .
-
-
-
-
- Replace the content of the <scenes> element with the following:
-
- <scenes>
- <!--View Controller-->
- <scene sceneID="EHf-IW-A2E">
- <objects>
- <viewController id="01J-lp-oVM" sceneMemberID="viewController">
- <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
- <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
- <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
- <subviews>
- <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="Image" translatesAutoresizingMaskIntoConstraints="NO" id="SpU-hA-y2f">
- <rect key="frame" x="155.5" y="273" width="64" height="64"/>
- </imageView>
- <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Hello Blockstack iOS" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Wfj-A6-BZM">
- <rect key="frame" x="108" y="432" width="158" height="21"/>
- <fontDescription key="fontDescription" type="system" pointSize="17"/>
- <nil key="textColor"/>
- <nil key="highlightedColor"/>
- </label>
- </subviews>
- <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
- <constraints>
- <constraint firstItem="Wfj-A6-BZM" firstAttribute="centerX" secondItem="6Tk-OE-BBY" secondAttribute="centerX" id="AZy-qf-xHq"/>
- <constraint firstItem="Wfj-A6-BZM" firstAttribute="top" secondItem="6Tk-OE-BBY" secondAttribute="top" constant="412" id="SwP-qV-1RP"/>
- <constraint firstItem="SpU-hA-y2f" firstAttribute="centerX" secondItem="6Tk-OE-BBY" secondAttribute="centerX" id="XdI-Db-fDo"/>
- <constraint firstItem="SpU-hA-y2f" firstAttribute="top" secondItem="6Tk-OE-BBY" secondAttribute="top" constant="253" id="xc5-po-W1E"/>
- </constraints>
- <viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
- </view>
- </viewController>
- <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
- </objects>
- <point key="canvasLocation" x="52" y="374.66266866566718"/>
- </scene>
-</scenes>
-
-
-
-
- Immediately after scenes but before the close of the </document> tag add the following <resources>.
-
- <resources>
- <image name= "Image" width= "64" height= "64" />
- </resources>
- </document>
-
-
-
-
- Choose Run > Run app in the emulator.
-
- The emulator now contains a new splash screen.
-
-
-
-
-
-
Add a Main.storyboard
-
-
Rather than have you build up your own UI, this section has you copy and paste a layout into the XML file source code for the Main.storyboard file.
-
-
- Select the Main.storyboard file.
-
- Chooose Open As > Source Code
-
- The blockstack-example/blockstack-example/Base.lproj/Main.storyboard file
-defines the graphical elements. Some elements are required before you can
-functionality to your code.
-
-
- Replace the element with the following:
-
- <view key= "view" contentMode= "scaleToFill" id= "8bC-Xf-vdC" >
- <rect key= "frame" x= "0.0" y= "0.0" width= "375" height= "667" />
- <autoresizingMask key= "autoresizingMask" widthSizable= "YES" heightSizable= "YES" />
- <subviews>
- <label opaque= "NO" userInteractionEnabled= "NO" contentMode= "left" horizontalHuggingPriority= "251" verticalHuggingPriority= "251" text= "hello-blockstack-ios" textAlignment= "center" lineBreakMode= "tailTruncation" baselineAdjustment= "alignBaselines" adjustsFontSizeToFit= "NO" translatesAutoresizingMaskIntoConstraints= "NO" id= "9eE-ZS-LU9" >
- <rect key= "frame" x= "0.0" y= "101" width= "375" height= "50" />
- <color key= "backgroundColor" red= "0.44735813140000003" green= "0.1280144453" blue= "0.57268613580000005" alpha= "1" colorSpace= "custom" customColorSpace= "sRGB" />
- <constraints>
- <constraint firstAttribute= "height" constant= "50" id= "U5v-13-4Ux" />
- </constraints>
- <fontDescription key= "fontDescription" type= "system" pointSize= "17" />
- <color key= "textColor" white= "1" alpha= "1" colorSpace= "custom" customColorSpace= "genericGamma22GrayColorSpace" />
- <nil key= "highlightedColor" />
- </label>
- <button opaque= "NO" contentMode= "scaleToFill" contentHorizontalAlignment= "center" contentVerticalAlignment= "center" buttonType= "roundedRect" lineBreakMode= "middleTruncation" translatesAutoresizingMaskIntoConstraints= "NO" id= "Lfp-KX-BDb" >
- <rect key= "frame" x= "100" y= "382" width= "175" height= "40" />
- <color key= "backgroundColor" red= "0.1215686275" green= "0.12941176469999999" blue= "0.14117647059999999" alpha= "1" colorSpace= "custom" customColorSpace= "sRGB" />
- <constraints>
- <constraint firstAttribute= "height" constant= "40" id= "8fN-Ro-Krn" />
- </constraints>
- <color key= "tintColor" white= "0.0" alpha= "1" colorSpace= "calibratedWhite" />
- <state key= "normal" title= "Sign into Blocksack" >
- <color key= "titleColor" white= "1" alpha= "1" colorSpace= "custom" customColorSpace= "genericGamma22GrayColorSpace" />
- </state>
- <connections>
- <action selector= "signIn:" destination= "BYZ-38-t0r" eventType= "touchUpInside" id= "nV7-rt-euZ" />
- </connections>
- </button>
- </subviews>
- <color key= "backgroundColor" red= "1" green= "1" blue= "1" alpha= "1" colorSpace= "custom" customColorSpace= "sRGB" />
- <constraints>
- <constraint firstItem= "9eE-ZS-LU9" firstAttribute= "leading" secondItem= "6Tk-OE-BBY" secondAttribute= "leading" id= "2ZP-tU-h9Y" />
- <constraint firstItem= "9eE-ZS-LU9" firstAttribute= "top" secondItem= "6Tk-OE-BBY" secondAttribute= "top" constant= "81" id= "DBh-q0-pAV" />
- <constraint firstItem= "6Tk-OE-BBY" firstAttribute= "trailing" secondItem= "Lfp-KX-BDb" secondAttribute= "trailing" constant= "100" id= "MHO-ew-4Bd" />
- <constraint firstItem= "Lfp-KX-BDb" firstAttribute= "leading" secondItem= "6Tk-OE-BBY" secondAttribute= "leading" constant= "100" id= "Rsm-LP-ya7" />
- <constraint firstItem= "Lfp-KX-BDb" firstAttribute= "top" secondItem= "6Tk-OE-BBY" secondAttribute= "top" constant= "362" id= "chE-B7-ya6" />
- <constraint firstItem= "6Tk-OE-BBY" firstAttribute= "trailing" secondItem= "9eE-ZS-LU9" secondAttribute= "trailing" id= "j0x-8j-04u" />
- </constraints>
- <viewLayoutGuide key= "safeArea" id= "6Tk-OE-BBY" />
- </view>
-
-
-
-
-
-
Add the UI variables to the ViewController file.
-
-
In this section, you edit the ViewController.swift file using the storyboard as a starting point.
-
-
-
- Select the Main.storyboard and choose Open As > Interface Builder - storyboard .
-
-
-
-
- With the interface builder open, display the ViewController.swift file in the rigth panel.
-
-
-
-
- In the storyboard, select the Sign into Blockstack button.
-
-
- Control-drag from the button to the code display in the editor on the right, stopping the drag at the line below controller’s opening statement.
-
-
-
-
- Repeat this process with the storyboard’s purple hello-blockstack-ios label.
-
- When you are done, your ViewController file contains the following variables:
-
- class ViewController : UIViewController {
-
- @IBOutlet var nameLabel : UILabel !
- @IBOutlet var signInButton : UIButton !
-
-
-
- And XCode has added two outlines to the Main.storyboard source.
-
- <connections>
- <outlet property= "nameLabel" destination= "9eE-ZS-LU9" id= "Ahv-Te-ZZo" />
- <outlet property= "signInButton" destination= "Lfp-KX-BDb" id= "yef-Jj-uPt" />
- </connections>
-
-
-
- Your connectors will have their own destination and id values.
-
-
-
-
Edit the ViewController.swift file
-
-
Now, you are ready to connect your applicaiton with your Blockstack Web
-Application. Normally, after building your Web application you would have
-registred it with Blockstack and the app would be available on the Web. This
-example skips this registroation step and uses an example application we’ve
-already created for you:
-
-
https://heuristic-brown-7a88f8.netlify.com/redirect.html
-
-
This web application already has a redirect in place for you. You’ll reference
-this application in your mobile add for now. In XCode, do the following;
-
-
- Open the ViewController.swift file.
-
- Add an import both for Blockstack and for SafariServices.
-
- import UIKit
- import Blockstack
- import SafariServices
-
-
-
-
- Just before the didReceiveMemoryWarning function a private updateUI function.
-
- This function takes care of loading the user data from Blockstack.
-
- private func updateUI() {
- DispatchQueue.main.async {
- if Blockstack.shared.isSignedIn() {
- // Read user profile data
- let retrievedUserData = Blockstack.shared.loadUserData()
- print(retrievedUserData?.profile?.name as Any)
- let name = retrievedUserData?.profile?.name ?? "Nameless Person"
- self.nameLabel?.text = "Hello, \(name)"
- self.nameLabel?.isHidden = false
- self.signInButton?.setTitle("Sign Out", for: .normal)
- } else {
- self.signInButton?.setTitle("Sign into Blockstack", for: .normal)
- }
- }
- }
-
-
-
-
- Replace the content of the viewDidLoad() function so that it calls this private function.
-
- override func viewDidLoad() {
- self.updateUI()
-}
-
-
-
-
- Add a handleSignInSuccess() function to handle sign in.
-
- func handleSignInSuccess(userData: UserData) {
- print(userData.profile?.name as Any)
-
- self.updateUI()
-
- // Check if signed in
- // checkIfSignedIn()
- }
-
-
-
-
- Add a signOut() function to handle signOut
-
- @IBAction func signOut(_ sender: Any) {
- // Sign user out
- Blockstack.shared.signOut(redirectURI: "myBlockstackApp") { error in
- if let error = error {
- print("sign out failed, error: \(error)")
- } else {
- self.updateUI()
- print("sign out success")
- }
- }
- }
-
-
-
-
- Add a function to check if a user is signed in
-
- func checkIfSignedIn () {
- Blockstack . shared . isSignedIn () ? print ( "currently signed in" ) : print ( "not signed in" )
- }
-
-
-
-
- Put it all together with a signin buttonType
-
- @IBAction func signIn ( _ sender : UIButton ) {
- // Address of deployed example web app
- Blockstack . shared . signIn ( redirectURI : "https://heuristic-brown-7a88f8.netlify.com/redirect.html" ,
- appDomain : URL ( string : "https://heuristic-brown-7a88f8.netlify.com" ) ! ) { authResult in
- switch authResult {
- case . success ( let userData ):
- print ( "sign in success" )
- self . handleSignInSuccess ( userData : userData )
- case . cancelled :
- print ( "sign in cancelled" )
- case . failed ( let error ):
- print ( "sign in failed, error: " , error ?? "n/a" )
- }
- }
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Related Articles
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Blockstack
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/_site/news/index.html b/_site/news/index.html
deleted file mode 100644
index 2ef7d9b5dc..0000000000
--- a/_site/news/index.html
+++ /dev/null
@@ -1,293 +0,0 @@
-
-
-
-
-
-
-
-
-
News | Blockstack
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
News
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Blockstack
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/_site/package.json b/_site/package.json
deleted file mode 100644
index 65298ac475..0000000000
--- a/_site/package.json
+++ /dev/null
@@ -1,41 +0,0 @@
-{
- "name": "docs",
- "version": "1.0.0",
- "description": "Docs Jekyll theme.",
- "main": "index.js",
- "scripts": {
- "test": "echo \"Error: no test specified\" && exit 1",
- "copy": "ncp node_modules/uikit/src/scss/ _sass/uikit/ && ncp node_modules/system-font-css/ _sass/system-font-css/",
- "lint": "jshint assets/js/custom.js",
- "uglify": "uglifyjs node_modules/uikit/dist/js/uikit.js node_modules/uikit/dist/js/uikit-icons.js node_modules/simple-jekyll-search/dest/simple-jekyll-search.js assets/js/custom.js -m -c -o assets/js/main.js",
- "concat": "uglifyjs node_modules/uikit/dist/js/uikit.js node_modules/uikit/dist/js/uikit-icons.js node_modules/simple-jekyll-search/dest/simple-jekyll-search.js assets/js/custom.js -b -o assets/js/main.js",
- "dev": "npm run lint && npm run concat",
- "build": "npm run lint && npm run uglify",
- "watch": "watch 'npm run dev' assets/js/",
- "postinstall": "npm run copy && npm run concat"
- },
- "repository": {
- "type": "git",
- "url": "git+https://github.com/"
- },
- "author": "moxiegirl",
- "license": "MIT",
- "bugs": {
- "url": "https://github.com/"
- },
- "homepage": "https://github.com/",
- "dependencies": {
- "simple-jekyll-search": "^1.5.0",
- "system-font-css": "^2.0.1",
- "uikit": "^3.0.0-beta.42"
- },
- "devDependencies": {
- "jshint": "^2.9.5",
- "ncp": "latest",
- "uglify-js": "^3.2.1",
- "watch": "^1.0.2"
- },
- "directories": {
- "doc": "docs"
- }
-}
diff --git a/_site/robots.txt b/_site/robots.txt
deleted file mode 100644
index 1f53798bb4..0000000000
--- a/_site/robots.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-User-agent: *
-Disallow: /
diff --git a/_site/search.json b/_site/search.json
deleted file mode 100644
index 3c5c1916ab..0000000000
--- a/_site/search.json
+++ /dev/null
@@ -1,3 +0,0 @@
-[
-
-]
diff --git a/_site/staticman.yml b/_site/staticman.yml
deleted file mode 100644
index 5dc758657d..0000000000
--- a/_site/staticman.yml
+++ /dev/null
@@ -1,77 +0,0 @@
-# Name of the property. You can have multiple properties with completely
-# different config blocks for different sections of your site.
-# For example, you can have one property to handle comment submission and
-# another one to handle posts.
-comments:
- # (*) REQUIRED
- #
- # Names of the fields the form is allowed to submit. If a field that is
- # not here is part of the request, an error will be thrown.
- allowedFields: ["name", "email", "url", "message"]
-
- # (*) REQUIRED
- #
- # Name of the branch being used. Must match the one sent in the URL of the
- # request.
- branch: "master"
-
- # Text to use as the commit message or pull request title. Accepts placeholders.
- commitMessage: "Add Staticman data"
-
- # (*) REQUIRED
- #
- # Destination path (filename) for the data files. Accepts placeholders.
- filename: "entry{@timestamp}"
-
- # The format of the generated data files. Accepted values are "json", "yaml"
- # or "frontmatter"
- format: "yaml"
-
- # List of fields to be populated automatically by Staticman and included in
- # the data file. Keys are the name of the field. The value can be an object
- # with a `type` property, which configures the generated field, or any value
- # to be used directly (e.g. a string, number or array)
- generatedFields:
- date:
- type: date
- options:
- format: "timestamp-seconds"
-
- # Whether entries need to be appproved before they are published to the main
- # branch. If set to `true`, a pull request will be created for your approval.
- # Otherwise, entries will be published to the main branch automatically.
- moderation: true
-
- # Name of the site. Used in notification emails.
- name: "zbabystack.netlify.com"
-
- # Notification settings. When enabled, users can choose to receive notifications
- # via email when someone adds a reply or a new comment. This requires an account
- # with Mailgun, which you can get for free at http://mailgun.com.
- #notifications:
- # Enable notifications
- #enabled: true
-
- # (!) ENCRYPTED
- #
- # Mailgun API key
- #apiKey: "1q2w3e4r"
-
- # (!) ENCRYPTED
- #
- # Mailgun domain (encrypted)
- #domain: "4r3e2w1q"
-
- # (*) REQUIRED
- #
- # Destination path (directory) for the data files. Accepts placeholders.
- path: "_data/comments/{options.slug}"
-
- # Names of required fields. If any of these isn't in the request or is empty,
- # an error will be thrown.
- requiredFields: ["name", "email", "message"]
-
- # List of transformations to apply to any of the fields supplied. Keys are
- # the name of the field and values are possible transformation types.
- transforms:
- email: md5
diff --git a/_site/thanks/index.html b/_site/thanks/index.html
deleted file mode 100644
index 485ae8f07e..0000000000
--- a/_site/thanks/index.html
+++ /dev/null
@@ -1,269 +0,0 @@
-
-
-
-
-
-
-
-
-
Thanks | Blockstack
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Thanks
-
-
-
Varius tempor. Nulla non sollicitudin tortor. Morbi sit amet laoreet ipsum, vel pretium mi. Morbi varius, tellus in accumsan blandit, elit ligula eleifend velit, luctus mattis ante nulla condimentum nulla.
-
-
Ut malesuada varius tempor. Nulla non sollicitudin tortor. Morbi sit amet laoreet ipsum, vel pretium mi. Morbi varius, tellus in accumsan blandit, elit ligula eleifend velit, luctus mattis ante nulla condimentum nulla.
-
-
Mesuada varius tempor. Nulla non sollicitudin tortor. Morbi sit amet laoreet ipsum, vel pretium mi. Morbi varius, tellus in accumsan blandit, elit ligula eleifend velit, luctus mattis ante nulla condimentum nulla.
-
-
Varius tempor. Nulla non sollicitudin tortor. Morbi sit amet laoreet ipsum, vel pretium mi. Morbi varius, tellus in accumsan blandit, elit ligula eleifend velit, luctus mattis ante nulla condimentum nulla.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Blockstack
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/assets/css/main.scss b/assets/css/main.scss
deleted file mode 100644
index 109f4248b3..0000000000
--- a/assets/css/main.scss
+++ /dev/null
@@ -1,22 +0,0 @@
----
-# Only the main Sass file needs front matter (the dashes are enough)
----
-
-// System fonts
-@import "system-font-css/_system-font";
-
-// Custom variables and variable overwrites.
-@import "theme/variables";
-
-// Import default variables and available mixins.
-@import "uikit/variables-theme";
-@import "uikit/mixins-theme";
-
-// Custom mixin overwrites.
-@import "theme/mixins";
-
-// Import UIkit.
-@import "theme/uikit";
-
-// Other vendor styles
-@import "syntax-highlighting/github";
diff --git a/assets/img/favicon.png b/assets/img/favicon.png
deleted file mode 100644
index 09d6ca94a9..0000000000
Binary files a/assets/img/favicon.png and /dev/null differ
diff --git a/assets/img/location.svg b/assets/img/location.svg
deleted file mode 100644
index e71e58b04c..0000000000
--- a/assets/img/location.svg
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
- location-dark
- Created with Sketch.
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/assets/img/touch-icon.png b/assets/img/touch-icon.png
deleted file mode 100644
index 243615bb9f..0000000000
Binary files a/assets/img/touch-icon.png and /dev/null differ
diff --git a/assets/js/custom.js b/assets/js/custom.js
deleted file mode 100644
index d123eb3515..0000000000
--- a/assets/js/custom.js
+++ /dev/null
@@ -1 +0,0 @@
-// Custom scripts
diff --git a/assets/js/main.js b/assets/js/main.js
deleted file mode 100644
index 031cf722e2..0000000000
--- a/assets/js/main.js
+++ /dev/null
@@ -1,8772 +0,0 @@
-(function(global, factory) {
- typeof exports === "object" && typeof module !== "undefined" ? module.exports = factory() : typeof define === "function" && define.amd ? define("uikit", factory) : global.UIkit = factory();
-})(this, function() {
- "use strict";
- function bind(fn, context) {
- return function(a) {
- var l = arguments.length;
- return l ? l > 1 ? fn.apply(context, arguments) : fn.call(context, a) : fn.call(context);
- };
- }
- var ref = Object.prototype;
- var hasOwnProperty = ref.hasOwnProperty;
- function hasOwn(obj, key) {
- return hasOwnProperty.call(obj, key);
- }
- var hyphenateRe = /([a-z\d])([A-Z])/g;
- function hyphenate(str) {
- return str.replace(hyphenateRe, "$1-$2").toLowerCase();
- }
- var camelizeRE = /-(\w)/g;
- function camelize(str) {
- return str.replace(camelizeRE, toUpper);
- }
- function toUpper(_, c) {
- return c ? c.toUpperCase() : "";
- }
- function ucfirst(str) {
- return str.length ? toUpper(null, str.charAt(0)) + str.slice(1) : "";
- }
- var strPrototype = String.prototype;
- var startsWithFn = strPrototype.startsWith || function(search) {
- return this.lastIndexOf(search, 0) === 0;
- };
- function startsWith(str, search) {
- return startsWithFn.call(str, search);
- }
- var endsWithFn = strPrototype.endsWith || function(search) {
- return this.substr(-search.length) === search;
- };
- function endsWith(str, search) {
- return endsWithFn.call(str, search);
- }
- var includesFn = function(search) {
- return ~this.indexOf(search);
- };
- var includesStr = strPrototype.includes || includesFn;
- var includesArray = Array.prototype.includes || includesFn;
- function includes(obj, search) {
- return obj && (isString(obj) ? includesStr : includesArray).call(obj, search);
- }
- var isArray = Array.isArray;
- function isFunction(obj) {
- return typeof obj === "function";
- }
- function isObject(obj) {
- return obj !== null && typeof obj === "object";
- }
- function isPlainObject(obj) {
- return isObject(obj) && Object.getPrototypeOf(obj) === Object.prototype;
- }
- function isWindow(obj) {
- return isObject(obj) && obj === obj.window;
- }
- function isDocument(obj) {
- return isObject(obj) && obj.nodeType === 9;
- }
- function isJQuery(obj) {
- return isObject(obj) && !!obj.jquery;
- }
- function isNode(element) {
- return element instanceof Node || isObject(element) && element.nodeType === 1;
- }
- function isNodeCollection(element) {
- return element instanceof NodeList || element instanceof HTMLCollection;
- }
- function isBoolean(value) {
- return typeof value === "boolean";
- }
- function isString(value) {
- return typeof value === "string";
- }
- function isNumber(value) {
- return typeof value === "number";
- }
- function isNumeric(value) {
- return isNumber(value) || isString(value) && !isNaN(value - parseFloat(value));
- }
- function isUndefined(value) {
- return value === void 0;
- }
- function toBoolean(value) {
- return isBoolean(value) ? value : value === "true" || value === "1" || value === "" ? true : value === "false" || value === "0" ? false : value;
- }
- function toNumber(value) {
- var number = Number(value);
- return !isNaN(number) ? number : false;
- }
- function toFloat(value) {
- return parseFloat(value) || 0;
- }
- function toNode(element) {
- return isNode(element) || isWindow(element) || isDocument(element) ? element : isNodeCollection(element) || isJQuery(element) ? element[0] : isArray(element) ? toNode(element[0]) : null;
- }
- var arrayProto = Array.prototype;
- function toNodes(element) {
- return isNode(element) ? [ element ] : isNodeCollection(element) ? arrayProto.slice.call(element) : isArray(element) ? element.map(toNode).filter(Boolean) : isJQuery(element) ? element.toArray() : [];
- }
- function toList(value) {
- return isArray(value) ? value : isString(value) ? value.split(/,(?![^(]*\))/).map(function(value) {
- return isNumeric(value) ? toNumber(value) : toBoolean(value.trim());
- }) : [ value ];
- }
- function toMs(time) {
- return !time ? 0 : endsWith(time, "ms") ? toFloat(time) : toFloat(time) * 1e3;
- }
- function swap(value, a, b) {
- return value.replace(new RegExp(a + "|" + b, "mg"), function(match) {
- return match === a ? b : a;
- });
- }
- var assign = Object.assign || function(target) {
- var args = [], len = arguments.length - 1;
- while (len-- > 0) args[len] = arguments[len + 1];
- target = Object(target);
- for (var i = 0; i < args.length; i++) {
- var source = args[i];
- if (source !== null) {
- for (var key in source) {
- if (hasOwn(source, key)) {
- target[key] = source[key];
- }
- }
- }
- }
- return target;
- };
- function each(obj, cb) {
- for (var key in obj) {
- if (cb.call(obj[key], obj[key], key) === false) {
- break;
- }
- }
- }
- function sortBy(collection, prop) {
- return collection.sort(function(a, b) {
- return a[prop] - b[prop];
- });
- }
- function clamp(number, min, max) {
- if (min === void 0) min = 0;
- if (max === void 0) max = 1;
- return Math.min(Math.max(number, min), max);
- }
- function noop() {}
- function intersectRect(r1, r2) {
- return r1.left <= r2.right && r2.left <= r1.right && r1.top <= r2.bottom && r2.top <= r1.bottom;
- }
- function pointInRect(point, rect) {
- return intersectRect({
- top: point.y,
- bottom: point.y,
- left: point.x,
- right: point.x
- }, rect);
- }
- var Dimensions = {
- ratio: function ratio(dimensions, prop, value) {
- var obj;
- var aProp = prop === "width" ? "height" : "width";
- return obj = {}, obj[aProp] = Math.round(value * dimensions[aProp] / dimensions[prop]),
- obj[prop] = value, obj;
- },
- contain: function contain(dimensions, maxDimensions) {
- var this$1 = this;
- dimensions = assign({}, dimensions);
- each(dimensions, function(_, prop) {
- return dimensions = dimensions[prop] > maxDimensions[prop] ? this$1.ratio(dimensions, prop, maxDimensions[prop]) : dimensions;
- });
- return dimensions;
- },
- cover: function cover(dimensions, maxDimensions) {
- var this$1 = this;
- dimensions = this.contain(dimensions, maxDimensions);
- each(dimensions, function(_, prop) {
- return dimensions = dimensions[prop] < maxDimensions[prop] ? this$1.ratio(dimensions, prop, maxDimensions[prop]) : dimensions;
- });
- return dimensions;
- }
- };
- function attr(element, name, value) {
- if (isObject(name)) {
- for (var key in name) {
- attr(element, key, name[key]);
- }
- return;
- }
- if (isUndefined(value)) {
- element = toNode(element);
- return element && element.getAttribute(name);
- } else {
- toNodes(element).forEach(function(element) {
- if (isFunction(value)) {
- value = value.call(element, attr(element, name));
- }
- if (value === null) {
- removeAttr(element, name);
- } else {
- element.setAttribute(name, value);
- }
- });
- }
- }
- function hasAttr(element, name) {
- return toNodes(element).some(function(element) {
- return element.hasAttribute(name);
- });
- }
- function removeAttr(element, name) {
- element = toNodes(element);
- name.split(" ").forEach(function(name) {
- return element.forEach(function(element) {
- return element.removeAttribute(name);
- });
- });
- }
- function filterAttr(element, attribute, pattern, replacement) {
- attr(element, attribute, function(value) {
- return value ? value.replace(pattern, replacement) : value;
- });
- }
- function data(element, attribute) {
- for (var i = 0, attrs = [ attribute, "data-" + attribute ]; i < attrs.length; i++) {
- if (hasAttr(element, attrs[i])) {
- return attr(element, attrs[i]);
- }
- }
- }
- function query(selector, context) {
- return toNode(selector) || find(selector, isContextSelector(selector) ? context : document);
- }
- function queryAll(selector, context) {
- var nodes = toNodes(selector);
- return nodes.length && nodes || findAll(selector, isContextSelector(selector) ? context : document);
- }
- function find(selector, context) {
- return toNode(_query(selector, context, "querySelector"));
- }
- function findAll(selector, context) {
- return toNodes(_query(selector, context, "querySelectorAll"));
- }
- function _query(selector, context, queryFn) {
- if (context === void 0) context = document;
- if (!selector || !isString(selector)) {
- return null;
- }
- selector = selector.replace(contextSanitizeRe, "$1 *");
- var removes;
- if (isContextSelector(selector)) {
- removes = [];
- selector = selector.split(",").map(function(selector, i) {
- var ctx = context;
- selector = selector.trim();
- if (selector[0] === "!") {
- var selectors = selector.substr(1).trim().split(" ");
- ctx = closest(context.parentNode, selectors[0]);
- selector = selectors.slice(1).join(" ");
- }
- if (!ctx) {
- return null;
- }
- if (!ctx.id) {
- ctx.id = "uk-" + Date.now() + i;
- removes.push(function() {
- return removeAttr(ctx, "id");
- });
- }
- return "#" + escape(ctx.id) + " " + selector;
- }).filter(Boolean).join(",");
- context = document;
- }
- try {
- return context[queryFn](selector);
- } catch (e) {
- return null;
- } finally {
- removes && removes.forEach(function(remove) {
- return remove();
- });
- }
- }
- var contextSelectorRe = /(^|,)\s*[!>+~]/;
- var contextSanitizeRe = /([!>+~])(?=\s+[!>+~]|\s*$)/g;
- function isContextSelector(selector) {
- return isString(selector) && selector.match(contextSelectorRe);
- }
- var elProto = Element.prototype;
- var matchesFn = elProto.matches || elProto.webkitMatchesSelector || elProto.msMatchesSelector;
- function matches(element, selector) {
- return toNodes(element).some(function(element) {
- return matchesFn.call(element, selector);
- });
- }
- var closestFn = elProto.closest || function(selector) {
- var ancestor = this;
- do {
- if (matches(ancestor, selector)) {
- return ancestor;
- }
- ancestor = ancestor.parentNode;
- } while (ancestor && ancestor.nodeType === 1);
- };
- function closest(element, selector) {
- if (startsWith(selector, ">")) {
- selector = selector.slice(1);
- }
- return isNode(element) ? element.parentNode && closestFn.call(element, selector) : toNodes(element).map(function(element) {
- return element.parentNode && closestFn.call(element, selector);
- }).filter(Boolean);
- }
- function parents(element, selector) {
- var elements = [];
- var parent = toNode(element).parentNode;
- while (parent && parent.nodeType === 1) {
- if (matches(parent, selector)) {
- elements.push(parent);
- }
- parent = parent.parentNode;
- }
- return elements;
- }
- var escapeFn = window.CSS && CSS.escape || function(css) {
- return css.replace(/([^\x7f-\uFFFF\w-])/g, function(match) {
- return "\\" + match;
- });
- };
- function escape(css) {
- return isString(css) ? escapeFn.call(null, css) : "";
- }
- var voidElements = {
- area: true,
- base: true,
- br: true,
- col: true,
- embed: true,
- hr: true,
- img: true,
- input: true,
- keygen: true,
- link: true,
- menuitem: true,
- meta: true,
- param: true,
- source: true,
- track: true,
- wbr: true
- };
- function isVoidElement(element) {
- return toNodes(element).some(function(element) {
- return voidElements[element.tagName.toLowerCase()];
- });
- }
- function isVisible(element) {
- return toNodes(element).some(function(element) {
- return element.offsetHeight || element.getBoundingClientRect().height;
- });
- }
- var selInput = "input,select,textarea,button";
- function isInput(element) {
- return toNodes(element).some(function(element) {
- return matches(element, selInput);
- });
- }
- function filter(element, selector) {
- return toNodes(element).filter(function(element) {
- return matches(element, selector);
- });
- }
- function within(element, selector) {
- return !isString(selector) ? element === selector || (isDocument(selector) ? selector.documentElement : toNode(selector)).contains(toNode(element)) : matches(element, selector) || closest(element, selector);
- }
- function on() {
- var args = [], len = arguments.length;
- while (len--) args[len] = arguments[len];
- var ref = getArgs(args);
- var target = ref[0];
- var type = ref[1];
- var selector = ref[2];
- var listener = ref[3];
- var useCapture = ref[4];
- target = toEventTarget(target);
- if (selector) {
- listener = delegate(target, selector, listener);
- }
- if (listener.length > 1) {
- listener = detail(listener);
- }
- type.split(" ").forEach(function(type) {
- return target && target.addEventListener(type, listener, useCapture);
- });
- return function() {
- return off(target, type, listener, useCapture);
- };
- }
- function off(target, type, listener, useCapture) {
- if (useCapture === void 0) useCapture = false;
- target = toEventTarget(target);
- target && type.split(" ").forEach(function(type) {
- return target.removeEventListener(type, listener, useCapture);
- });
- }
- function once() {
- var args = [], len = arguments.length;
- while (len--) args[len] = arguments[len];
- var ref = getArgs(args);
- var element = ref[0];
- var type = ref[1];
- var selector = ref[2];
- var listener = ref[3];
- var useCapture = ref[4];
- var condition = ref[5];
- var off = on(element, type, selector, function(e) {
- var result = !condition || condition(e);
- if (result) {
- off();
- listener(e, result);
- }
- }, useCapture);
- return off;
- }
- function trigger(target, event, detail) {
- return toEventTargets(target).reduce(function(notCanceled, target) {
- return notCanceled && target.dispatchEvent(createEvent(event, true, true, detail));
- }, true);
- }
- function createEvent(e, bubbles, cancelable, detail) {
- if (bubbles === void 0) bubbles = true;
- if (cancelable === void 0) cancelable = false;
- if (isString(e)) {
- var event = document.createEvent("CustomEvent");
- event.initCustomEvent(e, bubbles, cancelable, detail);
- e = event;
- }
- return e;
- }
- function getArgs(args) {
- if (isString(args[0])) {
- args[0] = find(args[0]);
- }
- if (isFunction(args[2])) {
- args.splice(2, 0, false);
- }
- return args;
- }
- function delegate(element, selector, listener) {
- var this$1 = this;
- return function(e) {
- var target = e.target;
- var current = selector[0] === ">" ? findAll(selector, element).reverse().filter(function(element) {
- return within(target, element);
- })[0] : closest(target, selector);
- if (current) {
- e.delegate = element;
- e.current = current;
- listener.call(this$1, e);
- }
- };
- }
- function detail(listener) {
- return function(e) {
- return isArray(e.detail) ? listener.apply(listener, [ e ].concat(e.detail)) : listener(e);
- };
- }
- function isEventTarget(target) {
- return "EventTarget" in window ? target instanceof EventTarget : target && "addEventListener" in target;
- }
- function toEventTarget(target) {
- return isEventTarget(target) ? target : toNode(target);
- }
- function toEventTargets(target) {
- return isEventTarget(target) ? [ target ] : isArray(target) ? target.map(toEventTarget).filter(Boolean) : toNodes(target);
- }
- function preventClick() {
- var timer = setTimeout(once(document, "click", function(e) {
- e.preventDefault();
- e.stopImmediatePropagation();
- clearTimeout(timer);
- }, true));
- trigger(document, "touchcancel");
- }
- var Promise = "Promise" in window ? window.Promise : PromiseFn;
- var Deferred = function Deferred() {
- var this$1 = this;
- this.promise = new Promise(function(resolve, reject) {
- this$1.reject = reject;
- this$1.resolve = resolve;
- });
- };
- var RESOLVED = 0;
- var REJECTED = 1;
- var PENDING = 2;
- var async = "setImmediate" in window ? setImmediate : setTimeout;
- function PromiseFn(executor) {
- this.state = PENDING;
- this.value = undefined;
- this.deferred = [];
- var promise = this;
- try {
- executor(function(x) {
- promise.resolve(x);
- }, function(r) {
- promise.reject(r);
- });
- } catch (e) {
- promise.reject(e);
- }
- }
- PromiseFn.reject = function(r) {
- return new PromiseFn(function(resolve, reject) {
- reject(r);
- });
- };
- PromiseFn.resolve = function(x) {
- return new PromiseFn(function(resolve, reject) {
- resolve(x);
- });
- };
- PromiseFn.all = function all(iterable) {
- return new PromiseFn(function(resolve, reject) {
- var result = [];
- var count = 0;
- if (iterable.length === 0) {
- resolve(result);
- }
- function resolver(i) {
- return function(x) {
- result[i] = x;
- count += 1;
- if (count === iterable.length) {
- resolve(result);
- }
- };
- }
- for (var i = 0; i < iterable.length; i += 1) {
- PromiseFn.resolve(iterable[i]).then(resolver(i), reject);
- }
- });
- };
- PromiseFn.race = function race(iterable) {
- return new PromiseFn(function(resolve, reject) {
- for (var i = 0; i < iterable.length; i += 1) {
- PromiseFn.resolve(iterable[i]).then(resolve, reject);
- }
- });
- };
- var p = PromiseFn.prototype;
- p.resolve = function resolve(x) {
- var promise = this;
- if (promise.state === PENDING) {
- if (x === promise) {
- throw new TypeError("Promise settled with itself.");
- }
- var called = false;
- try {
- var then = x && x.then;
- if (x !== null && isObject(x) && isFunction(then)) {
- then.call(x, function(x) {
- if (!called) {
- promise.resolve(x);
- }
- called = true;
- }, function(r) {
- if (!called) {
- promise.reject(r);
- }
- called = true;
- });
- return;
- }
- } catch (e) {
- if (!called) {
- promise.reject(e);
- }
- return;
- }
- promise.state = RESOLVED;
- promise.value = x;
- promise.notify();
- }
- };
- p.reject = function reject(reason) {
- var promise = this;
- if (promise.state === PENDING) {
- if (reason === promise) {
- throw new TypeError("Promise settled with itself.");
- }
- promise.state = REJECTED;
- promise.value = reason;
- promise.notify();
- }
- };
- p.notify = function notify() {
- var this$1 = this;
- async(function() {
- if (this$1.state !== PENDING) {
- while (this$1.deferred.length) {
- var ref = this$1.deferred.shift();
- var onResolved = ref[0];
- var onRejected = ref[1];
- var resolve = ref[2];
- var reject = ref[3];
- try {
- if (this$1.state === RESOLVED) {
- if (isFunction(onResolved)) {
- resolve(onResolved.call(undefined, this$1.value));
- } else {
- resolve(this$1.value);
- }
- } else if (this$1.state === REJECTED) {
- if (isFunction(onRejected)) {
- resolve(onRejected.call(undefined, this$1.value));
- } else {
- reject(this$1.value);
- }
- }
- } catch (e) {
- reject(e);
- }
- }
- }
- });
- };
- p.then = function then(onResolved, onRejected) {
- var this$1 = this;
- return new PromiseFn(function(resolve, reject) {
- this$1.deferred.push([ onResolved, onRejected, resolve, reject ]);
- this$1.notify();
- });
- };
- p.catch = function(onRejected) {
- return this.then(undefined, onRejected);
- };
- function ajax(url, options) {
- return new Promise(function(resolve, reject) {
- var env = assign({
- data: null,
- method: "GET",
- headers: {},
- xhr: new XMLHttpRequest(),
- beforeSend: noop,
- responseType: ""
- }, options);
- env.beforeSend(env);
- var xhr = env.xhr;
- for (var prop in env) {
- if (prop in xhr) {
- try {
- xhr[prop] = env[prop];
- } catch (e) {}
- }
- }
- xhr.open(env.method.toUpperCase(), url);
- for (var header in env.headers) {
- xhr.setRequestHeader(header, env.headers[header]);
- }
- on(xhr, "load", function() {
- if (xhr.status === 0 || xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) {
- resolve(xhr);
- } else {
- reject(assign(Error(xhr.statusText), {
- xhr: xhr,
- status: xhr.status
- }));
- }
- });
- on(xhr, "error", function() {
- return reject(assign(Error("Network Error"), {
- xhr: xhr
- }));
- });
- on(xhr, "timeout", function() {
- return reject(assign(Error("Network Timeout"), {
- xhr: xhr
- }));
- });
- xhr.send(env.data);
- });
- }
- function getImage(src) {
- return new Promise(function(resolve, reject) {
- var img = new Image();
- img.onerror = reject;
- img.onload = function() {
- return resolve(img);
- };
- img.src = src;
- });
- }
- function isReady() {
- return document.readyState === "complete" || document.readyState !== "loading" && !document.documentElement.doScroll;
- }
- function ready(fn) {
- if (isReady()) {
- fn();
- return;
- }
- var handle = function() {
- unbind1();
- unbind2();
- fn();
- };
- var unbind1 = on(document, "DOMContentLoaded", handle);
- var unbind2 = on(window, "load", handle);
- }
- function index(element, ref) {
- return ref ? toNodes(element).indexOf(toNode(ref)) : toNodes((element = toNode(element)) && element.parentNode.children).indexOf(element);
- }
- function getIndex(i, elements, current, finite) {
- if (current === void 0) current = 0;
- if (finite === void 0) finite = false;
- elements = toNodes(elements);
- var length = elements.length;
- i = isNumeric(i) ? toNumber(i) : i === "next" ? current + 1 : i === "previous" ? current - 1 : index(elements, i);
- if (finite) {
- return clamp(i, 0, length - 1);
- }
- i %= length;
- return i < 0 ? i + length : i;
- }
- function empty(element) {
- element = toNode(element);
- element.innerHTML = "";
- return element;
- }
- function html(parent, html) {
- parent = toNode(parent);
- return isUndefined(html) ? parent.innerHTML : append(parent.hasChildNodes() ? empty(parent) : parent, html);
- }
- function prepend(parent, element) {
- parent = toNode(parent);
- if (!parent.hasChildNodes()) {
- return append(parent, element);
- } else {
- return insertNodes(element, function(element) {
- return parent.insertBefore(element, parent.firstChild);
- });
- }
- }
- function append(parent, element) {
- parent = toNode(parent);
- return insertNodes(element, function(element) {
- return parent.appendChild(element);
- });
- }
- function before(ref, element) {
- ref = toNode(ref);
- return insertNodes(element, function(element) {
- return ref.parentNode.insertBefore(element, ref);
- });
- }
- function after(ref, element) {
- ref = toNode(ref);
- return insertNodes(element, function(element) {
- return ref.nextSibling ? before(ref.nextSibling, element) : append(ref.parentNode, element);
- });
- }
- function insertNodes(element, fn) {
- element = isString(element) ? fragment(element) : element;
- return element ? "length" in element ? toNodes(element).map(fn) : fn(element) : null;
- }
- function remove(element) {
- toNodes(element).map(function(element) {
- return element.parentNode && element.parentNode.removeChild(element);
- });
- }
- function wrapAll(element, structure) {
- structure = toNode(before(element, structure));
- while (structure.firstChild) {
- structure = structure.firstChild;
- }
- append(structure, element);
- return structure;
- }
- function wrapInner(element, structure) {
- return toNodes(toNodes(element).map(function(element) {
- return element.hasChildNodes ? wrapAll(toNodes(element.childNodes), structure) : append(element, structure);
- }));
- }
- function unwrap(element) {
- toNodes(element).map(function(element) {
- return element.parentNode;
- }).filter(function(value, index, self) {
- return self.indexOf(value) === index;
- }).forEach(function(parent) {
- before(parent, parent.childNodes);
- remove(parent);
- });
- }
- var fragmentRE = /^\s*<(\w+|!)[^>]*>/;
- var singleTagRE = /^<(\w+)\s*\/?>(?:<\/\1>)?$/;
- function fragment(html) {
- var matches = singleTagRE.exec(html);
- if (matches) {
- return document.createElement(matches[1]);
- }
- var container = document.createElement("div");
- if (fragmentRE.test(html)) {
- container.insertAdjacentHTML("beforeend", html.trim());
- } else {
- container.textContent = html;
- }
- return container.childNodes.length > 1 ? toNodes(container.childNodes) : container.firstChild;
- }
- function apply(node, fn) {
- if (!node || node.nodeType !== 1) {
- return;
- }
- fn(node);
- node = node.firstElementChild;
- while (node) {
- apply(node, fn);
- node = node.nextElementSibling;
- }
- }
- function addClass(element) {
- var args = [], len = arguments.length - 1;
- while (len-- > 0) args[len] = arguments[len + 1];
- apply$1(element, args, "add");
- }
- function removeClass(element) {
- var args = [], len = arguments.length - 1;
- while (len-- > 0) args[len] = arguments[len + 1];
- apply$1(element, args, "remove");
- }
- function removeClasses(element, cls) {
- filterAttr(element, "class", new RegExp("(^|\\s)" + cls + "(?!\\S)", "g"), "");
- }
- function replaceClass(element) {
- var args = [], len = arguments.length - 1;
- while (len-- > 0) args[len] = arguments[len + 1];
- args[0] && removeClass(element, args[0]);
- args[1] && addClass(element, args[1]);
- }
- function hasClass(element, cls) {
- return toNodes(element).some(function(element) {
- return element.classList.contains(cls);
- });
- }
- function toggleClass(element) {
- var args = [], len = arguments.length - 1;
- while (len-- > 0) args[len] = arguments[len + 1];
- if (!args.length) {
- return;
- }
- args = getArgs$1(args);
- var force = !isString(args[args.length - 1]) ? args.pop() : [];
- args = args.filter(Boolean);
- toNodes(element).forEach(function(ref) {
- var classList = ref.classList;
- for (var i = 0; i < args.length; i++) {
- supports.Force ? classList.toggle.apply(classList, [ args[i] ].concat(force)) : classList[(!isUndefined(force) ? force : !classList.contains(args[i])) ? "add" : "remove"](args[i]);
- }
- });
- }
- function apply$1(element, args, fn) {
- args = getArgs$1(args).filter(Boolean);
- args.length && toNodes(element).forEach(function(ref) {
- var classList = ref.classList;
- supports.Multiple ? classList[fn].apply(classList, args) : args.forEach(function(cls) {
- return classList[fn](cls);
- });
- });
- }
- function getArgs$1(args) {
- return args.reduce(function(args, arg) {
- return args.concat.call(args, isString(arg) && includes(arg, " ") ? arg.trim().split(" ") : arg);
- }, []);
- }
- var supports = {};
- (function() {
- var list = document.createElement("_").classList;
- if (list) {
- list.add("a", "b");
- list.toggle("c", false);
- supports.Multiple = list.contains("b");
- supports.Force = !list.contains("c");
- }
- list = null;
- })();
- var cssNumber = {
- "animation-iteration-count": true,
- "column-count": true,
- "fill-opacity": true,
- "flex-grow": true,
- "flex-shrink": true,
- "font-weight": true,
- "line-height": true,
- opacity: true,
- order: true,
- orphans: true,
- widows: true,
- "z-index": true,
- zoom: true
- };
- function css(element, property, value) {
- return toNodes(element).map(function(element) {
- if (isString(property)) {
- property = propName(property);
- if (isUndefined(value)) {
- return getStyle(element, property);
- } else if (!value && value !== 0) {
- element.style.removeProperty(property);
- } else {
- element.style[property] = isNumeric(value) && !cssNumber[property] ? value + "px" : value;
- }
- } else if (isArray(property)) {
- var styles = getStyles(element);
- return property.reduce(function(props, property) {
- props[property] = styles[propName(property)];
- return props;
- }, {});
- } else if (isObject(property)) {
- each(property, function(value, property) {
- return css(element, property, value);
- });
- }
- return element;
- })[0];
- }
- function getStyles(element, pseudoElt) {
- element = toNode(element);
- return element.ownerDocument.defaultView.getComputedStyle(element, pseudoElt);
- }
- function getStyle(element, property, pseudoElt) {
- return getStyles(element, pseudoElt)[property];
- }
- var vars = {};
- function getCssVar(name) {
- if (!(name in vars)) {
- var element = append(document.documentElement, document.createElement("div"));
- addClass(element, "var-" + name);
- try {
- vars[name] = getStyle(element, "content", ":before").replace(/^["'](.*)["']$/, "$1");
- vars[name] = JSON.parse(vars[name]);
- } catch (e) {}
- document.documentElement.removeChild(element);
- }
- return vars[name];
- }
- var cssProps = {};
- function propName(name) {
- var ret = cssProps[name];
- if (!ret) {
- ret = cssProps[name] = vendorPropName(name) || name;
- }
- return ret;
- }
- var cssPrefixes = [ "webkit", "moz", "ms" ];
- var ref$1 = document.createElement("_");
- var style = ref$1.style;
- function vendorPropName(name) {
- name = hyphenate(name);
- if (name in style) {
- return name;
- }
- var i = cssPrefixes.length, prefixedName;
- while (i--) {
- prefixedName = "-" + cssPrefixes[i] + "-" + name;
- if (prefixedName in style) {
- return prefixedName;
- }
- }
- }
- function transition(element, props, duration, timing) {
- if (duration === void 0) duration = 400;
- if (timing === void 0) timing = "linear";
- return Promise.all(toNodes(element).map(function(element) {
- return new Promise(function(resolve, reject) {
- for (var name in props) {
- var value = css(element, name);
- if (value === "") {
- css(element, name, value);
- }
- }
- var timer = setTimeout(function() {
- return trigger(element, "transitionend");
- }, duration);
- once(element, "transitionend transitioncanceled", function(ref) {
- var type = ref.type;
- clearTimeout(timer);
- removeClass(element, "uk-transition");
- css(element, {
- "transition-property": "",
- "transition-duration": "",
- "transition-timing-function": ""
- });
- type === "transitioncanceled" ? reject() : resolve();
- }, false, function(ref) {
- var target = ref.target;
- return element === target;
- });
- addClass(element, "uk-transition");
- css(element, assign({
- "transition-property": Object.keys(props).map(propName).join(","),
- "transition-duration": duration + "ms",
- "transition-timing-function": timing
- }, props));
- });
- }));
- }
- var Transition = {
- start: transition,
- stop: function stop(element) {
- trigger(element, "transitionend");
- return Promise.resolve();
- },
- cancel: function cancel(element) {
- trigger(element, "transitioncanceled");
- },
- inProgress: function inProgress(element) {
- return hasClass(element, "uk-transition");
- }
- };
- var animationPrefix = "uk-animation-";
- var clsCancelAnimation = "uk-cancel-animation";
- function animate(element, animation, duration, origin, out) {
- var arguments$1 = arguments;
- if (duration === void 0) duration = 200;
- return Promise.all(toNodes(element).map(function(element) {
- return new Promise(function(resolve, reject) {
- if (hasClass(element, clsCancelAnimation)) {
- requestAnimationFrame(function() {
- return Promise.resolve().then(function() {
- return animate.apply(void 0, arguments$1).then(resolve, reject);
- });
- });
- return;
- }
- var cls = animation + " " + animationPrefix + (out ? "leave" : "enter");
- if (startsWith(animation, animationPrefix)) {
- if (origin) {
- cls += " uk-transform-origin-" + origin;
- }
- if (out) {
- cls += " " + animationPrefix + "reverse";
- }
- }
- reset();
- once(element, "animationend animationcancel", function(ref) {
- var type = ref.type;
- var hasReset = false;
- if (type === "animationcancel") {
- reject();
- reset();
- } else {
- resolve();
- Promise.resolve().then(function() {
- hasReset = true;
- reset();
- });
- }
- requestAnimationFrame(function() {
- if (!hasReset) {
- addClass(element, clsCancelAnimation);
- requestAnimationFrame(function() {
- return removeClass(element, clsCancelAnimation);
- });
- }
- });
- }, false, function(ref) {
- var target = ref.target;
- return element === target;
- });
- css(element, "animationDuration", duration + "ms");
- addClass(element, cls);
- function reset() {
- css(element, "animationDuration", "");
- removeClasses(element, animationPrefix + "\\S*");
- }
- });
- }));
- }
- var inProgress = new RegExp(animationPrefix + "(enter|leave)");
- var Animation = {
- in: function in$1(element, animation, duration, origin) {
- return animate(element, animation, duration, origin, false);
- },
- out: function out(element, animation, duration, origin) {
- return animate(element, animation, duration, origin, true);
- },
- inProgress: function inProgress$1(element) {
- return inProgress.test(attr(element, "class"));
- },
- cancel: function cancel(element) {
- trigger(element, "animationcancel");
- }
- };
- function $(selector, context) {
- return !isString(selector) ? toNode(selector) : isHtml(selector) ? toNode(fragment(selector)) : find(selector, context);
- }
- function $$(selector, context) {
- return !isString(selector) ? toNodes(selector) : isHtml(selector) ? toNodes(fragment(selector)) : findAll(selector, context);
- }
- function isHtml(str) {
- return str[0] === "<" || str.match(/^\s*);
- }
- var dirs = {
- width: [ "x", "left", "right" ],
- height: [ "y", "top", "bottom" ]
- };
- function positionAt(element, target, elAttach, targetAttach, elOffset, targetOffset, flip, boundary) {
- elAttach = getPos(elAttach);
- targetAttach = getPos(targetAttach);
- var flipped = {
- element: elAttach,
- target: targetAttach
- };
- if (!element || !target) {
- return flipped;
- }
- var dim = getDimensions(element);
- var targetDim = getDimensions(target);
- var position = targetDim;
- moveTo(position, elAttach, dim, -1);
- moveTo(position, targetAttach, targetDim, 1);
- elOffset = getOffsets(elOffset, dim.width, dim.height);
- targetOffset = getOffsets(targetOffset, targetDim.width, targetDim.height);
- elOffset["x"] += targetOffset["x"];
- elOffset["y"] += targetOffset["y"];
- position.left += elOffset["x"];
- position.top += elOffset["y"];
- boundary = getDimensions(boundary || window$1(element));
- if (flip) {
- each(dirs, function(ref, prop) {
- var dir = ref[0];
- var align = ref[1];
- var alignFlip = ref[2];
- if (!(flip === true || includes(flip, dir))) {
- return;
- }
- var elemOffset = elAttach[dir] === align ? -dim[prop] : elAttach[dir] === alignFlip ? dim[prop] : 0;
- var targetOffset = targetAttach[dir] === align ? targetDim[prop] : targetAttach[dir] === alignFlip ? -targetDim[prop] : 0;
- if (position[align] < boundary[align] || position[align] + dim[prop] > boundary[alignFlip]) {
- var centerOffset = dim[prop] / 2;
- var centerTargetOffset = targetAttach[dir] === "center" ? -targetDim[prop] / 2 : 0;
- elAttach[dir] === "center" && (apply(centerOffset, centerTargetOffset) || apply(-centerOffset, -centerTargetOffset)) || apply(elemOffset, targetOffset);
- }
- function apply(elemOffset, targetOffset) {
- var newVal = position[align] + elemOffset + targetOffset - elOffset[dir] * 2;
- if (newVal >= boundary[align] && newVal + dim[prop] <= boundary[alignFlip]) {
- position[align] = newVal;
- [ "element", "target" ].forEach(function(el) {
- flipped[el][dir] = !elemOffset ? flipped[el][dir] : flipped[el][dir] === dirs[prop][1] ? dirs[prop][2] : dirs[prop][1];
- });
- return true;
- }
- }
- });
- }
- offset(element, position);
- return flipped;
- }
- function offset(element, coordinates) {
- element = toNode(element);
- if (coordinates) {
- var currentOffset = offset(element);
- var pos = css(element, "position");
- [ "left", "top" ].forEach(function(prop) {
- if (prop in coordinates) {
- var value = css(element, prop);
- element.style[prop] = coordinates[prop] - currentOffset[prop] + toFloat(pos === "absolute" && value === "auto" ? position(element)[prop] : value) + "px";
- }
- });
- return;
- }
- return getDimensions(element);
- }
- function getDimensions(element) {
- element = toNode(element);
- var ref = window$1(element);
- var top = ref.pageYOffset;
- var left = ref.pageXOffset;
- if (isWindow(element)) {
- var height = element.innerHeight;
- var width = element.innerWidth;
- return {
- top: top,
- left: left,
- height: height,
- width: width,
- bottom: top + height,
- right: left + width
- };
- }
- var display = false;
- if (!isVisible(element)) {
- display = element.style.display;
- element.style.display = "block";
- }
- var rect = element.getBoundingClientRect();
- if (display !== false) {
- element.style.display = display;
- }
- return {
- height: rect.height,
- width: rect.width,
- top: rect.top + top,
- left: rect.left + left,
- bottom: rect.bottom + top,
- right: rect.right + left
- };
- }
- function position(element) {
- element = toNode(element);
- var parent = offsetParent(element);
- var parentOffset = parent === docEl(element) ? {
- top: 0,
- left: 0
- } : offset(parent);
- var ref = [ "top", "left" ].reduce(function(props, prop) {
- var propName$$1 = ucfirst(prop);
- props[prop] -= parentOffset[prop] + (toFloat(css(element, "margin" + propName$$1)) || 0) + (toFloat(css(parent, "border" + propName$$1 + "Width")) || 0);
- return props;
- }, offset(element));
- var top = ref.top;
- var left = ref.left;
- return {
- top: top,
- left: left
- };
- }
- function offsetParent(element) {
- var parent = toNode(element).offsetParent;
- while (parent && css(parent, "position") === "static") {
- parent = parent.offsetParent;
- }
- return parent || docEl(element);
- }
- var height = dimension("height");
- var width = dimension("width");
- function dimension(prop) {
- var propName$$1 = ucfirst(prop);
- return function(element, value) {
- element = toNode(element);
- if (isUndefined(value)) {
- if (isWindow(element)) {
- return element["inner" + propName$$1];
- }
- if (isDocument(element)) {
- var doc = element.documentElement;
- return Math.max(doc["offset" + propName$$1], doc["scroll" + propName$$1]);
- }
- value = css(element, prop);
- value = value === "auto" ? element["offset" + propName$$1] : toFloat(value) || 0;
- return value - boxModelAdjust(prop, element);
- } else {
- css(element, prop, !value && value !== 0 ? "" : +value + boxModelAdjust(prop, element) + "px");
- }
- };
- }
- function boxModelAdjust(prop, element) {
- return css(element, "boxSizing") === "border-box" ? dirs[prop].slice(1).map(ucfirst).reduce(function(value, prop) {
- return value + toFloat(css(element, "padding" + prop)) + toFloat(css(element, "border" + prop + "Width"));
- }, 0) : 0;
- }
- function moveTo(position, attach, dim, factor) {
- each(dirs, function(ref, prop) {
- var dir = ref[0];
- var align = ref[1];
- var alignFlip = ref[2];
- if (attach[dir] === alignFlip) {
- position[align] += dim[prop] * factor;
- } else if (attach[dir] === "center") {
- position[align] += dim[prop] * factor / 2;
- }
- });
- }
- function getPos(pos) {
- var x = /left|center|right/;
- var y = /top|center|bottom/;
- pos = (pos || "").split(" ");
- if (pos.length === 1) {
- pos = x.test(pos[0]) ? pos.concat([ "center" ]) : y.test(pos[0]) ? [ "center" ].concat(pos) : [ "center", "center" ];
- }
- return {
- x: x.test(pos[0]) ? pos[0] : "center",
- y: y.test(pos[1]) ? pos[1] : "center"
- };
- }
- function getOffsets(offsets, width, height) {
- var ref = (offsets || "").split(" ");
- var x = ref[0];
- var y = ref[1];
- return {
- x: x ? toFloat(x) * (endsWith(x, "%") ? width / 100 : 1) : 0,
- y: y ? toFloat(y) * (endsWith(y, "%") ? height / 100 : 1) : 0
- };
- }
- function flipPosition(pos) {
- switch (pos) {
- case "left":
- return "right";
-
- case "right":
- return "left";
-
- case "top":
- return "bottom";
-
- case "bottom":
- return "top";
-
- default:
- return pos;
- }
- }
- function isInView(element, top, left) {
- if (top === void 0) top = 0;
- if (left === void 0) left = 0;
- element = toNode(element);
- var win = window$1(element);
- return isVisible(element) && intersectRect(element.getBoundingClientRect(), {
- top: top,
- left: left,
- bottom: top + height(win),
- right: left + width(win)
- });
- }
- function scrolledOver(element) {
- if (!isVisible(element)) {
- return 0;
- }
- element = toNode(element);
- var win = window$1(element);
- var doc = document$1(element);
- var elHeight = element.offsetHeight;
- var top = positionTop(element);
- var vp = height(win);
- var vh = vp + Math.min(0, top - vp);
- var diff = Math.max(0, vp - (height(doc) - (top + elHeight)));
- return clamp((vh + win.pageYOffset - top) / ((vh + (elHeight - (diff < vp ? diff : 0))) / 100) / 100);
- }
- function positionTop(element) {
- var top = 0;
- do {
- top += element.offsetTop;
- } while (element = element.offsetParent);
- return top;
- }
- function window$1(element) {
- return isWindow(element) ? element : document$1(element).defaultView;
- }
- function document$1(element) {
- return toNode(element).ownerDocument;
- }
- function docEl(element) {
- return document$1(element).documentElement;
- }
- var isRtl = attr(document.documentElement, "dir") === "rtl";
- var hasTouchEvents = "ontouchstart" in window;
- var hasPointerEvents = window.PointerEvent;
- var hasTouch = hasTouchEvents || window.DocumentTouch && document instanceof DocumentTouch || navigator.maxTouchPoints;
- var pointerDown = !hasTouch ? "mousedown" : "mousedown " + (hasTouchEvents ? "touchstart" : "pointerdown");
- var pointerMove = !hasTouch ? "mousemove" : "mousemove " + (hasTouchEvents ? "touchmove" : "pointermove");
- var pointerUp = !hasTouch ? "mouseup" : "mouseup " + (hasTouchEvents ? "touchend" : "pointerup");
- var pointerEnter = hasTouch && hasPointerEvents ? "pointerenter" : "mouseenter";
- var pointerLeave = hasTouch && hasPointerEvents ? "pointerleave" : "mouseleave";
- var fastdom = {
- reads: [],
- writes: [],
- read: function read(task) {
- this.reads.push(task);
- scheduleFlush();
- return task;
- },
- write: function write(task) {
- this.writes.push(task);
- scheduleFlush();
- return task;
- },
- clear: function clear(task) {
- return remove$1(this.reads, task) || remove$1(this.writes, task);
- },
- flush: function flush() {
- runTasks(this.reads);
- runTasks(this.writes.splice(0, this.writes.length));
- this.scheduled = false;
- if (this.reads.length || this.writes.length) {
- scheduleFlush();
- }
- }
- };
- function scheduleFlush() {
- if (!fastdom.scheduled) {
- fastdom.scheduled = true;
- requestAnimationFrame(fastdom.flush.bind(fastdom));
- }
- }
- function runTasks(tasks) {
- var task;
- while (task = tasks.shift()) {
- task();
- }
- }
- function remove$1(array, item) {
- var index = array.indexOf(item);
- return !!~index && !!array.splice(index, 1);
- }
- function MouseTracker() {}
- MouseTracker.prototype = {
- positions: [],
- position: null,
- init: function init() {
- var this$1 = this;
- this.positions = [];
- this.position = null;
- var ticking = false;
- this.unbind = on(document, "mousemove", function(e) {
- if (ticking) {
- return;
- }
- setTimeout(function() {
- var time = Date.now();
- var ref = this$1.positions;
- var length = ref.length;
- if (length && time - this$1.positions[length - 1].time > 100) {
- this$1.positions.splice(0, length);
- }
- this$1.positions.push({
- time: time,
- x: e.pageX,
- y: e.pageY
- });
- if (this$1.positions.length > 5) {
- this$1.positions.shift();
- }
- ticking = false;
- }, 5);
- ticking = true;
- });
- },
- cancel: function cancel() {
- if (this.unbind) {
- this.unbind();
- }
- },
- movesTo: function movesTo(target) {
- if (this.positions.length < 2) {
- return false;
- }
- var p = offset(target);
- var position$$1 = this.positions[this.positions.length - 1];
- var ref = this.positions;
- var prevPos = ref[0];
- if (p.left <= position$$1.x && position$$1.x <= p.right && p.top <= position$$1.y && position$$1.y <= p.bottom) {
- return false;
- }
- var points = [ [ {
- x: p.left,
- y: p.top
- }, {
- x: p.right,
- y: p.bottom
- } ], [ {
- x: p.right,
- y: p.top
- }, {
- x: p.left,
- y: p.bottom
- } ] ];
- if (p.right <= position$$1.x) {} else if (p.left >= position$$1.x) {
- points[0].reverse();
- points[1].reverse();
- } else if (p.bottom <= position$$1.y) {
- points[0].reverse();
- } else if (p.top >= position$$1.y) {
- points[1].reverse();
- }
- return !!points.reduce(function(result, point) {
- return result + (slope(prevPos, point[0]) < slope(position$$1, point[0]) && slope(prevPos, point[1]) > slope(position$$1, point[1]));
- }, 0);
- }
- };
- function slope(a, b) {
- return (b.y - a.y) / (b.x - a.x);
- }
- var strats = {};
- strats.args = strats.events = strats.init = strats.created = strats.beforeConnect = strats.connected = strats.ready = strats.beforeDisconnect = strats.disconnected = strats.destroy = function(parentVal, childVal) {
- parentVal = parentVal && !isArray(parentVal) ? [ parentVal ] : parentVal;
- return childVal ? parentVal ? parentVal.concat(childVal) : isArray(childVal) ? childVal : [ childVal ] : parentVal;
- };
- strats.update = function(parentVal, childVal) {
- return strats.args(parentVal, isFunction(childVal) ? {
- read: childVal
- } : childVal);
- };
- strats.props = function(parentVal, childVal) {
- if (isArray(childVal)) {
- childVal = childVal.reduce(function(value, key) {
- value[key] = String;
- return value;
- }, {});
- }
- return strats.methods(parentVal, childVal);
- };
- strats.computed = strats.defaults = strats.methods = function(parentVal, childVal) {
- return childVal ? parentVal ? assign({}, parentVal, childVal) : childVal : parentVal;
- };
- var defaultStrat = function(parentVal, childVal) {
- return isUndefined(childVal) ? parentVal : childVal;
- };
- function mergeOptions(parent, child) {
- var options = {};
- if (child.mixins) {
- for (var i = 0, l = child.mixins.length; i < l; i++) {
- parent = mergeOptions(parent, child.mixins[i]);
- }
- }
- for (var key in parent) {
- mergeKey(key);
- }
- for (var key$1 in child) {
- if (!hasOwn(parent, key$1)) {
- mergeKey(key$1);
- }
- }
- function mergeKey(key) {
- options[key] = (strats[key] || defaultStrat)(parent[key], child[key]);
- }
- return options;
- }
- var id = 0;
- var Player = function Player(el) {
- this.id = ++id;
- this.el = toNode(el);
- };
- Player.prototype.isVideo = function isVideo() {
- return this.isYoutube() || this.isVimeo() || this.isHTML5();
- };
- Player.prototype.isHTML5 = function isHTML5() {
- return this.el.tagName === "VIDEO";
- };
- Player.prototype.isIFrame = function isIFrame() {
- return this.el.tagName === "IFRAME";
- };
- Player.prototype.isYoutube = function isYoutube() {
- return this.isIFrame() && !!this.el.src.match(/\/\/.*?youtube(-nocookie)?\.[a-z]+\/(watch\?v=[^&\s]+|embed)|youtu\.be\/.*/);
- };
- Player.prototype.isVimeo = function isVimeo() {
- return this.isIFrame() && !!this.el.src.match(/vimeo\.com\/video\/.*/);
- };
- Player.prototype.enableApi = function enableApi() {
- var this$1 = this;
- if (this.ready) {
- return this.ready;
- }
- var youtube = this.isYoutube();
- var vimeo = this.isVimeo();
- var poller;
- if (youtube || vimeo) {
- return this.ready = new Promise(function(resolve) {
- once(this$1.el, "load", function() {
- if (youtube) {
- var listener = function() {
- return post(this$1.el, {
- event: "listening",
- id: this$1.id
- });
- };
- poller = setInterval(listener, 100);
- listener();
- }
- });
- listen(function(data$$1) {
- return youtube && data$$1.id === this$1.id && data$$1.event === "onReady" || vimeo && Number(data$$1.player_id) === this$1.id;
- }).then(function() {
- resolve();
- poller && clearInterval(poller);
- });
- attr(this$1.el, "src", "" + this$1.el.src + (includes(this$1.el.src, "?") ? "&" : "?") + (youtube ? "enablejsapi=1" : "api=1&player_id=" + this$1.id));
- });
- }
- return Promise.resolve();
- };
- Player.prototype.play = function play() {
- var this$1 = this;
- if (!this.isVideo()) {
- return;
- }
- if (this.isIFrame()) {
- this.enableApi().then(function() {
- return post(this$1.el, {
- func: "playVideo",
- method: "play"
- });
- });
- } else if (this.isHTML5()) {
- try {
- var promise = this.el.play();
- if (promise) {
- promise.catch(noop);
- }
- } catch (e) {}
- }
- };
- Player.prototype.pause = function pause() {
- var this$1 = this;
- if (!this.isVideo()) {
- return;
- }
- if (this.isIFrame()) {
- this.enableApi().then(function() {
- return post(this$1.el, {
- func: "pauseVideo",
- method: "pause"
- });
- });
- } else if (this.isHTML5()) {
- this.el.pause();
- }
- };
- Player.prototype.mute = function mute() {
- var this$1 = this;
- if (!this.isVideo()) {
- return;
- }
- if (this.isIFrame()) {
- this.enableApi().then(function() {
- return post(this$1.el, {
- func: "mute",
- method: "setVolume",
- value: 0
- });
- });
- } else if (this.isHTML5()) {
- this.el.muted = true;
- attr(this.el, "muted", "");
- }
- };
- function post(el, cmd) {
- try {
- el.contentWindow.postMessage(JSON.stringify(assign({
- event: "command"
- }, cmd)), "*");
- } catch (e) {}
- }
- function listen(cb) {
- return new Promise(function(resolve) {
- once(window, "message", function(_, data$$1) {
- return resolve(data$$1);
- }, false, function(ref) {
- var data$$1 = ref.data;
- if (!data$$1 || !isString(data$$1)) {
- return;
- }
- try {
- data$$1 = JSON.parse(data$$1);
- } catch (e) {
- return;
- }
- return data$$1 && cb(data$$1);
- });
- });
- }
- var touch = {};
- var clickTimeout;
- var swipeTimeout;
- var tapTimeout;
- var clicked;
- function swipeDirection(ref) {
- var x1 = ref.x1;
- var x2 = ref.x2;
- var y1 = ref.y1;
- var y2 = ref.y2;
- return Math.abs(x1 - x2) >= Math.abs(y1 - y2) ? x1 - x2 > 0 ? "Left" : "Right" : y1 - y2 > 0 ? "Up" : "Down";
- }
- function cancelAll() {
- clickTimeout && clearTimeout(clickTimeout);
- swipeTimeout && clearTimeout(swipeTimeout);
- tapTimeout && clearTimeout(tapTimeout);
- clickTimeout = swipeTimeout = tapTimeout = null;
- touch = {};
- }
- ready(function() {
- on(document, "click", function() {
- return clicked = true;
- }, true);
- on(document, pointerDown, function(e) {
- var target = e.target;
- var ref = getPos$1(e);
- var x = ref.x;
- var y = ref.y;
- var now = Date.now();
- var type = getType(e.type);
- if (touch.type && touch.type !== type) {
- return;
- }
- touch.el = "tagName" in target ? target : target.parentNode;
- clickTimeout && clearTimeout(clickTimeout);
- touch.x1 = x;
- touch.y1 = y;
- if (touch.last && now - touch.last <= 250) {
- touch = {};
- }
- touch.type = type;
- touch.last = now;
- clicked = e.button > 0;
- });
- on(document, pointerMove, function(e) {
- if (e.defaultPrevented) {
- return;
- }
- var ref = getPos$1(e);
- var x = ref.x;
- var y = ref.y;
- touch.x2 = x;
- touch.y2 = y;
- });
- on(document, pointerUp, function(ref) {
- var type = ref.type;
- var target = ref.target;
- if (touch.type !== getType(type)) {
- return;
- }
- if (touch.x2 && Math.abs(touch.x1 - touch.x2) > 30 || touch.y2 && Math.abs(touch.y1 - touch.y2) > 30) {
- swipeTimeout = setTimeout(function() {
- if (touch.el) {
- trigger(touch.el, "swipe");
- trigger(touch.el, "swipe" + swipeDirection(touch));
- }
- touch = {};
- });
- } else if ("last" in touch) {
- tapTimeout = setTimeout(function() {
- return trigger(touch.el, "tap");
- });
- if (touch.el && type !== "mouseup" && within(target, touch.el)) {
- clickTimeout = setTimeout(function() {
- clickTimeout = null;
- if (touch.el && !clicked) {
- trigger(touch.el, "click");
- }
- touch = {};
- }, 350);
- }
- } else {
- touch = {};
- }
- });
- on(document, "touchcancel", cancelAll);
- on(window, "scroll", cancelAll);
- });
- var touching = false;
- on(document, "touchstart", function() {
- return touching = true;
- }, true);
- on(document, "click", function() {
- touching = false;
- });
- on(document, "touchcancel", function() {
- return touching = false;
- }, true);
- function isTouch(e) {
- return touching || e.pointerType === "touch";
- }
- function getPos$1(e) {
- var touches = e.touches;
- var changedTouches = e.changedTouches;
- var ref = touches && touches[0] || changedTouches && changedTouches[0] || e;
- var x = ref.pageX;
- var y = ref.pageY;
- return {
- x: x,
- y: y
- };
- }
- function getType(type) {
- return type.slice(0, 5);
- }
- var util = Object.freeze({
- ajax: ajax,
- getImage: getImage,
- transition: transition,
- Transition: Transition,
- animate: animate,
- Animation: Animation,
- attr: attr,
- hasAttr: hasAttr,
- removeAttr: removeAttr,
- filterAttr: filterAttr,
- data: data,
- addClass: addClass,
- removeClass: removeClass,
- removeClasses: removeClasses,
- replaceClass: replaceClass,
- hasClass: hasClass,
- toggleClass: toggleClass,
- $: $,
- $$: $$,
- positionAt: positionAt,
- offset: offset,
- position: position,
- height: height,
- width: width,
- flipPosition: flipPosition,
- isInView: isInView,
- scrolledOver: scrolledOver,
- isReady: isReady,
- ready: ready,
- index: index,
- getIndex: getIndex,
- empty: empty,
- html: html,
- prepend: prepend,
- append: append,
- before: before,
- after: after,
- remove: remove,
- wrapAll: wrapAll,
- wrapInner: wrapInner,
- unwrap: unwrap,
- fragment: fragment,
- apply: apply,
- isRtl: isRtl,
- hasTouch: hasTouch,
- pointerDown: pointerDown,
- pointerMove: pointerMove,
- pointerUp: pointerUp,
- pointerEnter: pointerEnter,
- pointerLeave: pointerLeave,
- on: on,
- off: off,
- once: once,
- trigger: trigger,
- createEvent: createEvent,
- toEventTargets: toEventTargets,
- preventClick: preventClick,
- fastdom: fastdom,
- isVoidElement: isVoidElement,
- isVisible: isVisible,
- selInput: selInput,
- isInput: isInput,
- filter: filter,
- within: within,
- bind: bind,
- hasOwn: hasOwn,
- hyphenate: hyphenate,
- camelize: camelize,
- ucfirst: ucfirst,
- startsWith: startsWith,
- endsWith: endsWith,
- includes: includes,
- isArray: isArray,
- isFunction: isFunction,
- isObject: isObject,
- isPlainObject: isPlainObject,
- isWindow: isWindow,
- isDocument: isDocument,
- isJQuery: isJQuery,
- isNode: isNode,
- isNodeCollection: isNodeCollection,
- isBoolean: isBoolean,
- isString: isString,
- isNumber: isNumber,
- isNumeric: isNumeric,
- isUndefined: isUndefined,
- toBoolean: toBoolean,
- toNumber: toNumber,
- toFloat: toFloat,
- toNode: toNode,
- toNodes: toNodes,
- toList: toList,
- toMs: toMs,
- swap: swap,
- assign: assign,
- each: each,
- sortBy: sortBy,
- clamp: clamp,
- noop: noop,
- intersectRect: intersectRect,
- pointInRect: pointInRect,
- Dimensions: Dimensions,
- MouseTracker: MouseTracker,
- mergeOptions: mergeOptions,
- Player: Player,
- Promise: Promise,
- Deferred: Deferred,
- query: query,
- queryAll: queryAll,
- find: find,
- findAll: findAll,
- matches: matches,
- closest: closest,
- parents: parents,
- escape: escape,
- css: css,
- getStyles: getStyles,
- getStyle: getStyle,
- getCssVar: getCssVar,
- propName: propName,
- isTouch: isTouch,
- getPos: getPos$1
- });
- function componentAPI(UIkit) {
- var DATA = UIkit.data;
- UIkit.components = {};
- UIkit.component = function(id, options) {
- var name = camelize(id);
- if (isPlainObject(options)) {
- options.name = name;
- options = UIkit.extend(options);
- } else if (isUndefined(options)) {
- return UIkit.components[name];
- } else {
- options.options.name = name;
- }
- UIkit.components[name] = options;
- UIkit[name] = function(element, data) {
- var i = arguments.length, argsArray = Array(i);
- while (i--) argsArray[i] = arguments[i];
- if (isPlainObject(element)) {
- return new UIkit.components[name]({
- data: element
- });
- }
- if (UIkit.components[name].options.functional) {
- return new UIkit.components[name]({
- data: [].concat(argsArray)
- });
- }
- return element && element.nodeType ? init(element) : $$(element).map(init)[0];
- function init(element) {
- var cmp = UIkit.getComponent(element, name);
- if (cmp && data) {
- cmp.$reset(data);
- }
- return cmp || new UIkit.components[name]({
- el: element,
- data: data || {}
- });
- }
- };
- if (UIkit._initialized && !options.options.functional) {
- fastdom.read(function() {
- return UIkit[name]("[uk-" + id + "],[data-uk-" + id + "]");
- });
- }
- return UIkit.components[name];
- };
- UIkit.getComponents = function(element) {
- return element && element[DATA] || {};
- };
- UIkit.getComponent = function(element, name) {
- return UIkit.getComponents(element)[name];
- };
- UIkit.connect = function(node) {
- if (node[DATA]) {
- for (var name in node[DATA]) {
- node[DATA][name]._callConnected();
- }
- }
- for (var i = 0; i < node.attributes.length; i++) {
- var name$1 = getComponentName(node.attributes[i].name);
- if (name$1 && name$1 in UIkit.components) {
- UIkit[name$1](node);
- }
- }
- };
- UIkit.disconnect = function(node) {
- for (var name in node[DATA]) {
- node[DATA][name]._callDisconnected();
- }
- };
- }
- function getComponentName(attribute) {
- return startsWith(attribute, "uk-") || startsWith(attribute, "data-uk-") ? camelize(attribute.replace("data-uk-", "").replace("uk-", "")) : false;
- }
- function boot(UIkit) {
- var connect = UIkit.connect;
- var disconnect = UIkit.disconnect;
- if (!("MutationObserver" in window)) {
- return;
- }
- if (document.body) {
- init();
- } else {
- new MutationObserver(function() {
- if (document.body) {
- this.disconnect();
- init();
- }
- }).observe(document, {
- childList: true,
- subtree: true
- });
- }
- function init() {
- apply(document.body, connect);
- fastdom.flush();
- new MutationObserver(function(mutations) {
- return mutations.forEach(applyMutation);
- }).observe(document, {
- childList: true,
- subtree: true,
- characterData: true,
- attributes: true
- });
- UIkit._initialized = true;
- }
- function applyMutation(mutation) {
- var target = mutation.target;
- var type = mutation.type;
- var update = type !== "attributes" ? applyChildList(mutation) : applyAttribute(mutation);
- update && UIkit.update(target);
- }
- function applyAttribute(ref) {
- var target = ref.target;
- var attributeName = ref.attributeName;
- if (attributeName === "href") {
- return true;
- }
- var name = getComponentName(attributeName);
- if (!name || !(name in UIkit.components)) {
- return;
- }
- if (hasAttr(target, attributeName)) {
- UIkit[name](target);
- return true;
- }
- var component = UIkit.getComponent(target, name);
- if (component) {
- component.$destroy();
- return true;
- }
- }
- function applyChildList(ref) {
- var addedNodes = ref.addedNodes;
- var removedNodes = ref.removedNodes;
- for (var i = 0; i < addedNodes.length; i++) {
- apply(addedNodes[i], connect);
- }
- for (var i$1 = 0; i$1 < removedNodes.length; i$1++) {
- apply(removedNodes[i$1], disconnect);
- }
- return true;
- }
- function apply(node, fn) {
- if (node.nodeType !== 1 || hasAttr(node, "uk-no-boot")) {
- return;
- }
- fn(node);
- node = node.firstElementChild;
- while (node) {
- var next = node.nextElementSibling;
- apply(node, fn);
- node = next;
- }
- }
- }
- function globalAPI(UIkit) {
- var DATA = UIkit.data;
- UIkit.use = function(plugin) {
- if (plugin.installed) {
- return;
- }
- plugin.call(null, this);
- plugin.installed = true;
- return this;
- };
- UIkit.mixin = function(mixin, component) {
- component = (isString(component) ? UIkit.components[component] : component) || this;
- mixin = mergeOptions({}, mixin);
- mixin.mixins = component.options.mixins;
- delete component.options.mixins;
- component.options = mergeOptions(mixin, component.options);
- };
- UIkit.extend = function(options) {
- options = options || {};
- var Super = this;
- var Sub = function UIkitComponent(options) {
- this._init(options);
- };
- Sub.prototype = Object.create(Super.prototype);
- Sub.prototype.constructor = Sub;
- Sub.options = mergeOptions(Super.options, options);
- Sub["super"] = Super;
- Sub.extend = Super.extend;
- return Sub;
- };
- UIkit.update = function(element, e) {
- e = createEvent(e || "update");
- element = element ? toNode(element) : document.body;
- apply(element, function(element) {
- return update(element[DATA], e);
- });
- while (element && element.parentNode) {
- update(element.parentNode[DATA], e);
- element = element.parentNode;
- }
- };
- var container;
- Object.defineProperty(UIkit, "container", {
- get: function get() {
- return container || document.body;
- },
- set: function set(element) {
- container = $(element);
- }
- });
- function update(data, e) {
- if (!data) {
- return;
- }
- for (var name in data) {
- if (data[name]._isReady) {
- data[name]._callUpdate(e);
- }
- }
- }
- }
- function hooksAPI(UIkit) {
- UIkit.prototype._callHook = function(hook) {
- var this$1 = this;
- var handlers = this.$options[hook];
- if (handlers) {
- handlers.forEach(function(handler) {
- return handler.call(this$1);
- });
- }
- };
- UIkit.prototype._callConnected = function() {
- var this$1 = this;
- if (this._connected) {
- return;
- }
- this._data = {};
- this._callHook("beforeConnect");
- this._connected = true;
- this._initEvents();
- this._initObserver();
- this._callHook("connected");
- if (!this._isReady) {
- ready(function() {
- return this$1._callReady();
- });
- }
- this._callUpdate();
- };
- UIkit.prototype._callDisconnected = function() {
- if (!this._connected) {
- return;
- }
- this._callHook("beforeDisconnect");
- if (this._observer) {
- this._observer.disconnect();
- this._observer = null;
- }
- this._unbindEvents();
- this._callHook("disconnected");
- this._connected = false;
- };
- UIkit.prototype._callReady = function() {
- if (this._isReady) {
- return;
- }
- this._isReady = true;
- this._callHook("ready");
- this._resetComputeds();
- this._callUpdate();
- };
- UIkit.prototype._callUpdate = function(e) {
- var this$1 = this;
- e = createEvent(e || "update");
- var type = e.type;
- if (includes([ "update", "load", "resize" ], type)) {
- this._resetComputeds();
- }
- var updates = this.$options.update;
- var ref = this._frames;
- var reads = ref.reads;
- var writes = ref.writes;
- if (!updates) {
- return;
- }
- updates.forEach(function(ref, i) {
- var read = ref.read;
- var write = ref.write;
- var events = ref.events;
- if (type !== "update" && !includes(events, type)) {
- return;
- }
- if (read && !includes(fastdom.reads, reads[i])) {
- reads[i] = fastdom.read(function() {
- var result = read.call(this$1, this$1._data, e);
- if (result === false && write) {
- fastdom.clear(writes[i]);
- delete writes[i];
- } else if (isPlainObject(result)) {
- assign(this$1._data, result);
- }
- delete reads[i];
- });
- }
- if (write && !includes(fastdom.writes, writes[i])) {
- writes[i] = fastdom.write(function() {
- write.call(this$1, this$1._data, e);
- delete writes[i];
- });
- }
- });
- };
- }
- function stateAPI(UIkit) {
- var uid = 0;
- UIkit.prototype.props = {};
- UIkit.prototype._init = function(options) {
- options = options || {};
- options = this.$options = mergeOptions(this.constructor.options, options, this);
- this.$el = null;
- this.$name = UIkit.prefix + hyphenate(this.$options.name);
- this.$props = {};
- this._frames = {
- reads: {},
- writes: {}
- };
- this._events = [];
- this._uid = uid++;
- this._initData();
- this._initMethods();
- this._initComputeds();
- this._callHook("created");
- if (options.el) {
- this.$mount(options.el);
- }
- };
- UIkit.prototype._initData = function() {
- var this$1 = this;
- var ref = this.$options;
- var defaults = ref.defaults;
- var data$$1 = ref.data;
- if (data$$1 === void 0) data$$1 = {};
- var args = ref.args;
- if (args === void 0) args = [];
- var props = ref.props;
- if (props === void 0) props = {};
- var el = ref.el;
- if (args.length && isArray(data$$1)) {
- data$$1 = data$$1.slice(0, args.length).reduce(function(data$$1, value, index) {
- if (isPlainObject(value)) {
- assign(data$$1, value);
- } else {
- data$$1[args[index]] = value;
- }
- return data$$1;
- }, {});
- }
- for (var key in assign({}, defaults, props)) {
- this$1.$props[key] = this$1[key] = hasOwn(data$$1, key) && !isUndefined(data$$1[key]) ? coerce(props[key], data$$1[key], el) : defaults ? defaults[key] && isArray(defaults[key]) ? defaults[key].concat() : defaults[key] : null;
- }
- };
- UIkit.prototype._initMethods = function() {
- var this$1 = this;
- var ref = this.$options;
- var methods = ref.methods;
- if (methods) {
- for (var key in methods) {
- this$1[key] = bind(methods[key], this$1);
- }
- }
- };
- UIkit.prototype._initComputeds = function() {
- var this$1 = this;
- var ref = this.$options;
- var computed = ref.computed;
- this._resetComputeds();
- if (computed) {
- for (var key in computed) {
- registerComputed(this$1, key, computed[key]);
- }
- }
- };
- UIkit.prototype._resetComputeds = function() {
- this._computeds = {};
- };
- UIkit.prototype._initProps = function(props) {
- var this$1 = this;
- var key;
- this._resetComputeds();
- props = props || getProps(this.$options, this.$name);
- for (key in props) {
- if (!isUndefined(props[key])) {
- this$1.$props[key] = props[key];
- }
- }
- var exclude = [ this.$options.computed, this.$options.methods ];
- for (key in this$1.$props) {
- if (key in props && notIn(exclude, key)) {
- this$1[key] = this$1.$props[key];
- }
- }
- };
- UIkit.prototype._initEvents = function() {
- var this$1 = this;
- var ref = this.$options;
- var events = ref.events;
- if (events) {
- events.forEach(function(event) {
- if (!hasOwn(event, "handler")) {
- for (var key in event) {
- registerEvent(this$1, event[key], key);
- }
- } else {
- registerEvent(this$1, event);
- }
- });
- }
- };
- UIkit.prototype._unbindEvents = function() {
- this._events.forEach(function(unbind) {
- return unbind();
- });
- this._events = [];
- };
- UIkit.prototype._initObserver = function() {
- var this$1 = this;
- var ref = this.$options;
- var attrs = ref.attrs;
- var props = ref.props;
- var el = ref.el;
- if (this._observer || !props || !attrs) {
- return;
- }
- attrs = isArray(attrs) ? attrs : Object.keys(props).map(function(key) {
- return hyphenate(key);
- });
- this._observer = new MutationObserver(function() {
- var data$$1 = getProps(this$1.$options, this$1.$name);
- if (attrs.some(function(key) {
- return !isUndefined(data$$1[key]) && data$$1[key] !== this$1.$props[key];
- })) {
- this$1.$reset(data$$1);
- }
- });
- this._observer.observe(el, {
- attributes: true,
- attributeFilter: attrs.concat([ this.$name, "data-" + this.$name ])
- });
- };
- function getProps(opts, name) {
- var data$$1 = {};
- var args = opts.args;
- if (args === void 0) args = [];
- var props = opts.props;
- if (props === void 0) props = {};
- var el = opts.el;
- if (!props) {
- return data$$1;
- }
- for (var key in props) {
- var prop = hyphenate(key);
- if (hasAttr(el, prop)) {
- var value = coerce(props[key], attr(el, prop), el);
- if (prop === "target" && (!value || startsWith(value, "_"))) {
- continue;
- }
- data$$1[key] = value;
- }
- }
- var options = parseOptions(data(el, name), args);
- for (var key$1 in options) {
- var prop$1 = camelize(key$1);
- if (props[prop$1] !== undefined) {
- data$$1[prop$1] = coerce(props[prop$1], options[key$1], el);
- }
- }
- return data$$1;
- }
- function parseOptions(options, args) {
- var obj;
- if (args === void 0) args = [];
- try {
- return !options ? {} : startsWith(options, "{") ? JSON.parse(options) : args.length && !includes(options, ":") ? (obj = {},
- obj[args[0]] = options, obj) : options.split(";").reduce(function(options, option) {
- var ref = option.split(/:(.+)/);
- var key = ref[0];
- var value = ref[1];
- if (key && value) {
- options[key.trim()] = value.trim();
- }
- return options;
- }, {});
- } catch (e) {
- return {};
- }
- }
- function registerComputed(component, key, cb) {
- Object.defineProperty(component, key, {
- enumerable: true,
- get: function get() {
- var _computeds = component._computeds;
- var $props = component.$props;
- var $el = component.$el;
- if (!hasOwn(_computeds, key)) {
- _computeds[key] = cb.call(component, $props, $el);
- }
- return _computeds[key];
- },
- set: function set(value) {
- component._computeds[key] = value;
- }
- });
- }
- function registerEvent(component, event, key) {
- if (!isPlainObject(event)) {
- event = {
- name: key,
- handler: event
- };
- }
- var name = event.name;
- var el = event.el;
- var handler = event.handler;
- var capture = event.capture;
- var delegate = event.delegate;
- var filter = event.filter;
- var self = event.self;
- el = isFunction(el) ? el.call(component) : el || component.$el;
- if (isArray(el)) {
- el.forEach(function(el) {
- return registerEvent(component, assign({}, event, {
- el: el
- }), key);
- });
- return;
- }
- if (!el || filter && !filter.call(component)) {
- return;
- }
- handler = detail(isString(handler) ? component[handler] : bind(handler, component));
- if (self) {
- handler = selfFilter(handler);
- }
- component._events.push(on(el, name, !delegate ? null : isString(delegate) ? delegate : delegate.call(component), handler, capture));
- }
- function selfFilter(handler) {
- return function selfHandler(e) {
- if (e.target === e.currentTarget || e.target === e.current) {
- return handler.call(null, e);
- }
- };
- }
- function notIn(options, key) {
- return options.every(function(arr) {
- return !arr || !hasOwn(arr, key);
- });
- }
- function detail(listener) {
- return function(e) {
- return isArray(e.detail) ? listener.apply(void 0, [ e ].concat(e.detail)) : listener(e);
- };
- }
- function coerce(type, value, context) {
- if (type === Boolean) {
- return toBoolean(value);
- } else if (type === Number) {
- return toNumber(value);
- } else if (type === "query") {
- return query(value, context);
- } else if (type === "list") {
- return toList(value);
- } else if (type === "media") {
- return toMedia(value);
- }
- return type ? type(value) : value;
- }
- function toMedia(value) {
- if (isString(value)) {
- if (value[0] === "@") {
- var name = "media-" + value.substr(1);
- value = toFloat(getCssVar(name));
- } else if (isNaN(value)) {
- return value;
- }
- }
- return value && !isNaN(value) ? "(min-width: " + value + "px)" : false;
- }
- }
- function instanceAPI(UIkit) {
- var DATA = UIkit.data;
- UIkit.prototype.$mount = function(el) {
- var ref = this.$options;
- var name = ref.name;
- if (!el[DATA]) {
- el[DATA] = {};
- }
- if (el[DATA][name]) {
- return;
- }
- el[DATA][name] = this;
- this.$el = this.$options.el = this.$options.el || el;
- this._initProps();
- this._callHook("init");
- if (within(el, document)) {
- this._callConnected();
- }
- };
- UIkit.prototype.$emit = function(e) {
- this._callUpdate(e);
- };
- UIkit.prototype.$reset = function(data) {
- this._callDisconnected();
- this._initProps(data);
- this._callConnected();
- };
- UIkit.prototype.$destroy = function(removeEl) {
- if (removeEl === void 0) removeEl = false;
- var ref = this.$options;
- var el = ref.el;
- var name = ref.name;
- if (el) {
- this._callDisconnected();
- }
- this._callHook("destroy");
- if (!el || !el[DATA]) {
- return;
- }
- delete el[DATA][name];
- if (!Object.keys(el[DATA]).length) {
- delete el[DATA];
- }
- if (removeEl) {
- remove(this.$el);
- }
- };
- }
- var UIkit$2 = function(options) {
- this._init(options);
- };
- UIkit$2.util = util;
- UIkit$2.data = "__uikit__";
- UIkit$2.prefix = "uk-";
- UIkit$2.options = {};
- globalAPI(UIkit$2);
- hooksAPI(UIkit$2);
- stateAPI(UIkit$2);
- instanceAPI(UIkit$2);
- componentAPI(UIkit$2);
- var Class = {
- init: function init() {
- addClass(this.$el, this.$name);
- }
- };
- var Container = {
- props: {
- container: Boolean
- },
- defaults: {
- container: true
- },
- computed: {
- container: function container(ref) {
- var container = ref.container;
- return container === true && UIkit$2.container || container && $(container);
- }
- }
- };
- var Togglable = {
- props: {
- cls: Boolean,
- animation: "list",
- duration: Number,
- origin: String,
- transition: String,
- queued: Boolean
- },
- defaults: {
- cls: false,
- animation: [ false ],
- duration: 200,
- origin: false,
- transition: "linear",
- queued: false,
- initProps: {
- overflow: "",
- height: "",
- paddingTop: "",
- paddingBottom: "",
- marginTop: "",
- marginBottom: ""
- },
- hideProps: {
- overflow: "hidden",
- height: 0,
- paddingTop: 0,
- paddingBottom: 0,
- marginTop: 0,
- marginBottom: 0
- }
- },
- computed: {
- hasAnimation: function hasAnimation(ref) {
- var animation = ref.animation;
- return !!animation[0];
- },
- hasTransition: function hasTransition(ref) {
- var animation = ref.animation;
- return this.hasAnimation && animation[0] === true;
- }
- },
- methods: {
- toggleElement: function toggleElement(targets, show, animate) {
- var this$1 = this;
- return new Promise(function(resolve) {
- targets = toNodes(targets);
- var all = function(targets) {
- return Promise.all(targets.map(function(el) {
- return this$1._toggleElement(el, show, animate);
- }));
- };
- var toggled = targets.filter(function(el) {
- return this$1.isToggled(el);
- });
- var untoggled = targets.filter(function(el) {
- return !includes(toggled, el);
- });
- var p;
- if (!this$1.queued || !isUndefined(animate) || !isUndefined(show) || !this$1.hasAnimation || targets.length < 2) {
- p = all(untoggled.concat(toggled));
- } else {
- var body = document.body;
- var scroll = body.scrollTop;
- var el = toggled[0];
- var inProgress = Animation.inProgress(el) && hasClass(el, "uk-animation-leave") || Transition.inProgress(el) && el.style.height === "0px";
- p = all(toggled);
- if (!inProgress) {
- p = p.then(function() {
- var p = all(untoggled);
- body.scrollTop = scroll;
- return p;
- });
- }
- }
- p.then(resolve, noop);
- });
- },
- toggleNow: function toggleNow(targets, show) {
- var this$1 = this;
- return new Promise(function(resolve) {
- return Promise.all(toNodes(targets).map(function(el) {
- return this$1._toggleElement(el, show, false);
- })).then(resolve, noop);
- });
- },
- isToggled: function isToggled(el) {
- var nodes = toNodes(el || this.$el);
- return this.cls ? hasClass(nodes, this.cls.split(" ")[0]) : !hasAttr(nodes, "hidden");
- },
- updateAria: function updateAria(el) {
- if (this.cls === false) {
- attr(el, "aria-hidden", !this.isToggled(el));
- }
- },
- _toggleElement: function _toggleElement(el, show, animate) {
- var this$1 = this;
- show = isBoolean(show) ? show : Animation.inProgress(el) ? hasClass(el, "uk-animation-leave") : Transition.inProgress(el) ? el.style.height === "0px" : !this.isToggled(el);
- if (!trigger(el, "before" + (show ? "show" : "hide"), [ this ])) {
- return Promise.reject();
- }
- var promise = (animate === false || !this.hasAnimation ? this._toggleImmediate : this.hasTransition ? this._toggleHeight : this._toggleAnimation)(el, show);
- trigger(el, show ? "show" : "hide", [ this ]);
- return promise.then(function() {
- trigger(el, show ? "shown" : "hidden", [ this$1 ]);
- trigger(el, "resize");
- });
- },
- _toggle: function _toggle(el, toggled) {
- if (!el) {
- return;
- }
- var changed;
- if (this.cls) {
- changed = includes(this.cls, " ") || Boolean(toggled) !== hasClass(el, this.cls);
- changed && toggleClass(el, this.cls, includes(this.cls, " ") ? undefined : toggled);
- } else {
- changed = Boolean(toggled) === hasAttr(el, "hidden");
- changed && attr(el, "hidden", !toggled ? "" : null);
- }
- $$("[autofocus]", el).some(function(el) {
- return isVisible(el) && (el.focus() || true);
- });
- this.updateAria(el);
- changed && trigger(el, "resize");
- },
- _toggleImmediate: function _toggleImmediate(el, show) {
- this._toggle(el, show);
- return Promise.resolve();
- },
- _toggleHeight: function _toggleHeight(el, show) {
- var this$1 = this;
- var inProgress = Transition.inProgress(el);
- var inner = el.hasChildNodes ? toFloat(css(el.firstElementChild, "marginTop")) + toFloat(css(el.lastElementChild, "marginBottom")) : 0;
- var currentHeight = isVisible(el) ? height(el) + (inProgress ? 0 : inner) : 0;
- Transition.cancel(el);
- if (!this.isToggled(el)) {
- this._toggle(el, true);
- }
- height(el, "");
- fastdom.flush();
- var endHeight = height(el) + (inProgress ? 0 : inner);
- height(el, currentHeight);
- return (show ? Transition.start(el, assign({}, this.initProps, {
- overflow: "hidden",
- height: endHeight
- }), Math.round(this.duration * (1 - currentHeight / endHeight)), this.transition) : Transition.start(el, this.hideProps, Math.round(this.duration * (currentHeight / endHeight)), this.transition).then(function() {
- return this$1._toggle(el, false);
- })).then(function() {
- return css(el, this$1.initProps);
- });
- },
- _toggleAnimation: function _toggleAnimation(el, show) {
- var this$1 = this;
- Animation.cancel(el);
- if (show) {
- this._toggle(el, true);
- return Animation.in(el, this.animation[0], this.duration, this.origin);
- }
- return Animation.out(el, this.animation[1] || this.animation[0], this.duration, this.origin).then(function() {
- return this$1._toggle(el, false);
- });
- }
- }
- };
- var active;
- var Modal = {
- mixins: [ Class, Container, Togglable ],
- props: {
- selPanel: String,
- selClose: String,
- escClose: Boolean,
- bgClose: Boolean,
- stack: Boolean
- },
- defaults: {
- cls: "uk-open",
- escClose: true,
- bgClose: true,
- overlay: true,
- stack: false
- },
- computed: {
- panel: function panel(ref, $el) {
- var selPanel = ref.selPanel;
- return $(selPanel, $el);
- },
- transitionElement: function transitionElement() {
- return this.panel;
- },
- transitionDuration: function transitionDuration() {
- return toMs(css(this.transitionElement, "transitionDuration"));
- }
- },
- events: [ {
- name: "click",
- delegate: function delegate() {
- return this.selClose;
- },
- handler: function handler(e) {
- e.preventDefault();
- this.hide();
- }
- }, {
- name: "toggle",
- self: true,
- handler: function handler(e) {
- if (e.defaultPrevented) {
- return;
- }
- e.preventDefault();
- this.toggle();
- }
- }, {
- name: "beforeshow",
- self: true,
- handler: function handler(e) {
- var prev = active && active !== this && active;
- active = this;
- if (prev) {
- if (this.stack) {
- this.prev = prev;
- } else {
- prev.hide().then(this.show);
- e.preventDefault();
- return;
- }
- }
- registerEvents();
- }
- }, {
- name: "beforehide",
- self: true,
- handler: function handler() {
- active = active && active !== this && active || this.prev;
- if (!active) {
- deregisterEvents();
- }
- }
- }, {
- name: "show",
- self: true,
- handler: function handler() {
- if (!hasClass(document.documentElement, this.clsPage)) {
- this.scrollbarWidth = width(window) - width(document);
- css(document.body, "overflowY", this.scrollbarWidth && this.overlay ? "scroll" : "");
- }
- addClass(document.documentElement, this.clsPage);
- }
- }, {
- name: "hidden",
- self: true,
- handler: function handler() {
- var this$1 = this;
- var found;
- var ref = this;
- var prev = ref.prev;
- while (prev) {
- if (prev.clsPage === this$1.clsPage) {
- found = true;
- break;
- }
- prev = prev.prev;
- }
- if (!found) {
- removeClass(document.documentElement, this.clsPage);
- }
- !this.prev && css(document.body, "overflowY", "");
- }
- } ],
- methods: {
- toggle: function toggle() {
- return this.isToggled() ? this.hide() : this.show();
- },
- show: function show() {
- if (this.isToggled()) {
- return;
- }
- if (this.container && this.$el.parentNode !== this.container) {
- append(this.container, this.$el);
- this._callConnected();
- }
- return this.toggleNow(this.$el, true);
- },
- hide: function hide() {
- if (this.isToggled()) {
- return this.toggleNow(this.$el, false);
- }
- },
- getActive: function getActive() {
- return active;
- },
- _toggleImmediate: function _toggleImmediate(el, show) {
- var this$1 = this;
- return new Promise(function(resolve) {
- return requestAnimationFrame(function() {
- this$1._toggle(el, show);
- if (this$1.transitionDuration) {
- once(this$1.transitionElement, "transitionend", resolve, false, function(e) {
- return e.target === this$1.transitionElement;
- });
- } else {
- resolve();
- }
- });
- });
- }
- }
- };
- var events;
- function registerEvents() {
- if (events) {
- return;
- }
- events = [ on(document, "click", function(ref) {
- var target = ref.target;
- var defaultPrevented = ref.defaultPrevented;
- if (active && active.bgClose && !defaultPrevented && (!active.overlay || within(target, active.$el)) && (!active.panel || !within(target, active.panel))) {
- active.hide();
- }
- }), on(document, "keydown", function(e) {
- if (e.keyCode === 27 && active && active.escClose) {
- e.preventDefault();
- active.hide();
- }
- }) ];
- }
- function deregisterEvents() {
- events && events.forEach(function(unbind) {
- return unbind();
- });
- events = null;
- }
- var Position = {
- props: {
- pos: String,
- offset: null,
- flip: Boolean,
- clsPos: String
- },
- defaults: {
- pos: "bottom-" + (!isRtl ? "left" : "right"),
- flip: true,
- offset: false,
- clsPos: ""
- },
- computed: {
- pos: function pos(ref) {
- var pos = ref.pos;
- return (pos + (!includes(pos, "-") ? "-center" : "")).split("-");
- },
- dir: function dir() {
- return this.pos[0];
- },
- align: function align() {
- return this.pos[1];
- }
- },
- methods: {
- positionAt: function positionAt$1(element, target, boundary) {
- removeClasses(element, this.clsPos + "-(top|bottom|left|right)(-[a-z]+)?");
- css(element, {
- top: "",
- left: ""
- });
- var node;
- var ref = this;
- var offset$$1 = ref.offset;
- offset$$1 = isNumeric(offset$$1) ? offset$$1 : (node = $(offset$$1)) ? offset(node)[axis === "x" ? "left" : "top"] - offset(target)[axis === "x" ? "right" : "bottom"] : 0;
- var axis = this.getAxis();
- var ref$1 = positionAt(element, target, axis === "x" ? flipPosition(this.dir) + " " + this.align : this.align + " " + flipPosition(this.dir), axis === "x" ? this.dir + " " + this.align : this.align + " " + this.dir, axis === "x" ? "" + (this.dir === "left" ? -offset$$1 : offset$$1) : " " + (this.dir === "top" ? -offset$$1 : offset$$1), null, this.flip, boundary).target;
- var x = ref$1.x;
- var y = ref$1.y;
- this.dir = axis === "x" ? x : y;
- this.align = axis === "x" ? y : x;
- toggleClass(element, this.clsPos + "-" + this.dir + "-" + this.align, this.offset === false);
- },
- getAxis: function getAxis() {
- return this.dir === "top" || this.dir === "bottom" ? "y" : "x";
- }
- }
- };
- function mixin(UIkit) {
- UIkit.mixin.class = Class;
- UIkit.mixin.container = Container;
- UIkit.mixin.modal = Modal;
- UIkit.mixin.position = Position;
- UIkit.mixin.togglable = Togglable;
- }
- function Accordion(UIkit) {
- UIkit.component("accordion", {
- mixins: [ Class, Togglable ],
- props: {
- targets: String,
- active: null,
- collapsible: Boolean,
- multiple: Boolean,
- toggle: String,
- content: String,
- transition: String
- },
- defaults: {
- targets: "> *",
- active: false,
- animation: [ true ],
- collapsible: true,
- multiple: false,
- clsOpen: "uk-open",
- toggle: "> .uk-accordion-title",
- content: "> .uk-accordion-content",
- transition: "ease"
- },
- computed: {
- items: function items(ref, $el) {
- var targets = ref.targets;
- return $$(targets, $el);
- }
- },
- events: [ {
- name: "click",
- delegate: function delegate() {
- return this.targets + " " + this.$props.toggle;
- },
- handler: function handler(e) {
- e.preventDefault();
- this.toggle(index($$(this.targets + " " + this.$props.toggle, this.$el), e.current));
- }
- } ],
- connected: function connected() {
- if (this.active === false) {
- return;
- }
- var active = this.items[Number(this.active)];
- if (active && !hasClass(active, this.clsOpen)) {
- this.toggle(active, false);
- }
- },
- update: function update() {
- var this$1 = this;
- this.items.forEach(function(el) {
- return this$1._toggleImmediate($(this$1.content, el), hasClass(el, this$1.clsOpen));
- });
- var active = !this.collapsible && !hasClass(this.items, this.clsOpen) && this.items[0];
- if (active) {
- this.toggle(active, false);
- }
- },
- methods: {
- toggle: function toggle(item, animate) {
- var this$1 = this;
- var index = getIndex(item, this.items);
- var active = filter(this.items, "." + this.clsOpen);
- item = this.items[index];
- item && [ item ].concat(!this.multiple && !includes(active, item) && active || []).forEach(function(el) {
- var isItem = el === item;
- var state = isItem && !hasClass(el, this$1.clsOpen);
- if (!state && isItem && !this$1.collapsible && active.length < 2) {
- return;
- }
- toggleClass(el, this$1.clsOpen, state);
- var content = el._wrapper ? el._wrapper.firstElementChild : $(this$1.content, el);
- if (!el._wrapper) {
- el._wrapper = wrapAll(content, "
");
- attr(el._wrapper, "hidden", state ? "" : null);
- }
- this$1._toggleImmediate(content, true);
- this$1.toggleElement(el._wrapper, state, animate).then(function() {
- if (hasClass(el, this$1.clsOpen) === state) {
- if (!state) {
- this$1._toggleImmediate(content, false);
- }
- el._wrapper = null;
- unwrap(content);
- }
- });
- });
- }
- }
- });
- }
- function Alert(UIkit) {
- UIkit.component("alert", {
- attrs: true,
- mixins: [ Class, Togglable ],
- args: "animation",
- props: {
- close: String
- },
- defaults: {
- animation: [ true ],
- selClose: ".uk-alert-close",
- duration: 150,
- hideProps: assign({
- opacity: 0
- }, Togglable.defaults.hideProps)
- },
- events: [ {
- name: "click",
- delegate: function delegate() {
- return this.selClose;
- },
- handler: function handler(e) {
- e.preventDefault();
- this.close();
- }
- } ],
- methods: {
- close: function close() {
- var this$1 = this;
- this.toggleElement(this.$el).then(function() {
- return this$1.$destroy(true);
- });
- }
- }
- });
- }
- function Core(UIkit) {
- ready(function() {
- var scroll = 0;
- var started = 0;
- on(window, "load resize", function(e) {
- return UIkit.update(null, e);
- });
- on(window, "scroll", function(e) {
- e.dir = scroll <= window.pageYOffset ? "down" : "up";
- e.scrollY = scroll = window.pageYOffset;
- UIkit.update(null, e);
- });
- on(document, "animationstart", function(ref) {
- var target = ref.target;
- if ((css(target, "animationName") || "").match(/^uk-.*(left|right)/)) {
- started++;
- css(document.body, "overflowX", "hidden");
- setTimeout(function() {
- if (!--started) {
- css(document.body, "overflowX", "");
- }
- }, toMs(css(target, "animationDuration")) + 100);
- }
- }, true);
- if (!hasTouch) {
- return;
- }
- var cls = "uk-hover";
- on(document, "tap", function(ref) {
- var target = ref.target;
- return $$("." + cls).forEach(function(el) {
- return !within(target, el) && removeClass(el, cls);
- });
- });
- Object.defineProperty(UIkit, "hoverSelector", {
- set: function set(selector) {
- on(document, "tap", selector, function(ref) {
- var current = ref.current;
- return addClass(current, cls);
- });
- }
- });
- UIkit.hoverSelector = ".uk-animation-toggle, .uk-transition-toggle, [uk-hover]";
- });
- }
- function Cover(UIkit) {
- UIkit.component("cover", {
- mixins: [ Class, UIkit.components.video.options ],
- props: {
- width: Number,
- height: Number
- },
- defaults: {
- automute: true
- },
- update: {
- write: function write() {
- var el = this.$el;
- if (!isVisible(el)) {
- return;
- }
- var ref = el.parentNode;
- var height = ref.offsetHeight;
- var width = ref.offsetWidth;
- css(css(el, {
- width: "",
- height: ""
- }), Dimensions.cover({
- width: this.width || el.clientWidth,
- height: this.height || el.clientHeight
- }, {
- width: width + (width % 2 ? 1 : 0),
- height: height + (height % 2 ? 1 : 0)
- }));
- },
- events: [ "load", "resize" ]
- },
- events: {
- loadedmetadata: function loadedmetadata() {
- this.$emit();
- }
- }
- });
- }
- function Drop(UIkit) {
- var active;
- UIkit.component("drop", {
- mixins: [ Position, Togglable ],
- args: "pos",
- props: {
- mode: "list",
- toggle: Boolean,
- boundary: "query",
- boundaryAlign: Boolean,
- delayShow: Number,
- delayHide: Number,
- clsDrop: String
- },
- defaults: {
- mode: [ "click", "hover" ],
- toggle: true,
- boundary: window,
- boundaryAlign: false,
- delayShow: 0,
- delayHide: 800,
- clsDrop: false,
- hoverIdle: 200,
- animation: [ "uk-animation-fade" ],
- cls: "uk-open"
- },
- computed: {
- clsDrop: function clsDrop(ref) {
- var clsDrop = ref.clsDrop;
- return clsDrop || "uk-" + this.$options.name;
- },
- clsPos: function clsPos() {
- return this.clsDrop;
- }
- },
- init: function init() {
- this.tracker = new MouseTracker();
- addClass(this.$el, this.clsDrop);
- },
- connected: function connected() {
- var ref = this.$props;
- var toggle = ref.toggle;
- this.toggle = toggle && UIkit.toggle(isString(toggle) ? query(toggle, this.$el) : this.$el.previousElementSibling, {
- target: this.$el,
- mode: this.mode
- });
- this.updateAria(this.$el);
- },
- events: [ {
- name: "click",
- delegate: function delegate() {
- return "." + this.clsDrop + "-close";
- },
- handler: function handler(e) {
- e.preventDefault();
- this.hide(false);
- }
- }, {
- name: "click",
- delegate: function delegate() {
- return 'a[href^="#"]';
- },
- handler: function handler(e) {
- if (e.defaultPrevented) {
- return;
- }
- var id = e.target.hash;
- if (!id) {
- e.preventDefault();
- }
- if (!id || !within(id, this.$el)) {
- this.hide(false);
- }
- }
- }, {
- name: "beforescroll",
- handler: function handler() {
- this.hide(false);
- }
- }, {
- name: "toggle",
- self: true,
- handler: function handler(e, toggle) {
- e.preventDefault();
- if (this.isToggled()) {
- this.hide(false);
- } else {
- this.show(toggle, false);
- }
- }
- }, {
- name: pointerEnter,
- filter: function filter() {
- return includes(this.mode, "hover");
- },
- handler: function handler(e) {
- if (isTouch(e)) {
- return;
- }
- if (active && active !== this && active.toggle && includes(active.toggle.mode, "hover") && !within(e.target, active.toggle.$el) && !pointInRect({
- x: e.pageX,
- y: e.pageY
- }, offset(active.$el))) {
- active.hide(false);
- }
- e.preventDefault();
- this.show(this.toggle);
- }
- }, {
- name: "toggleshow",
- handler: function handler(e, toggle) {
- if (toggle && !includes(toggle.target, this.$el)) {
- return;
- }
- e.preventDefault();
- this.show(toggle || this.toggle);
- }
- }, {
- name: "togglehide " + pointerLeave,
- handler: function handler(e, toggle) {
- if (isTouch(e) || toggle && !includes(toggle.target, this.$el)) {
- return;
- }
- e.preventDefault();
- if (this.toggle && includes(this.toggle.mode, "hover")) {
- this.hide();
- }
- }
- }, {
- name: "beforeshow",
- self: true,
- handler: function handler() {
- this.clearTimers();
- Animation.cancel(this.$el);
- this.position();
- }
- }, {
- name: "show",
- self: true,
- handler: function handler() {
- this.tracker.init();
- if (this.toggle) {
- addClass(this.toggle.$el, this.cls);
- attr(this.toggle.$el, "aria-expanded", "true");
- }
- registerEvent();
- }
- }, {
- name: "beforehide",
- self: true,
- handler: function handler() {
- this.clearTimers();
- }
- }, {
- name: "hide",
- handler: function handler(ref) {
- var target = ref.target;
- if (this.$el !== target) {
- active = active === null && within(target, this.$el) && this.isToggled() ? this : active;
- return;
- }
- active = this.isActive() ? null : active;
- if (this.toggle) {
- removeClass(this.toggle.$el, this.cls);
- attr(this.toggle.$el, "aria-expanded", "false");
- this.toggle.$el.blur();
- $$("a, button", this.toggle.$el).forEach(function(el) {
- return el.blur();
- });
- }
- this.tracker.cancel();
- }
- } ],
- update: {
- write: function write() {
- if (this.isToggled() && !Animation.inProgress(this.$el)) {
- this.position();
- }
- },
- events: [ "resize" ]
- },
- methods: {
- show: function show(toggle, delay) {
- var this$1 = this;
- if (delay === void 0) delay = true;
- var show = function() {
- return !this$1.isToggled() && this$1.toggleElement(this$1.$el, true);
- };
- var tryShow = function() {
- this$1.toggle = toggle || this$1.toggle;
- this$1.clearTimers();
- if (this$1.isActive()) {
- return;
- } else if (delay && active && active !== this$1 && active.isDelaying) {
- this$1.showTimer = setTimeout(this$1.show, 10);
- return;
- } else if (this$1.isParentOf(active)) {
- if (active.hideTimer) {
- active.hide(false);
- } else {
- return;
- }
- } else if (active && !this$1.isChildOf(active) && !this$1.isParentOf(active)) {
- var prev;
- while (active && active !== prev && !this$1.isChildOf(active)) {
- prev = active;
- active.hide(false);
- }
- }
- if (delay && this$1.delayShow) {
- this$1.showTimer = setTimeout(show, this$1.delayShow);
- } else {
- show();
- }
- active = this$1;
- };
- if (toggle && this.toggle && toggle.$el !== this.toggle.$el) {
- once(this.$el, "hide", tryShow);
- this.hide(false);
- } else {
- tryShow();
- }
- },
- hide: function hide(delay) {
- var this$1 = this;
- if (delay === void 0) delay = true;
- var hide = function() {
- return this$1.toggleNow(this$1.$el, false);
- };
- this.clearTimers();
- this.isDelaying = this.tracker.movesTo(this.$el);
- if (delay && this.isDelaying) {
- this.hideTimer = setTimeout(this.hide, this.hoverIdle);
- } else if (delay && this.delayHide) {
- this.hideTimer = setTimeout(hide, this.delayHide);
- } else {
- hide();
- }
- },
- clearTimers: function clearTimers() {
- clearTimeout(this.showTimer);
- clearTimeout(this.hideTimer);
- this.showTimer = null;
- this.hideTimer = null;
- this.isDelaying = false;
- },
- isActive: function isActive() {
- return active === this;
- },
- isChildOf: function isChildOf(drop) {
- return drop && drop !== this && within(this.$el, drop.$el);
- },
- isParentOf: function isParentOf(drop) {
- return drop && drop !== this && within(drop.$el, this.$el);
- },
- position: function position() {
- removeClasses(this.$el, this.clsDrop + "-(stack|boundary)");
- css(this.$el, {
- top: "",
- left: "",
- display: "block"
- });
- toggleClass(this.$el, this.clsDrop + "-boundary", this.boundaryAlign);
- var boundary = offset(this.boundary);
- var alignTo = this.boundaryAlign ? boundary : offset(this.toggle.$el);
- if (this.align === "justify") {
- var prop = this.getAxis() === "y" ? "width" : "height";
- css(this.$el, prop, alignTo[prop]);
- } else if (this.$el.offsetWidth > Math.max(boundary.right - alignTo.left, alignTo.right - boundary.left)) {
- addClass(this.$el, this.clsDrop + "-stack");
- }
- this.positionAt(this.$el, this.boundaryAlign ? this.boundary : this.toggle.$el, this.boundary);
- css(this.$el, "display", "");
- }
- }
- });
- UIkit.drop.getActive = function() {
- return active;
- };
- var registered;
- function registerEvent() {
- if (registered) {
- return;
- }
- registered = true;
- on(document, "click", function(ref) {
- var target = ref.target;
- var defaultPrevented = ref.defaultPrevented;
- var prev;
- if (defaultPrevented) {
- return;
- }
- while (active && active !== prev && !within(target, active.$el) && !(active.toggle && within(target, active.toggle.$el))) {
- prev = active;
- active.hide(false);
- }
- });
- }
- }
- function Dropdown(UIkit) {
- UIkit.component("dropdown", UIkit.components.drop.extend({
- name: "dropdown"
- }));
- }
- function FormCustom(UIkit) {
- UIkit.component("form-custom", {
- mixins: [ Class ],
- args: "target",
- props: {
- target: Boolean
- },
- defaults: {
- target: false
- },
- computed: {
- input: function input(_, $el) {
- return $(selInput, $el);
- },
- state: function state() {
- return this.input.nextElementSibling;
- },
- target: function target(ref, $el) {
- var target = ref.target;
- return target && (target === true && this.input.parentNode === $el && this.input.nextElementSibling || query(target, $el));
- }
- },
- update: function update() {
- var ref = this;
- var target = ref.target;
- var input = ref.input;
- if (!target) {
- return;
- }
- var option;
- target[isInput(target) ? "value" : "textContent"] = input.files && input.files[0] ? input.files[0].name : matches(input, "select") && (option = $$("option", input).filter(function(el) {
- return el.selected;
- })[0]) ? option.textContent : input.value;
- },
- events: [ {
- name: "focusin focusout mouseenter mouseleave",
- delegate: selInput,
- handler: function handler(ref) {
- var type = ref.type;
- var current = ref.current;
- if (current === this.input) {
- toggleClass(this.state, "uk-" + (includes(type, "focus") ? "focus" : "hover"), includes([ "focusin", "mouseenter" ], type));
- }
- }
- }, {
- name: "change",
- handler: function handler() {
- this.$emit();
- }
- } ]
- });
- }
- function Gif(UIkit) {
- UIkit.component("gif", {
- update: {
- read: function read(data) {
- var inview = isInView(this.$el);
- if (!inview || data.isInView === inview) {
- return false;
- }
- data.isInView = inview;
- },
- write: function write() {
- this.$el.src = this.$el.src;
- },
- events: [ "scroll", "load", "resize" ]
- }
- });
- }
- function Grid(UIkit) {
- UIkit.component("grid", UIkit.components.margin.extend({
- mixins: [ Class ],
- name: "grid",
- defaults: {
- margin: "uk-grid-margin",
- clsStack: "uk-grid-stack"
- },
- update: {
- write: function write(ref) {
- var stacks = ref.stacks;
- toggleClass(this.$el, this.clsStack, stacks);
- },
- events: [ "load", "resize" ]
- }
- }));
- }
- function HeightMatch(UIkit) {
- UIkit.component("height-match", {
- args: "target",
- props: {
- target: String,
- row: Boolean
- },
- defaults: {
- target: "> *",
- row: true
- },
- computed: {
- elements: function elements(ref, $el) {
- var target = ref.target;
- return $$(target, $el);
- }
- },
- update: {
- read: function read() {
- var this$1 = this;
- var lastOffset = false;
- css(this.elements, "minHeight", "");
- return {
- rows: !this.row ? [ this.match(this.elements) ] : this.elements.reduce(function(rows, el) {
- if (lastOffset !== el.offsetTop) {
- rows.push([ el ]);
- } else {
- rows[rows.length - 1].push(el);
- }
- lastOffset = el.offsetTop;
- return rows;
- }, []).map(function(elements) {
- return this$1.match(elements);
- })
- };
- },
- write: function write(ref) {
- var rows = ref.rows;
- rows.forEach(function(ref) {
- var height = ref.height;
- var elements = ref.elements;
- return css(elements, "minHeight", height);
- });
- },
- events: [ "load", "resize" ]
- },
- methods: {
- match: function match(elements) {
- if (elements.length < 2) {
- return {};
- }
- var heights = [];
- var max = 0;
- elements.forEach(function(el) {
- var style, hidden;
- if (!isVisible(el)) {
- style = attr(el, "style");
- hidden = attr(el, "hidden");
- attr(el, {
- style: (style || "") + ";display:block !important;",
- hidden: null
- });
- }
- max = Math.max(max, el.offsetHeight);
- heights.push(el.offsetHeight);
- if (!isUndefined(style)) {
- attr(el, {
- style: style,
- hidden: hidden
- });
- }
- });
- elements = elements.filter(function(el, i) {
- return heights[i] < max;
- });
- return {
- height: max,
- elements: elements
- };
- }
- }
- });
- }
- function HeightViewport(UIkit) {
- UIkit.component("height-viewport", {
- props: {
- expand: Boolean,
- offsetTop: Boolean,
- offsetBottom: Boolean,
- minHeight: Number
- },
- defaults: {
- expand: false,
- offsetTop: false,
- offsetBottom: false,
- minHeight: 0
- },
- update: {
- write: function write() {
- css(this.$el, "boxSizing", "border-box");
- var viewport = height(window);
- var minHeight, offsetTop = 0;
- if (this.expand) {
- css(this.$el, {
- height: "",
- minHeight: ""
- });
- var diff = viewport - offsetHeight(document.documentElement);
- if (diff > 0) {
- minHeight = offsetHeight(this.$el) + diff;
- }
- } else {
- var ref = offset(this.$el);
- var top = ref.top;
- if (top < viewport / 2 && this.offsetTop) {
- offsetTop += top;
- }
- if (this.offsetBottom === true) {
- offsetTop += offsetHeight(this.$el.nextElementSibling);
- } else if (isNumeric(this.offsetBottom)) {
- offsetTop += viewport / 100 * this.offsetBottom;
- } else if (this.offsetBottom && endsWith(this.offsetBottom, "px")) {
- offsetTop += toFloat(this.offsetBottom);
- } else if (isString(this.offsetBottom)) {
- offsetTop += offsetHeight(query(this.offsetBottom, this.$el));
- }
- minHeight = offsetTop ? "calc(100vh - " + offsetTop + "px)" : "100vh";
- }
- if (!minHeight) {
- return;
- }
- css(this.$el, {
- height: "",
- minHeight: minHeight
- });
- var elHeight = this.$el.offsetHeight;
- if (this.minHeight && this.minHeight > elHeight) {
- css(this.$el, "minHeight", this.minHeight);
- }
- if (viewport - offsetTop >= elHeight) {
- css(this.$el, "height", minHeight);
- }
- },
- events: [ "load", "resize" ]
- }
- });
- function offsetHeight(el) {
- return el && el.offsetHeight || 0;
- }
- }
- var closeIcon = '
';
- var closeLarge = '
';
- var marker = '
';
- var navbarToggleIcon = '
';
- var overlayIcon = '
';
- var paginationNext = '
';
- var paginationPrevious = '
';
- var searchIcon = '
';
- var searchLarge = '
';
- var searchNavbar = '
';
- var slidenavNext = '
';
- var slidenavNextLarge = '
';
- var slidenavPrevious = '
';
- var slidenavPreviousLarge = '
';
- var spinner = '
';
- var totop = '
';
- function Icon(UIkit) {
- var parsed = {};
- var icons = {
- spinner: spinner,
- totop: totop,
- marker: marker,
- "close-icon": closeIcon,
- "close-large": closeLarge,
- "navbar-toggle-icon": navbarToggleIcon,
- "overlay-icon": overlayIcon,
- "pagination-next": paginationNext,
- "pagination-previous": paginationPrevious,
- "search-icon": searchIcon,
- "search-large": searchLarge,
- "search-navbar": searchNavbar,
- "slidenav-next": slidenavNext,
- "slidenav-next-large": slidenavNextLarge,
- "slidenav-previous": slidenavPrevious,
- "slidenav-previous-large": slidenavPreviousLarge
- };
- UIkit.component("icon", UIkit.components.svg.extend({
- attrs: [ "icon", "ratio" ],
- mixins: [ Class ],
- name: "icon",
- args: "icon",
- props: [ "icon" ],
- defaults: {
- exclude: [ "id", "style", "class", "src", "icon" ]
- },
- init: function init() {
- addClass(this.$el, "uk-icon");
- if (isRtl) {
- this.icon = swap(swap(this.icon, "left", "right"), "previous", "next");
- }
- },
- methods: {
- getSvg: function getSvg() {
- var icon = getIcon(this.icon);
- if (!icon) {
- return Promise.reject("Icon not found.");
- }
- return Promise.resolve(icon);
- }
- }
- }));
- [ "marker", "navbar-toggle-icon", "overlay-icon", "pagination-previous", "pagination-next", "totop" ].forEach(function(name) {
- return registerComponent(name);
- });
- [ "slidenav-previous", "slidenav-next" ].forEach(function(name) {
- return registerComponent(name, {
- init: function init() {
- addClass(this.$el, "uk-slidenav");
- if (hasClass(this.$el, "uk-slidenav-large")) {
- this.icon += "-large";
- }
- }
- });
- });
- registerComponent("search-icon", {
- init: function init() {
- if (hasClass(this.$el, "uk-search-icon") && parents(this.$el, ".uk-search-large").length) {
- this.icon = "search-large";
- } else if (parents(this.$el, ".uk-search-navbar").length) {
- this.icon = "search-navbar";
- }
- }
- });
- registerComponent("close", {
- init: function init() {
- this.icon = "close-" + (hasClass(this.$el, "uk-close-large") ? "large" : "icon");
- }
- });
- registerComponent("spinner", {
- connected: function connected() {
- var this$1 = this;
- this.svg.then(function(svg) {
- return this$1.ratio !== 1 && css($("circle", svg), "stroke-width", 1 / this$1.ratio);
- }, noop);
- }
- });
- UIkit.icon.add = function(added) {
- Object.keys(added).forEach(function(name) {
- icons[name] = added[name];
- delete parsed[name];
- });
- if (UIkit._initialized) {
- apply(document.body, function(el) {
- var icon = UIkit.getComponent(el, "icon");
- if (icon) {
- icon.$reset();
- }
- });
- }
- };
- function registerComponent(name, mixin$$1) {
- UIkit.component(name, UIkit.components.icon.extend({
- name: name,
- mixins: mixin$$1 ? [ mixin$$1 ] : [],
- defaults: {
- icon: name
- }
- }));
- }
- function getIcon(icon) {
- if (!icons[icon]) {
- return null;
- }
- if (!parsed[icon]) {
- parsed[icon] = $(icons[icon].trim());
- }
- return parsed[icon];
- }
- }
- function Leader(UIkit) {
- UIkit.component("leader", {
- mixins: [ Class ],
- props: {
- fill: String,
- media: "media"
- },
- defaults: {
- fill: "",
- media: false,
- clsWrapper: "uk-leader-fill",
- clsHide: "uk-leader-hide",
- attrFill: "data-fill"
- },
- computed: {
- fill: function fill(ref) {
- var fill = ref.fill;
- return fill || getCssVar("leader-fill");
- }
- },
- connected: function connected() {
- var assign;
- assign = wrapInner(this.$el, '
'), this.wrapper = assign[0];
- },
- disconnected: function disconnected() {
- unwrap(this.wrapper.childNodes);
- },
- update: [ {
- read: function read(ref) {
- var changed = ref.changed;
- var width = ref.width;
- var prev = width;
- width = Math.floor(this.$el.offsetWidth / 2);
- return {
- width: width,
- changed: changed || prev !== width,
- hide: this.media && !window.matchMedia(this.media).matches
- };
- },
- write: function write(data) {
- toggleClass(this.wrapper, this.clsHide, data.hide);
- if (data.changed) {
- data.changed = false;
- attr(this.wrapper, this.attrFill, new Array(data.width).join(this.fill));
- }
- },
- events: [ "load", "resize" ]
- } ]
- });
- }
- function Margin(UIkit) {
- UIkit.component("margin", {
- props: {
- margin: String,
- firstColumn: Boolean
- },
- defaults: {
- margin: "uk-margin-small-top",
- firstColumn: "uk-first-column"
- },
- update: {
- read: function read(data) {
- var items = this.$el.children;
- if (!items.length || !isVisible(this.$el)) {
- return data.rows = false;
- }
- data.stacks = true;
- var rows = [ [] ];
- for (var i = 0; i < items.length; i++) {
- var el = items[i];
- var dim = el.getBoundingClientRect();
- if (!dim.height) {
- continue;
- }
- for (var j = rows.length - 1; j >= 0; j--) {
- var row = rows[j];
- if (!row[0]) {
- row.push(el);
- break;
- }
- var leftDim = row[0].getBoundingClientRect();
- if (dim.top >= Math.floor(leftDim.bottom)) {
- rows.push([ el ]);
- break;
- }
- if (Math.floor(dim.bottom) > leftDim.top) {
- data.stacks = false;
- if (dim.left < leftDim.left && !isRtl) {
- row.unshift(el);
- break;
- }
- row.push(el);
- break;
- }
- if (j === 0) {
- rows.unshift([ el ]);
- break;
- }
- }
- }
- data.rows = rows;
- },
- write: function write(ref) {
- var this$1 = this;
- var rows = ref.rows;
- rows.forEach(function(row, i) {
- return row.forEach(function(el, j) {
- toggleClass(el, this$1.margin, i !== 0);
- toggleClass(el, this$1.firstColumn, j === 0);
- });
- });
- },
- events: [ "load", "resize" ]
- }
- });
- }
- function Modal$1(UIkit) {
- UIkit.component("modal", {
- mixins: [ Modal ],
- defaults: {
- clsPage: "uk-modal-page",
- selPanel: ".uk-modal-dialog",
- selClose: ".uk-modal-close, .uk-modal-close-default, .uk-modal-close-outside, .uk-modal-close-full"
- },
- events: [ {
- name: "show",
- self: true,
- handler: function handler() {
- if (hasClass(this.panel, "uk-margin-auto-vertical")) {
- addClass(this.$el, "uk-flex");
- } else {
- css(this.$el, "display", "block");
- }
- height(this.$el);
- }
- }, {
- name: "hidden",
- self: true,
- handler: function handler() {
- css(this.$el, "display", "");
- removeClass(this.$el, "uk-flex");
- }
- } ]
- });
- UIkit.component("overflow-auto", {
- mixins: [ Class ],
- computed: {
- modal: function modal(_, $el) {
- return closest($el, ".uk-modal");
- },
- panel: function panel(_, $el) {
- return closest($el, ".uk-modal-dialog");
- }
- },
- connected: function connected() {
- css(this.$el, "minHeight", 150);
- },
- update: {
- write: function write() {
- if (!this.panel || !this.modal) {
- return;
- }
- var current = css(this.$el, "maxHeight");
- css(css(this.$el, "maxHeight", 150), "maxHeight", Math.max(150, 150 + height(this.modal) - this.panel.offsetHeight));
- if (current !== css(this.$el, "maxHeight")) {
- trigger(this.$el, "resize");
- }
- },
- events: [ "load", "resize" ]
- }
- });
- UIkit.modal.dialog = function(content, options) {
- var dialog = UIkit.modal(' ", options);
- dialog.show();
- on(dialog.$el, "hidden", function(ref) {
- var target = ref.target;
- var currentTarget = ref.currentTarget;
- if (target === currentTarget) {
- dialog.$destroy(true);
- }
- });
- return dialog;
- };
- UIkit.modal.alert = function(message, options) {
- options = assign({
- bgClose: false,
- escClose: false,
- labels: UIkit.modal.labels
- }, options);
- return new Promise(function(resolve) {
- return on(UIkit.modal.dialog(' ' + (isString(message) ? message : html(message)) + '
", options).$el, "hide", resolve);
- });
- };
- UIkit.modal.confirm = function(message, options) {
- options = assign({
- bgClose: false,
- escClose: true,
- labels: UIkit.modal.labels
- }, options);
- return new Promise(function(resolve, reject) {
- var confirm = UIkit.modal.dialog(' ' + (isString(message) ? message : html(message)) + '
", options);
- var resolved = false;
- on(confirm.$el, "submit", "form", function(e) {
- e.preventDefault();
- resolve();
- resolved = true;
- confirm.hide();
- });
- on(confirm.$el, "hide", function() {
- if (!resolved) {
- reject();
- }
- });
- });
- };
- UIkit.modal.prompt = function(message, value, options) {
- options = assign({
- bgClose: false,
- escClose: true,
- labels: UIkit.modal.labels
- }, options);
- return new Promise(function(resolve) {
- var prompt = UIkit.modal.dialog(' ' + (isString(message) ? message : html(message)) + '
", options), input = $("input", prompt.$el);
- input.value = value;
- var resolved = false;
- on(prompt.$el, "submit", "form", function(e) {
- e.preventDefault();
- resolve(input.value);
- resolved = true;
- prompt.hide();
- });
- on(prompt.$el, "hide", function() {
- if (!resolved) {
- resolve(null);
- }
- });
- });
- };
- UIkit.modal.labels = {
- ok: "Ok",
- cancel: "Cancel"
- };
- }
- function Nav(UIkit) {
- UIkit.component("nav", UIkit.components.accordion.extend({
- name: "nav",
- defaults: {
- targets: "> .uk-parent",
- toggle: "> a",
- content: "> ul"
- }
- }));
- }
- function Navbar(UIkit) {
- UIkit.component("navbar", {
- mixins: [ Class ],
- props: {
- dropdown: String,
- mode: "list",
- align: String,
- offset: Number,
- boundary: Boolean,
- boundaryAlign: Boolean,
- clsDrop: String,
- delayShow: Number,
- delayHide: Number,
- dropbar: Boolean,
- dropbarMode: String,
- dropbarAnchor: "query",
- duration: Number
- },
- defaults: {
- dropdown: ".uk-navbar-nav > li",
- align: !isRtl ? "left" : "right",
- clsDrop: "uk-navbar-dropdown",
- mode: undefined,
- offset: undefined,
- delayShow: undefined,
- delayHide: undefined,
- boundaryAlign: undefined,
- flip: "x",
- boundary: true,
- dropbar: false,
- dropbarMode: "slide",
- dropbarAnchor: false,
- duration: 200
- },
- computed: {
- boundary: function boundary(ref, $el) {
- var boundary = ref.boundary;
- var boundaryAlign = ref.boundaryAlign;
- return boundary === true || boundaryAlign ? $el : boundary;
- },
- pos: function pos(ref) {
- var align = ref.align;
- return "bottom-" + align;
- }
- },
- beforeConnect: function beforeConnect() {
- var ref = this.$props;
- var dropbar = ref.dropbar;
- this.dropbar = dropbar && (isString(dropbar) && query(dropbar, this.$el) || $("
"));
- if (this.dropbar) {
- addClass(this.dropbar, "uk-navbar-dropbar");
- if (this.dropbarMode === "slide") {
- addClass(this.dropbar, "uk-navbar-dropbar-slide");
- }
- }
- },
- disconnected: function disconnected() {
- this.dropbar && remove(this.dropbar);
- },
- update: function update() {
- UIkit.drop($$(this.dropdown + " ." + this.clsDrop, this.$el).filter(function(el) {
- return !UIkit.getComponent(el, "drop") && !UIkit.getComponent(el, "dropdown");
- }), assign({}, this.$props, {
- boundary: this.boundary,
- pos: this.pos,
- offset: this.dropbar || this.offset
- }));
- },
- events: [ {
- name: "mouseover",
- delegate: function delegate() {
- return this.dropdown;
- },
- handler: function handler(ref) {
- var current = ref.current;
- var active = this.getActive();
- if (active && active.toggle && !within(active.toggle.$el, current) && !active.tracker.movesTo(active.$el)) {
- active.hide(false);
- }
- }
- }, {
- name: "mouseleave",
- el: function el() {
- return this.dropbar;
- },
- handler: function handler() {
- var active = this.getActive();
- if (active && !matches(this.dropbar, ":hover")) {
- active.hide();
- }
- }
- }, {
- name: "beforeshow",
- capture: true,
- filter: function filter() {
- return this.dropbar;
- },
- handler: function handler() {
- if (!this.dropbar.parentNode) {
- after(this.dropbarAnchor || this.$el, this.dropbar);
- }
- }
- }, {
- name: "show",
- capture: true,
- filter: function filter() {
- return this.dropbar;
- },
- handler: function handler(_, drop) {
- var $el = drop.$el;
- var dir = drop.dir;
- this.clsDrop && addClass($el, this.clsDrop + "-dropbar");
- if (dir === "bottom") {
- this.transitionTo($el.offsetHeight + toFloat(css($el, "marginTop")) + toFloat(css($el, "marginBottom")), $el);
- }
- }
- }, {
- name: "beforehide",
- filter: function filter() {
- return this.dropbar;
- },
- handler: function handler(e, ref) {
- var $el = ref.$el;
- var active = this.getActive();
- if (matches(this.dropbar, ":hover") && active && active.$el === $el) {
- e.preventDefault();
- }
- }
- }, {
- name: "hide",
- filter: function filter() {
- return this.dropbar;
- },
- handler: function handler(_, ref) {
- var $el = ref.$el;
- var active = this.getActive();
- if (!active || active && active.$el === $el) {
- this.transitionTo(0);
- }
- }
- } ],
- methods: {
- getActive: function getActive() {
- var active = UIkit.drop.getActive();
- return active && includes(active.mode, "hover") && within(active.toggle.$el, this.$el) && active;
- },
- transitionTo: function transitionTo(newHeight, el) {
- var ref = this;
- var dropbar = ref.dropbar;
- var oldHeight = isVisible(dropbar) ? height(dropbar) : 0;
- el = oldHeight < newHeight && el;
- css(el, {
- height: oldHeight,
- overflow: "hidden"
- });
- height(dropbar, oldHeight);
- Transition.cancel([ el, dropbar ]);
- return Transition.start([ el, dropbar ], {
- height: newHeight
- }, this.duration).catch(noop).then(function() {
- return css(el, {
- height: "",
- overflow: ""
- });
- });
- }
- }
- });
- }
- var scroll;
- function Offcanvas(UIkit) {
- UIkit.component("offcanvas", {
- mixins: [ Modal ],
- args: "mode",
- props: {
- content: String,
- mode: String,
- flip: Boolean,
- overlay: Boolean
- },
- defaults: {
- content: ".uk-offcanvas-content",
- mode: "slide",
- flip: false,
- overlay: false,
- clsPage: "uk-offcanvas-page",
- clsContainer: "uk-offcanvas-container",
- selPanel: ".uk-offcanvas-bar",
- clsFlip: "uk-offcanvas-flip",
- clsContent: "uk-offcanvas-content",
- clsContentAnimation: "uk-offcanvas-content-animation",
- clsSidebarAnimation: "uk-offcanvas-bar-animation",
- clsMode: "uk-offcanvas",
- clsOverlay: "uk-offcanvas-overlay",
- selClose: ".uk-offcanvas-close"
- },
- computed: {
- content: function content(ref) {
- var content = ref.content;
- return $(content) || document.body;
- },
- clsFlip: function clsFlip(ref) {
- var flip = ref.flip;
- var clsFlip = ref.clsFlip;
- return flip ? clsFlip : "";
- },
- clsOverlay: function clsOverlay(ref) {
- var overlay = ref.overlay;
- var clsOverlay = ref.clsOverlay;
- return overlay ? clsOverlay : "";
- },
- clsMode: function clsMode(ref) {
- var mode = ref.mode;
- var clsMode = ref.clsMode;
- return clsMode + "-" + mode;
- },
- clsSidebarAnimation: function clsSidebarAnimation(ref) {
- var mode = ref.mode;
- var clsSidebarAnimation = ref.clsSidebarAnimation;
- return mode === "none" || mode === "reveal" ? "" : clsSidebarAnimation;
- },
- clsContentAnimation: function clsContentAnimation(ref) {
- var mode = ref.mode;
- var clsContentAnimation = ref.clsContentAnimation;
- return mode !== "push" && mode !== "reveal" ? "" : clsContentAnimation;
- },
- transitionElement: function transitionElement(ref) {
- var mode = ref.mode;
- return mode === "reveal" ? this.panel.parentNode : this.panel;
- }
- },
- update: {
- write: function write() {
- if (this.getActive() === this) {
- if (this.overlay || this.clsContentAnimation) {
- width(this.content, width(window) - this.scrollbarWidth);
- }
- if (this.overlay) {
- height(this.content, height(window));
- if (scroll) {
- this.content.scrollTop = scroll.y;
- }
- }
- }
- },
- events: [ "resize" ]
- },
- events: [ {
- name: "click",
- delegate: function delegate() {
- return 'a[href^="#"]';
- },
- handler: function handler(ref) {
- var current = ref.current;
- if (current.hash && $(current.hash, this.content)) {
- scroll = null;
- this.hide();
- }
- }
- }, {
- name: "beforescroll",
- filter: function filter() {
- return this.overlay;
- },
- handler: function handler(e, scroll, target) {
- if (scroll && target && this.isToggled() && $(target, this.content)) {
- once(this.$el, "hidden", function() {
- return scroll.scrollTo(target);
- });
- e.preventDefault();
- }
- }
- }, {
- name: "show",
- self: true,
- handler: function handler() {
- scroll = scroll || {
- x: window.pageXOffset,
- y: window.pageYOffset
- };
- if (this.mode === "reveal" && !hasClass(this.panel, this.clsMode)) {
- wrapAll(this.panel, "");
- addClass(this.panel.parentNode, this.clsMode);
- }
- css(document.documentElement, "overflowY", (!this.clsContentAnimation || this.flip) && this.scrollbarWidth && this.overlay ? "scroll" : "");
- addClass(document.body, this.clsContainer, this.clsFlip, this.clsOverlay);
- height(document.body);
- addClass(this.content, this.clsContentAnimation);
- addClass(this.panel, this.clsSidebarAnimation, this.mode !== "reveal" ? this.clsMode : "");
- addClass(this.$el, this.clsOverlay);
- css(this.$el, "display", "block");
- height(this.$el);
- }
- }, {
- name: "hide",
- self: true,
- handler: function handler() {
- removeClass(this.content, this.clsContentAnimation);
- var active = this.getActive();
- if (this.mode === "none" || active && active !== this && active !== this.prev) {
- trigger(this.panel, "transitionend");
- }
- }
- }, {
- name: "hidden",
- self: true,
- handler: function handler() {
- if (this.mode === "reveal") {
- unwrap(this.panel);
- }
- if (!this.overlay) {
- scroll = {
- x: window.pageXOffset,
- y: window.pageYOffset
- };
- } else if (!scroll) {
- var ref = this.content;
- var x = ref.scrollLeft;
- var y = ref.scrollTop;
- scroll = {
- x: x,
- y: y
- };
- }
- removeClass(this.panel, this.clsSidebarAnimation, this.clsMode);
- removeClass(this.$el, this.clsOverlay);
- css(this.$el, "display", "");
- removeClass(document.body, this.clsContainer, this.clsFlip, this.clsOverlay);
- document.body.scrollTop = scroll.y;
- css(document.documentElement, "overflowY", "");
- width(this.content, "");
- height(this.content, "");
- window.scrollTo(scroll.x, scroll.y);
- scroll = null;
- }
- }, {
- name: "swipeLeft swipeRight",
- handler: function handler(e) {
- if (this.isToggled() && isTouch(e) && (e.type === "swipeLeft" && !this.flip || e.type === "swipeRight" && this.flip)) {
- this.hide();
- }
- }
- } ]
- });
- }
- function Responsive(UIkit) {
- UIkit.component("responsive", {
- props: [ "width", "height" ],
- init: function init() {
- addClass(this.$el, "uk-responsive-width");
- },
- update: {
- read: function read() {
- return isVisible(this.$el) && this.width && this.height ? {
- width: width(this.$el.parentNode),
- height: this.height
- } : false;
- },
- write: function write(dim) {
- height(this.$el, Dimensions.contain({
- height: this.height,
- width: this.width
- }, dim).height);
- },
- events: [ "load", "resize" ]
- }
- });
- }
- function Scroll(UIkit) {
- UIkit.component("scroll", {
- props: {
- duration: Number,
- offset: Number
- },
- defaults: {
- duration: 1e3,
- offset: 0
- },
- methods: {
- scrollTo: function scrollTo(el) {
- var this$1 = this;
- el = el && $(el) || document.body;
- var docHeight = height(document);
- var winHeight = height(window);
- var target = offset(el).top - this.offset;
- if (target + winHeight > docHeight) {
- target = docHeight - winHeight;
- }
- if (!trigger(this.$el, "beforescroll", [ this, el ])) {
- return;
- }
- var start = Date.now();
- var startY = window.pageYOffset;
- var step = function() {
- var currentY = startY + (target - startY) * ease(clamp((Date.now() - start) / this$1.duration));
- window.scrollTo(window.pageXOffset, currentY);
- if (currentY !== target) {
- requestAnimationFrame(step);
- } else {
- trigger(this$1.$el, "scrolled", [ this$1, el ]);
- }
- };
- step();
- }
- },
- events: {
- click: function click(e) {
- if (e.defaultPrevented) {
- return;
- }
- e.preventDefault();
- this.scrollTo(escape(this.$el.hash).substr(1));
- }
- }
- });
- function ease(k) {
- return .5 * (1 - Math.cos(Math.PI * k));
- }
- }
- function Scrollspy(UIkit) {
- UIkit.component("scrollspy", {
- args: "cls",
- props: {
- cls: "list",
- target: String,
- hidden: Boolean,
- offsetTop: Number,
- offsetLeft: Number,
- repeat: Boolean,
- delay: Number
- },
- defaults: {
- cls: [],
- target: false,
- hidden: true,
- offsetTop: 0,
- offsetLeft: 0,
- repeat: false,
- delay: 0,
- inViewClass: "uk-scrollspy-inview"
- },
- computed: {
- elements: function elements(ref, $el) {
- var target = ref.target;
- return target ? $$(target, $el) : [ $el ];
- }
- },
- update: [ {
- write: function write() {
- if (this.hidden) {
- css(filter(this.elements, ":not(." + this.inViewClass + ")"), "visibility", "hidden");
- }
- }
- }, {
- read: function read(els) {
- var this$1 = this;
- if (!UIkit._initialized) {
- if (document.readyState === "complete") {
- requestAnimationFrame(function() {
- return this$1.$emit();
- });
- }
- return false;
- }
- this.elements.forEach(function(el, i) {
- var elData = els[i];
- if (!elData || elData.el !== el) {
- var cls = data(el, "uk-scrollspy-class");
- elData = {
- el: el,
- toggles: cls && cls.split(",") || this$1.cls
- };
- }
- elData.show = isInView(el, this$1.offsetTop, this$1.offsetLeft);
- els[i] = elData;
- });
- },
- write: function write(els) {
- var this$1 = this;
- var index = this.elements.length === 1 ? 1 : 0;
- this.elements.forEach(function(el, i) {
- var elData = els[i];
- var cls = elData.toggles[i] || elData.toggles[0];
- if (elData.show && !elData.inview && !elData.timer) {
- var show = function() {
- css(el, "visibility", "");
- addClass(el, this$1.inViewClass);
- toggleClass(el, cls);
- trigger(el, "inview");
- UIkit.update(el);
- elData.inview = true;
- delete elData.timer;
- };
- if (this$1.delay && index) {
- elData.timer = setTimeout(show, this$1.delay * index);
- } else {
- show();
- }
- index++;
- } else if (!elData.show && elData.inview && this$1.repeat) {
- if (elData.timer) {
- clearTimeout(elData.timer);
- delete elData.timer;
- }
- css(el, "visibility", this$1.hidden ? "hidden" : "");
- removeClass(el, this$1.inViewClass);
- toggleClass(el, cls);
- trigger(el, "outview");
- UIkit.update(el);
- elData.inview = false;
- }
- });
- },
- events: [ "scroll", "load", "resize" ]
- } ]
- });
- }
- function ScrollspyNav(UIkit) {
- UIkit.component("scrollspy-nav", {
- props: {
- cls: String,
- closest: String,
- scroll: Boolean,
- overflow: Boolean,
- offset: Number
- },
- defaults: {
- cls: "uk-active",
- closest: false,
- scroll: false,
- overflow: true,
- offset: 0
- },
- computed: {
- links: function links(_, $el) {
- return $$('a[href^="#"]', $el).filter(function(el) {
- return el.hash;
- });
- },
- elements: function elements() {
- return this.closest ? closest(this.links, this.closest) : this.links;
- },
- targets: function targets() {
- return $$(this.links.map(function(el) {
- return el.hash;
- }).join(","));
- }
- },
- update: [ {
- read: function read() {
- if (this.scroll) {
- UIkit.scroll(this.links, {
- offset: this.offset || 0
- });
- }
- }
- }, {
- read: function read(data) {
- var this$1 = this;
- var scroll = window.pageYOffset + this.offset + 1;
- var max = height(document) - height(window) + this.offset;
- data.active = false;
- this.targets.every(function(el, i) {
- var ref = offset(el);
- var top = ref.top;
- var last = i + 1 === this$1.targets.length;
- if (!this$1.overflow && (i === 0 && top > scroll || last && top + el.offsetTop < scroll)) {
- return false;
- }
- if (!last && offset(this$1.targets[i + 1]).top <= scroll) {
- return true;
- }
- if (scroll >= max) {
- for (var j = this$1.targets.length - 1; j > i; j--) {
- if (isInView(this$1.targets[j])) {
- el = this$1.targets[j];
- break;
- }
- }
- }
- return !(data.active = $(filter(this$1.links, '[href="#' + el.id + '"]')));
- });
- },
- write: function write(ref) {
- var active = ref.active;
- this.links.forEach(function(el) {
- return el.blur();
- });
- removeClass(this.elements, this.cls);
- if (active) {
- trigger(this.$el, "active", [ active, addClass(this.closest ? closest(active, this.closest) : active, this.cls) ]);
- }
- },
- events: [ "scroll", "load", "resize" ]
- } ]
- });
- }
- function Sticky(UIkit) {
- UIkit.component("sticky", {
- mixins: [ Class ],
- attrs: true,
- props: {
- top: null,
- bottom: Boolean,
- offset: Number,
- animation: String,
- clsActive: String,
- clsInactive: String,
- clsFixed: String,
- clsBelow: String,
- selTarget: String,
- widthElement: "query",
- showOnUp: Boolean,
- media: "media",
- target: Number
- },
- defaults: {
- top: 0,
- bottom: false,
- offset: 0,
- animation: "",
- clsActive: "uk-active",
- clsInactive: "",
- clsFixed: "uk-sticky-fixed",
- clsBelow: "uk-sticky-below",
- selTarget: "",
- widthElement: false,
- showOnUp: false,
- media: false,
- target: false
- },
- computed: {
- selTarget: function selTarget(ref, $el) {
- var selTarget = ref.selTarget;
- return selTarget && $(selTarget, $el) || $el;
- }
- },
- connected: function connected() {
- this.placeholder = $('
');
- this.widthElement = this.$props.widthElement || this.placeholder;
- if (!this.isActive) {
- this.hide();
- }
- },
- disconnected: function disconnected() {
- if (this.isActive) {
- this.isActive = false;
- this.hide();
- removeClass(this.selTarget, this.clsInactive);
- }
- remove(this.placeholder);
- this.placeholder = null;
- this.widthElement = null;
- },
- ready: function ready() {
- var this$1 = this;
- if (!(this.target && location.hash && window.pageYOffset > 0)) {
- return;
- }
- var target = $(location.hash);
- if (target) {
- fastdom.read(function() {
- var ref = offset(target);
- var top = ref.top;
- var elTop = offset(this$1.$el).top;
- var elHeight = this$1.$el.offsetHeight;
- if (elTop + elHeight >= top && elTop <= top + target.offsetHeight) {
- window.scrollTo(0, top - elHeight - this$1.target - this$1.offset);
- }
- });
- }
- },
- events: [ {
- name: "active",
- self: true,
- handler: function handler() {
- replaceClass(this.selTarget, this.clsInactive, this.clsActive);
- }
- }, {
- name: "inactive",
- self: true,
- handler: function handler() {
- replaceClass(this.selTarget, this.clsActive, this.clsInactive);
- }
- } ],
- update: [ {
- write: function write() {
- var ref = this;
- var placeholder = ref.placeholder;
- var outerHeight = (this.isActive ? placeholder : this.$el).offsetHeight;
- css(placeholder, assign({
- height: css(this.$el, "position") !== "absolute" ? outerHeight : ""
- }, css(this.$el, [ "marginTop", "marginBottom", "marginLeft", "marginRight" ])));
- if (!within(placeholder, document)) {
- after(this.$el, placeholder);
- attr(placeholder, "hidden", "");
- }
- attr(this.widthElement, "hidden", null);
- this.width = this.widthElement.offsetWidth;
- attr(this.widthElement, "hidden", this.isActive ? null : "");
- this.topOffset = offset(this.isActive ? placeholder : this.$el).top;
- this.bottomOffset = this.topOffset + outerHeight;
- var bottom = parseProp("bottom", this);
- this.top = Math.max(toFloat(parseProp("top", this)), this.topOffset) - this.offset;
- this.bottom = bottom && bottom - outerHeight;
- this.inactive = this.media && !window.matchMedia(this.media).matches;
- if (this.isActive) {
- this.update();
- }
- },
- events: [ "load", "resize" ]
- }, {
- read: function read(_, ref) {
- var scrollY = ref.scrollY;
- if (scrollY === void 0) scrollY = window.pageYOffset;
- return {
- scroll: this.scroll = scrollY,
- visible: isVisible(this.$el)
- };
- },
- write: function write(ref, ref$1) {
- var this$1 = this;
- var visible = ref.visible;
- var scroll = ref.scroll;
- if (ref$1 === void 0) ref$1 = {};
- var dir = ref$1.dir;
- if (scroll < 0 || !visible || this.disabled || this.showOnUp && !dir) {
- return;
- }
- if (this.inactive || scroll < this.top || this.showOnUp && (scroll <= this.top || dir === "down" || dir === "up" && !this.isActive && scroll <= this.bottomOffset)) {
- if (!this.isActive) {
- return;
- }
- this.isActive = false;
- if (this.animation && scroll > this.topOffset) {
- Animation.cancel(this.$el);
- Animation.out(this.$el, this.animation).then(function() {
- return this$1.hide();
- }, noop);
- } else {
- this.hide();
- }
- } else if (this.isActive) {
- this.update();
- } else if (this.animation) {
- Animation.cancel(this.$el);
- this.show();
- Animation.in(this.$el, this.animation).catch(noop);
- } else {
- this.show();
- }
- },
- events: [ "scroll" ]
- } ],
- methods: {
- show: function show() {
- this.isActive = true;
- this.update();
- attr(this.placeholder, "hidden", null);
- },
- hide: function hide() {
- if (!this.isActive || hasClass(this.selTarget, this.clsActive)) {
- trigger(this.$el, "inactive");
- }
- removeClass(this.$el, this.clsFixed, this.clsBelow);
- css(this.$el, {
- position: "",
- top: "",
- width: ""
- });
- attr(this.placeholder, "hidden", "");
- },
- update: function update() {
- var active = this.top !== 0 || this.scroll > this.top;
- var top = Math.max(0, this.offset);
- if (this.bottom && this.scroll > this.bottom - this.offset) {
- top = this.bottom - this.scroll;
- }
- css(this.$el, {
- position: "fixed",
- top: top + "px",
- width: this.width
- });
- if (hasClass(this.selTarget, this.clsActive)) {
- if (!active) {
- trigger(this.$el, "inactive");
- }
- } else if (active) {
- trigger(this.$el, "active");
- }
- toggleClass(this.$el, this.clsBelow, this.scroll > this.bottomOffset);
- addClass(this.$el, this.clsFixed);
- }
- }
- });
- function parseProp(prop, ref) {
- var $props = ref.$props;
- var $el = ref.$el;
- var propOffset = ref[prop + "Offset"];
- var value = $props[prop];
- if (!value) {
- return;
- }
- if (isNumeric(value)) {
- return propOffset + toFloat(value);
- } else if (isString(value) && value.match(/^-?\d+vh$/)) {
- return height(window) * toFloat(value) / 100;
- } else {
- var el = value === true ? $el.parentNode : query(value, $el);
- if (el) {
- return offset(el).top + el.offsetHeight;
- }
- }
- }
- }
- var svgs = {};
- function Svg(UIkit) {
- UIkit.component("svg", {
- attrs: true,
- props: {
- id: String,
- icon: String,
- src: String,
- style: String,
- width: Number,
- height: Number,
- ratio: Number,
- class: String
- },
- defaults: {
- ratio: 1,
- id: false,
- exclude: [ "src" ],
- class: ""
- },
- init: function init() {
- this.class += " uk-svg";
- },
- connected: function connected() {
- var this$1 = this;
- if (!this.icon && includes(this.src, "#")) {
- var parts = this.src.split("#");
- if (parts.length > 1) {
- var assign;
- assign = parts, this.src = assign[0], this.icon = assign[1];
- }
- }
- this.svg = this.getSvg().then(function(svg) {
- var el;
- if (isString(svg)) {
- if (this$1.icon && includes(svg, "
/g;
- var symbols = {};
- function parseSymbols(svg, icon) {
- if (!symbols[svg]) {
- symbols[svg] = {};
- var match;
- while (match = symbolRe.exec(svg)) {
- symbols[svg][match[3]] = '";
- }
- }
- return symbols[svg][icon];
- }
- }
- function Switcher(UIkit) {
- UIkit.component("switcher", {
- mixins: [ Togglable ],
- args: "connect",
- props: {
- connect: String,
- toggle: String,
- active: Number,
- swiping: Boolean
- },
- defaults: {
- connect: "~.uk-switcher",
- toggle: "> *",
- active: 0,
- swiping: true,
- cls: "uk-active",
- clsContainer: "uk-switcher",
- attrItem: "uk-switcher-item",
- queued: true
- },
- computed: {
- connects: function connects(ref, $el) {
- var connect = ref.connect;
- return queryAll(connect, $el);
- },
- toggles: function toggles(ref, $el) {
- var toggle = ref.toggle;
- return $$(toggle, $el);
- }
- },
- events: [ {
- name: "click",
- delegate: function delegate() {
- return this.toggle + ":not(.uk-disabled)";
- },
- handler: function handler(e) {
- e.preventDefault();
- this.show(e.current);
- }
- }, {
- name: "click",
- el: function el() {
- return this.connects;
- },
- delegate: function delegate() {
- return "[" + this.attrItem + "],[data-" + this.attrItem + "]";
- },
- handler: function handler(e) {
- e.preventDefault();
- this.show(data(e.current, this.attrItem));
- }
- }, {
- name: "swipeRight swipeLeft",
- filter: function filter() {
- return this.swiping;
- },
- el: function el() {
- return this.connects;
- },
- handler: function handler(e) {
- if (!isTouch(e)) {
- return;
- }
- e.preventDefault();
- if (!window.getSelection().toString()) {
- this.show(e.type === "swipeLeft" ? "next" : "previous");
- }
- }
- } ],
- update: function update() {
- var this$1 = this;
- this.connects.forEach(function(list) {
- return this$1.updateAria(list.children);
- });
- this.show(filter(this.toggles, "." + this.cls)[0] || this.toggles[this.active] || this.toggles[0]);
- },
- methods: {
- show: function show(item) {
- var this$1 = this;
- var ref = this.toggles;
- var length = ref.length;
- var prev = !!this.connects.length && index(filter(this.connects[0].children, "." + this.cls)[0]);
- var hasPrev = prev >= 0;
- var dir = item === "previous" ? -1 : 1;
- var toggle, next = getIndex(item, this.toggles, prev);
- for (var i = 0; i < length; i++, next = (next + dir + length) % length) {
- if (!matches(this$1.toggles[next], ".uk-disabled, [disabled]")) {
- toggle = this$1.toggles[next];
- break;
- }
- }
- if (!toggle || prev >= 0 && hasClass(toggle, this.cls) || prev === next) {
- return;
- }
- removeClass(this.toggles, this.cls);
- attr(this.toggles, "aria-expanded", false);
- addClass(toggle, this.cls);
- attr(toggle, "aria-expanded", true);
- this.connects.forEach(function(list) {
- if (!hasPrev) {
- this$1.toggleNow(list.children[next]);
- } else {
- this$1.toggleElement([ list.children[prev], list.children[next] ]);
- }
- });
- }
- }
- });
- }
- function Tab(UIkit) {
- UIkit.component("tab", UIkit.components.switcher.extend({
- mixins: [ Class ],
- name: "tab",
- props: {
- media: "media"
- },
- defaults: {
- media: 960,
- attrItem: "uk-tab-item"
- },
- init: function init() {
- var cls = hasClass(this.$el, "uk-tab-left") ? "uk-tab-left" : hasClass(this.$el, "uk-tab-right") ? "uk-tab-right" : false;
- if (cls) {
- UIkit.toggle(this.$el, {
- cls: cls,
- mode: "media",
- media: this.media
- });
- }
- }
- }));
- }
- function Toggle(UIkit) {
- UIkit.component("toggle", {
- mixins: [ UIkit.mixin.togglable ],
- args: "target",
- props: {
- href: String,
- target: null,
- mode: "list",
- media: "media"
- },
- defaults: {
- href: false,
- target: false,
- mode: "click",
- queued: true,
- media: false
- },
- computed: {
- target: function target(ref, $el) {
- var href = ref.href;
- var target = ref.target;
- target = queryAll(target || href, $el);
- return target.length && target || [ $el ];
- }
- },
- events: [ {
- name: pointerEnter + " " + pointerLeave,
- filter: function filter() {
- return includes(this.mode, "hover");
- },
- handler: function handler(e) {
- if (!isTouch(e)) {
- this.toggle("toggle" + (e.type === pointerEnter ? "show" : "hide"));
- }
- }
- }, {
- name: "click",
- filter: function filter() {
- return includes(this.mode, "click") || hasTouch;
- },
- handler: function handler(e) {
- if (!isTouch(e) && !includes(this.mode, "click")) {
- return;
- }
- var link;
- if (closest(e.target, 'a[href="#"], button') || (link = closest(e.target, "a[href]")) && (this.cls || !isVisible(this.target) || link.hash && matches(this.target, link.hash))) {
- once(document, "click", function(e) {
- return e.preventDefault();
- });
- }
- this.toggle();
- }
- } ],
- update: {
- write: function write() {
- if (!includes(this.mode, "media") || !this.media) {
- return;
- }
- var toggled = this.isToggled(this.target);
- if (window.matchMedia(this.media).matches ? !toggled : toggled) {
- this.toggle();
- }
- },
- events: [ "load", "resize" ]
- },
- methods: {
- toggle: function toggle(type) {
- if (trigger(this.target, type || "toggle", [ this ])) {
- this.toggleElement(this.target);
- }
- }
- }
- });
- }
- function Video(UIkit) {
- UIkit.component("video", {
- args: "autoplay",
- props: {
- automute: Boolean,
- autoplay: Boolean
- },
- defaults: {
- automute: false,
- autoplay: true
- },
- computed: {
- inView: function inView(ref) {
- var autoplay = ref.autoplay;
- return autoplay === "inview";
- }
- },
- connected: function connected() {
- if (this.inView && !hasAttr(this.$el, "preload")) {
- this.$el.preload = "none";
- }
- },
- ready: function ready() {
- this.player = new Player(this.$el);
- if (this.automute) {
- this.player.mute();
- }
- },
- update: [ {
- read: function read(_, ref) {
- var type = ref.type;
- return !this.player || (type === "scroll" || type === "resize") && !this.inView ? false : {
- visible: isVisible(this.$el) && css(this.$el, "visibility") !== "hidden",
- inView: this.inView && isInView(this.$el)
- };
- },
- write: function write(ref) {
- var visible = ref.visible;
- var inView = ref.inView;
- if (!visible || this.inView && !inView) {
- this.player.pause();
- } else if (this.autoplay === true || this.inView && inView) {
- this.player.play();
- }
- },
- events: [ "load", "resize", "scroll" ]
- } ]
- });
- }
- function core(UIkit) {
- UIkit.use(Toggle);
- UIkit.use(Accordion);
- UIkit.use(Alert);
- UIkit.use(Video);
- UIkit.use(Cover);
- UIkit.use(Drop);
- UIkit.use(Dropdown);
- UIkit.use(FormCustom);
- UIkit.use(HeightMatch);
- UIkit.use(HeightViewport);
- UIkit.use(Margin);
- UIkit.use(Gif);
- UIkit.use(Grid);
- UIkit.use(Leader);
- UIkit.use(Modal$1);
- UIkit.use(Nav);
- UIkit.use(Navbar);
- UIkit.use(Offcanvas);
- UIkit.use(Responsive);
- UIkit.use(Scroll);
- UIkit.use(Scrollspy);
- UIkit.use(ScrollspyNav);
- UIkit.use(Sticky);
- UIkit.use(Svg);
- UIkit.use(Icon);
- UIkit.use(Switcher);
- UIkit.use(Tab);
- UIkit.use(Core);
- }
- UIkit$2.version = "3.0.0-beta.42";
- mixin(UIkit$2);
- core(UIkit$2);
- function plugin(UIkit) {
- if (plugin.installed) {
- return;
- }
- var ref = UIkit.util;
- var $ = ref.$;
- var empty = ref.empty;
- var html = ref.html;
- UIkit.component("countdown", {
- mixins: [ UIkit.mixin.class ],
- attrs: true,
- props: {
- date: String,
- clsWrapper: String
- },
- defaults: {
- date: "",
- clsWrapper: ".uk-countdown-%unit%"
- },
- computed: {
- date: function date(ref) {
- var date = ref.date;
- return Date.parse(date);
- },
- days: function days(ref, $el) {
- var clsWrapper = ref.clsWrapper;
- return $(clsWrapper.replace("%unit%", "days"), $el);
- },
- hours: function hours(ref, $el) {
- var clsWrapper = ref.clsWrapper;
- return $(clsWrapper.replace("%unit%", "hours"), $el);
- },
- minutes: function minutes(ref, $el) {
- var clsWrapper = ref.clsWrapper;
- return $(clsWrapper.replace("%unit%", "minutes"), $el);
- },
- seconds: function seconds(ref, $el) {
- var clsWrapper = ref.clsWrapper;
- return $(clsWrapper.replace("%unit%", "seconds"), $el);
- },
- units: function units() {
- var this$1 = this;
- return [ "days", "hours", "minutes", "seconds" ].filter(function(unit) {
- return this$1[unit];
- });
- }
- },
- connected: function connected() {
- this.start();
- },
- disconnected: function disconnected() {
- var this$1 = this;
- this.stop();
- this.units.forEach(function(unit) {
- return empty(this$1[unit]);
- });
- },
- events: [ {
- name: "visibilitychange",
- el: document,
- handler: function handler() {
- if (document.hidden) {
- this.stop();
- } else {
- this.start();
- }
- }
- } ],
- update: {
- write: function write() {
- var this$1 = this;
- var timespan = getTimeSpan(this.date);
- if (timespan.total <= 0) {
- this.stop();
- timespan.days = timespan.hours = timespan.minutes = timespan.seconds = 0;
- }
- this.units.forEach(function(unit) {
- var digits = String(Math.floor(timespan[unit]));
- digits = digits.length < 2 ? "0" + digits : digits;
- var el = this$1[unit];
- if (el.textContent !== digits) {
- digits = digits.split("");
- if (digits.length !== el.children.length) {
- html(el, digits.map(function() {
- return " ";
- }).join(""));
- }
- digits.forEach(function(digit, i) {
- return el.children[i].textContent = digit;
- });
- }
- });
- }
- },
- methods: {
- start: function start() {
- var this$1 = this;
- this.stop();
- if (this.date && this.units.length) {
- this.$emit();
- this.timer = setInterval(function() {
- return this$1.$emit();
- }, 1e3);
- }
- },
- stop: function stop() {
- if (this.timer) {
- clearInterval(this.timer);
- this.timer = null;
- }
- }
- }
- });
- function getTimeSpan(date) {
- var total = date - Date.now();
- return {
- total: total,
- seconds: total / 1e3 % 60,
- minutes: total / 1e3 / 60 % 60,
- hours: total / 1e3 / 60 / 60 % 24,
- days: total / 1e3 / 60 / 60 / 24
- };
- }
- }
- function plugin$1(UIkit) {
- if (plugin$1.installed) {
- return;
- }
- var ref = UIkit.util;
- var addClass = ref.addClass;
- var css = ref.css;
- var scrolledOver = ref.scrolledOver;
- var sortBy = ref.sortBy;
- var toFloat = ref.toFloat;
- UIkit.component("grid-parallax", UIkit.components.grid.extend({
- props: {
- target: String,
- translate: Number
- },
- defaults: {
- target: false,
- translate: 150
- },
- computed: {
- translate: function translate(ref) {
- var translate = ref.translate;
- return Math.abs(translate);
- }
- },
- init: function init() {
- addClass(this.$el, "uk-grid");
- },
- disconnected: function disconnected() {
- this.reset();
- css(this.$el, "marginBottom", "");
- },
- update: [ {
- read: function read(ref) {
- var rows = ref.rows;
- return {
- columns: rows && rows[0] && rows[0].length || 0,
- rows: rows && rows.map(function(elements) {
- return sortBy(elements, "offsetLeft");
- })
- };
- },
- write: function write(ref) {
- var columns = ref.columns;
- css(this.$el, "marginBottom", columns > 1 ? this.translate + toFloat(css(css(this.$el, "marginBottom", ""), "marginBottom")) : "");
- },
- events: [ "load", "resize" ]
- }, {
- read: function read() {
- return {
- scrolled: scrolledOver(this.$el) * this.translate
- };
- },
- write: function write(ref) {
- var rows = ref.rows;
- var columns = ref.columns;
- var scrolled = ref.scrolled;
- if (!rows || columns === 1 || !scrolled) {
- return this.reset();
- }
- rows.forEach(function(row) {
- return row.forEach(function(el, i) {
- return css(el, "transform", "translateY(" + (i % 2 ? scrolled : scrolled / 8) + "px)");
- });
- });
- },
- events: [ "scroll", "load", "resize" ]
- } ],
- methods: {
- reset: function reset() {
- css(this.$el.children, "transform", "");
- }
- }
- }));
- UIkit.components.gridParallax.options.update.unshift({
- read: function read() {
- this.reset();
- },
- events: [ "load", "resize" ]
- });
- }
- function AnimationsPlugin(UIkit) {
- var ref = UIkit.util;
- var css = ref.css;
- var Animations = {
- slide: {
- show: function show(dir) {
- return [ {
- transform: translate(dir * -100)
- }, {
- transform: translate()
- } ];
- },
- percent: function percent(current) {
- return Animations.translated(current);
- },
- translate: function translate$1(percent, dir) {
- return [ {
- transform: translate(dir * -100 * percent)
- }, {
- transform: translate(dir * 100 * (1 - percent))
- } ];
- }
- },
- translated: function translated(el) {
- return Math.abs(css(el, "transform").split(",")[4] / el.offsetWidth) || 0;
- }
- };
- return Animations;
- }
- function translate(value, unit) {
- if (value === void 0) value = 0;
- if (unit === void 0) unit = "%";
- return "translateX(" + value + (value ? unit : "") + ")";
- }
- function scale3d(value) {
- return "scale3d(" + value + ", " + value + ", 1)";
- }
- function TransitionerPlugin(UIkit) {
- var ref = UIkit.util;
- var createEvent = ref.createEvent;
- var clamp = ref.clamp;
- var css = ref.css;
- var Deferred = ref.Deferred;
- var noop = ref.noop;
- var Promise = ref.Promise;
- var Transition = ref.Transition;
- var trigger = ref.trigger;
- function Transitioner(prev, next, dir, ref) {
- var animation = ref.animation;
- var easing = ref.easing;
- var percent = animation.percent;
- var translate = animation.translate;
- var show = animation.show;
- if (show === void 0) show = noop;
- var props = show(dir);
- var deferred = new Deferred();
- return {
- dir: dir,
- show: function show(duration, percent, linear) {
- var this$1 = this;
- if (percent === void 0) percent = 0;
- var timing = linear ? "linear" : easing;
- duration -= Math.round(duration * clamp(percent, -1, 1));
- this.translate(percent);
- triggerUpdate(next, "itemin", {
- percent: percent,
- duration: duration,
- timing: timing,
- dir: dir
- });
- triggerUpdate(prev, "itemout", {
- percent: 1 - percent,
- duration: duration,
- timing: timing,
- dir: dir
- });
- Promise.all([ Transition.start(next, props[1], duration, timing), Transition.start(prev, props[0], duration, timing) ]).then(function() {
- this$1.reset();
- deferred.resolve();
- }, noop);
- return deferred.promise;
- },
- stop: function stop() {
- return Transition.stop([ next, prev ]);
- },
- cancel: function cancel() {
- Transition.cancel([ next, prev ]);
- },
- reset: function reset() {
- for (var prop in props[0]) {
- css([ next, prev ], prop, "");
- }
- },
- forward: function forward(duration, percent) {
- if (percent === void 0) percent = this.percent();
- Transition.cancel([ next, prev ]);
- return this.show(duration, percent, true);
- },
- translate: function translate$1(percent) {
- this.reset();
- var props = translate(percent, dir);
- css(next, props[1]);
- css(prev, props[0]);
- triggerUpdate(next, "itemtranslatein", {
- percent: percent,
- dir: dir
- });
- triggerUpdate(prev, "itemtranslateout", {
- percent: 1 - percent,
- dir: dir
- });
- },
- percent: function percent$1() {
- return percent(prev || next, next, dir);
- },
- getDistance: function getDistance() {
- return prev.offsetWidth;
- }
- };
- }
- function triggerUpdate(el, type, data) {
- trigger(el, createEvent(type, false, false, data));
- }
- return Transitioner;
- }
- function AutoplayMixin(UIkit) {
- var ref = UIkit.util;
- var pointerDown = ref.pointerDown;
- return {
- props: {
- autoplay: Boolean,
- autoplayInterval: Number,
- pauseOnHover: Boolean
- },
- defaults: {
- autoplay: false,
- autoplayInterval: 7e3,
- pauseOnHover: true
- },
- connected: function connected() {
- this.startAutoplay();
- },
- disconnected: function disconnected() {
- this.stopAutoplay();
- },
- events: [ {
- name: "visibilitychange",
- el: document,
- handler: function handler() {
- if (document.hidden) {
- this.stopAutoplay();
- } else {
- this.startAutoplay();
- }
- }
- }, {
- name: pointerDown,
- handler: "stopAutoplay"
- }, {
- name: "mouseenter",
- filter: function filter() {
- return this.autoplay;
- },
- handler: function handler() {
- this.isHovering = true;
- }
- }, {
- name: "mouseleave",
- filter: function filter() {
- return this.autoplay;
- },
- handler: function handler() {
- this.isHovering = false;
- }
- } ],
- methods: {
- startAutoplay: function startAutoplay() {
- var this$1 = this;
- this.stopAutoplay();
- if (this.autoplay) {
- this.interval = setInterval(function() {
- return !(this$1.isHovering && this$1.pauseOnHover) && !this$1.stack.length && this$1.show("next");
- }, this.autoplayInterval);
- }
- },
- stopAutoplay: function stopAutoplay() {
- if (this.interval) {
- clearInterval(this.interval);
- }
- }
- }
- };
- }
- function DragMixin(UIkit) {
- var ref = UIkit.util;
- var getPos = ref.getPos;
- var includes = ref.includes;
- var isRtl = ref.isRtl;
- var isTouch = ref.isTouch;
- var off = ref.off;
- var on = ref.on;
- var pointerDown = ref.pointerDown;
- var pointerMove = ref.pointerMove;
- var pointerUp = ref.pointerUp;
- var preventClick = ref.preventClick;
- var trigger = ref.trigger;
- return {
- defaults: {
- threshold: 10,
- preventCatch: false
- },
- init: function init() {
- var this$1 = this;
- [ "start", "move", "end" ].forEach(function(key) {
- var fn = this$1[key];
- this$1[key] = function(e) {
- var pos = getPos(e).x * (isRtl ? -1 : 1);
- this$1.prevPos = pos !== this$1.pos ? this$1.pos : this$1.prevPos;
- this$1.pos = pos;
- fn(e);
- };
- });
- },
- events: [ {
- name: pointerDown,
- delegate: function delegate() {
- return this.slidesSelector;
- },
- handler: function handler(e) {
- if (!isTouch(e) && hasTextNodesOnly(e.target) || e.button > 0 || this.length < 2 || this.preventCatch) {
- return;
- }
- this.start(e);
- }
- }, {
- name: "dragstart",
- handler: function handler(e) {
- e.preventDefault();
- }
- } ],
- methods: {
- start: function start() {
- this.drag = this.pos;
- if (this._transitioner) {
- this.percent = this._transitioner.percent();
- this.drag += this._transitioner.getDistance() * this.percent * this.dir;
- this._transitioner.translate(this.percent);
- this._transitioner.cancel();
- this.dragging = true;
- this.stack = [];
- } else {
- this.prevIndex = this.index;
- }
- this.unbindMove = on(document, pointerMove, this.move, {
- capture: true,
- passive: false
- });
- on(window, "scroll", this.unbindMove);
- on(document, pointerUp, this.end, true);
- },
- move: function move(e) {
- var this$1 = this;
- var distance = this.pos - this.drag;
- if (distance === 0 || this.prevPos === this.pos || !this.dragging && Math.abs(distance) < this.threshold) {
- return;
- }
- e.cancelable && e.preventDefault();
- this.dragging = true;
- this.dir = distance < 0 ? 1 : -1;
- var ref = this;
- var slides = ref.slides;
- var ref$1 = this;
- var prevIndex = ref$1.prevIndex;
- var dis = Math.abs(distance);
- var nextIndex = this.getIndex(prevIndex + this.dir, prevIndex);
- var width = this._getDistance(prevIndex, nextIndex) || slides[prevIndex].offsetWidth;
- while (nextIndex !== prevIndex && dis > width) {
- this$1.drag -= width * this$1.dir;
- prevIndex = nextIndex;
- dis -= width;
- nextIndex = this$1.getIndex(prevIndex + this$1.dir, prevIndex);
- width = this$1._getDistance(prevIndex, nextIndex) || slides[prevIndex].offsetWidth;
- }
- this.percent = dis / width;
- var prev = slides[prevIndex];
- var next = slides[nextIndex];
- var changed = this.index !== nextIndex;
- var edge = prevIndex === nextIndex;
- var itemShown;
- [ this.index, this.prevIndex ].filter(function(i) {
- return !includes([ nextIndex, prevIndex ], i);
- }).forEach(function(i) {
- trigger(slides[i], "itemhidden", [ this$1 ]);
- if (edge) {
- itemShown = true;
- this$1.prevIndex = prevIndex;
- }
- });
- if (this.index === prevIndex && this.prevIndex !== prevIndex || itemShown) {
- trigger(slides[this.index], "itemshown", [ this ]);
- }
- if (changed) {
- this.prevIndex = prevIndex;
- this.index = nextIndex;
- !edge && trigger(prev, "beforeitemhide", [ this ]);
- trigger(next, "beforeitemshow", [ this ]);
- }
- this._transitioner = this._translate(Math.abs(this.percent), prev, !edge && next);
- if (changed) {
- !edge && trigger(prev, "itemhide", [ this ]);
- trigger(next, "itemshow", [ this ]);
- }
- },
- end: function end() {
- off(window, "scroll", this.unbindMove);
- this.unbindMove();
- off(document, pointerUp, this.end, true);
- if (this.dragging) {
- this.dragging = null;
- if (this.index === this.prevIndex) {
- this.percent = 1 - this.percent;
- this.dir *= -1;
- this._show(false, this.index, true);
- this._transitioner = null;
- } else {
- var dirChange = (isRtl ? this.dir * (isRtl ? 1 : -1) : this.dir) < 0 === this.prevPos > this.pos;
- this.index = dirChange ? this.index : this.prevIndex;
- if (dirChange) {
- this.percent = 1 - this.percent;
- }
- this.show(this.dir > 0 && !dirChange || this.dir < 0 && dirChange ? "next" : "previous", true);
- }
- preventClick();
- }
- this.drag = this.percent = null;
- }
- }
- };
- function hasTextNodesOnly(el) {
- return !el.children.length && el.childNodes.length;
- }
- }
- function NavMixin(UIkit) {
- var ref = UIkit.util;
- var $ = ref.$;
- var $$ = ref.$$;
- var data = ref.data;
- var html = ref.html;
- var toggleClass = ref.toggleClass;
- var toNumber = ref.toNumber;
- return {
- defaults: {
- selNav: false
- },
- computed: {
- nav: function nav(ref, $el) {
- var selNav = ref.selNav;
- return $(selNav, $el);
- },
- navItemSelector: function navItemSelector(ref) {
- var attrItem = ref.attrItem;
- return "[" + attrItem + "],[data-" + attrItem + "]";
- },
- navItems: function navItems(_, $el) {
- return $$(this.navItemSelector, $el);
- }
- },
- update: [ {
- write: function write() {
- var this$1 = this;
- if (this.nav && this.length !== this.nav.children.length) {
- html(this.nav, this.slides.map(function(_, i) {
- return " ';
- }).join(""));
- }
- toggleClass($$(this.navItemSelector, this.$el).concat(this.nav), "uk-hidden", !this.maxIndex);
- this.updateNav();
- },
- events: [ "load", "resize" ]
- } ],
- events: [ {
- name: "click",
- delegate: function delegate() {
- return this.navItemSelector;
- },
- handler: function handler(e) {
- e.preventDefault();
- e.current.blur();
- this.show(data(e.current, this.attrItem));
- }
- }, {
- name: "itemshow",
- handler: "updateNav"
- } ],
- methods: {
- updateNav: function updateNav() {
- var this$1 = this;
- var i = this.getValidIndex();
- this.navItems.forEach(function(el) {
- var cmd = data(el, this$1.attrItem);
- toggleClass(el, this$1.clsActive, toNumber(cmd) === i);
- toggleClass(el, "uk-invisible", this$1.finite && (cmd === "previous" && i === 0 || cmd === "next" && i >= this$1.maxIndex));
- });
- }
- }
- };
- }
- function plugin$5(UIkit) {
- if (plugin$5.installed) {
- return;
- }
- var ref = UIkit.util;
- var $ = ref.$;
- var assign = ref.assign;
- var clamp = ref.clamp;
- var fastdom = ref.fastdom;
- var getIndex = ref.getIndex;
- var hasClass = ref.hasClass;
- var isNumber = ref.isNumber;
- var isRtl = ref.isRtl;
- var Promise = ref.Promise;
- var toNodes = ref.toNodes;
- var trigger = ref.trigger;
- UIkit.mixin.slider = {
- attrs: true,
- mixins: [ AutoplayMixin(UIkit), DragMixin(UIkit), NavMixin(UIkit) ],
- props: {
- clsActivated: Boolean,
- easing: String,
- index: Number,
- finite: Boolean,
- velocity: Number
- },
- defaults: {
- easing: "ease",
- finite: false,
- velocity: 1,
- index: 0,
- stack: [],
- percent: 0,
- clsActive: "uk-active",
- clsActivated: false,
- Transitioner: false,
- transitionOptions: {}
- },
- computed: {
- duration: function duration(ref, $el) {
- var velocity = ref.velocity;
- return speedUp($el.offsetWidth / velocity);
- },
- length: function length() {
- return this.slides.length;
- },
- list: function list(ref, $el) {
- var selList = ref.selList;
- return $(selList, $el);
- },
- maxIndex: function maxIndex() {
- return this.length - 1;
- },
- slidesSelector: function slidesSelector(ref) {
- var selList = ref.selList;
- return selList + " > *";
- },
- slides: function slides() {
- return toNodes(this.list.children);
- }
- },
- methods: {
- show: function show(index, force) {
- var this$1 = this;
- if (force === void 0) force = false;
- if (this.dragging || !this.length) {
- return;
- }
- var ref = this;
- var stack = ref.stack;
- var queueIndex = force ? 0 : stack.length;
- var reset = function() {
- stack.splice(queueIndex, 1);
- if (stack.length) {
- this$1.show(stack.shift(), true);
- }
- };
- stack[force ? "unshift" : "push"](index);
- if (!force && stack.length > 1) {
- if (stack.length === 2) {
- this._transitioner.forward(Math.min(this.duration, 200));
- }
- return;
- }
- var prevIndex = this.index;
- var prev = hasClass(this.slides, this.clsActive) && this.slides[prevIndex];
- var nextIndex = this.getIndex(index, this.index);
- var next = this.slides[nextIndex];
- if (prev === next) {
- reset();
- return;
- }
- this.dir = getDirection(index, prevIndex);
- this.prevIndex = prevIndex;
- this.index = nextIndex;
- prev && trigger(prev, "beforeitemhide", [ this ]);
- if (!trigger(next, "beforeitemshow", [ this, prev ])) {
- this.index = this.prevIndex;
- reset();
- return;
- }
- var promise = this._show(prev, next, force).then(function() {
- prev && trigger(prev, "itemhidden", [ this$1 ]);
- trigger(next, "itemshown", [ this$1 ]);
- return new Promise(function(resolve) {
- fastdom.write(function() {
- stack.shift();
- if (stack.length) {
- this$1.show(stack.shift(), true);
- } else {
- this$1._transitioner = null;
- }
- resolve();
- });
- });
- });
- prev && trigger(prev, "itemhide", [ this ]);
- trigger(next, "itemshow", [ this ]);
- return promise;
- },
- getIndex: function getIndex$1(index, prev) {
- if (index === void 0) index = this.index;
- if (prev === void 0) prev = this.index;
- return clamp(getIndex(index, this.slides, prev, this.finite), 0, this.maxIndex);
- },
- getValidIndex: function getValidIndex(index, prevIndex) {
- if (index === void 0) index = this.index;
- if (prevIndex === void 0) prevIndex = this.prevIndex;
- return this.getIndex(index, prevIndex);
- },
- _show: function _show(prev, next, force) {
- this._transitioner = this._getTransitioner(prev, next, this.dir, assign({
- easing: force ? next.offsetWidth < 600 ? "cubic-bezier(0.25, 0.46, 0.45, 0.94)" : "cubic-bezier(0.165, 0.84, 0.44, 1)" : this.easing
- }, this.transitionOptions));
- if (!force && !prev) {
- this._transitioner.translate(1);
- return Promise.resolve();
- }
- var ref = this.stack;
- var length = ref.length;
- return this._transitioner[length > 1 ? "forward" : "show"](length > 1 ? Math.min(this.duration, 75 + 75 / (length - 1)) : this.duration, this.percent);
- },
- _getDistance: function _getDistance(prev, next) {
- return new this._getTransitioner(prev, prev !== next && next).getDistance();
- },
- _translate: function _translate(percent, prev, next) {
- if (prev === void 0) prev = this.prevIndex;
- if (next === void 0) next = this.index;
- var transitioner = this._getTransitioner(prev !== next ? prev : false, next);
- transitioner.translate(percent);
- return transitioner;
- },
- _getTransitioner: function _getTransitioner(prev, next, dir, options) {
- if (prev === void 0) prev = this.prevIndex;
- if (next === void 0) next = this.index;
- if (dir === void 0) dir = this.dir || 1;
- if (options === void 0) options = this.transitionOptions;
- return new this.Transitioner(isNumber(prev) ? this.slides[prev] : prev, isNumber(next) ? this.slides[next] : next, dir * (isRtl ? -1 : 1), options);
- }
- }
- };
- function getDirection(index, prevIndex) {
- return index === "next" ? 1 : index === "previous" ? -1 : index < prevIndex ? -1 : 1;
- }
- }
- function speedUp(x) {
- return .5 * x + 300;
- }
- function plugin$4(UIkit) {
- if (plugin$4.installed) {
- return;
- }
- UIkit.use(plugin$5);
- var mixin = UIkit.mixin;
- var UIkit_util = UIkit.util;
- var addClass = UIkit_util.addClass;
- var assign = UIkit_util.assign;
- var fastdom = UIkit_util.fastdom;
- var isNumber = UIkit_util.isNumber;
- var removeClass = UIkit_util.removeClass;
- var Animations = AnimationsPlugin(UIkit);
- var Transitioner = TransitionerPlugin(UIkit);
- UIkit.mixin.slideshow = {
- mixins: [ mixin.slider ],
- props: {
- animation: String
- },
- defaults: {
- animation: "slide",
- clsActivated: "uk-transition-active",
- Animations: Animations,
- Transitioner: Transitioner
- },
- computed: {
- animation: function animation(ref) {
- var animation = ref.animation;
- var Animations = ref.Animations;
- return assign(animation in Animations ? Animations[animation] : Animations.slide, {
- name: animation
- });
- },
- transitionOptions: function transitionOptions() {
- return {
- animation: this.animation
- };
- }
- },
- events: {
- "itemshow itemhide itemshown itemhidden": function itemshowitemhideitemshownitemhidden(ref) {
- var target = ref.target;
- UIkit.update(target);
- },
- itemshow: function itemshow() {
- isNumber(this.prevIndex) && fastdom.flush();
- },
- beforeitemshow: function beforeitemshow(ref) {
- var target = ref.target;
- addClass(target, this.clsActive);
- },
- itemshown: function itemshown(ref) {
- var target = ref.target;
- addClass(target, this.clsActivated);
- },
- itemhidden: function itemhidden(ref) {
- var target = ref.target;
- removeClass(target, this.clsActive, this.clsActivated);
- }
- }
- };
- }
- function AnimationsPlugin$1(UIkit) {
- var mixin = UIkit.mixin;
- var UIkit_util = UIkit.util;
- var assign = UIkit_util.assign;
- var css = UIkit_util.css;
- return assign({}, mixin.slideshow.defaults.Animations, {
- fade: {
- show: function show() {
- return [ {
- opacity: 0
- }, {
- opacity: 1
- } ];
- },
- percent: function percent(current) {
- return 1 - css(current, "opacity");
- },
- translate: function translate$$1(percent) {
- return [ {
- opacity: 1 - percent
- }, {
- opacity: percent
- } ];
- }
- },
- scale: {
- show: function show() {
- return [ {
- opacity: 0,
- transform: scale3d(1 - .2)
- }, {
- opacity: 1,
- transform: scale3d(1)
- } ];
- },
- percent: function percent(current) {
- return 1 - css(current, "opacity");
- },
- translate: function translate$$1(percent) {
- return [ {
- opacity: 1 - percent,
- transform: scale3d(1 - .2 * percent)
- }, {
- opacity: percent,
- transform: scale3d(1 - .2 + .2 * percent)
- } ];
- }
- }
- });
- }
- function plugin$3(UIkit) {
- if (plugin$3.installed) {
- return;
- }
- UIkit.use(plugin$4);
- var mixin = UIkit.mixin;
- var util = UIkit.util;
- var $ = util.$;
- var addClass = util.addClass;
- var ajax = util.ajax;
- var append = util.append;
- var assign = util.assign;
- var attr = util.attr;
- var css = util.css;
- var getImage = util.getImage;
- var html = util.html;
- var index = util.index;
- var on = util.on;
- var pointerDown = util.pointerDown;
- var pointerMove = util.pointerMove;
- var removeClass = util.removeClass;
- var Transition = util.Transition;
- var trigger = util.trigger;
- var Animations = AnimationsPlugin$1(UIkit);
- UIkit.component("lightbox-panel", {
- mixins: [ mixin.container, mixin.modal, mixin.togglable, mixin.slideshow ],
- functional: true,
- props: {
- delayControls: Number,
- preload: Number,
- videoAutoplay: Boolean,
- template: String
- },
- defaults: {
- preload: 1,
- videoAutoplay: false,
- delayControls: 3e3,
- items: [],
- cls: "uk-open",
- clsPage: "uk-lightbox-page",
- selList: ".uk-lightbox-items",
- attrItem: "uk-lightbox-item",
- selClose: ".uk-close-large",
- pauseOnHover: false,
- velocity: 2,
- Animations: Animations,
- template: ''
- },
- created: function created() {
- var this$1 = this;
- this.$mount(append(this.container, this.template));
- this.caption = $(".uk-lightbox-caption", this.$el);
- this.items.forEach(function() {
- return append(this$1.list, " ");
- });
- },
- events: [ {
- name: pointerMove + " " + pointerDown + " keydown",
- handler: "showControls"
- }, {
- name: "click",
- self: true,
- delegate: function delegate() {
- return this.slidesSelector;
- },
- handler: function handler(e) {
- e.preventDefault();
- this.hide();
- }
- }, {
- name: "shown",
- self: true,
- handler: "showControls"
- }, {
- name: "hide",
- self: true,
- handler: function handler() {
- this.hideControls();
- removeClass(this.slides, this.clsActive);
- Transition.stop(this.slides);
- }
- }, {
- name: "keyup",
- el: document,
- handler: function handler(e) {
- if (!this.isToggled(this.$el)) {
- return;
- }
- switch (e.keyCode) {
- case 37:
- this.show("previous");
- break;
-
- case 39:
- this.show("next");
- break;
- }
- }
- }, {
- name: "beforeitemshow",
- handler: function handler(e) {
- if (this.isToggled()) {
- return;
- }
- this.preventCatch = true;
- e.preventDefault();
- this.toggleNow(this.$el, true);
- this.animation = Animations["scale"];
- removeClass(e.target, this.clsActive);
- this.stack.splice(1, 0, this.index);
- }
- }, {
- name: "itemshow",
- handler: function handler(ref) {
- var this$1 = this;
- var target = ref.target;
- var i = index(target);
- var ref$1 = this.getItem(i);
- var caption = ref$1.caption;
- css(this.caption, "display", caption ? "" : "none");
- html(this.caption, caption);
- for (var j = 0; j <= this.preload; j++) {
- this$1.loadItem(this$1.getIndex(i + j));
- this$1.loadItem(this$1.getIndex(i - j));
- }
- }
- }, {
- name: "itemshown",
- handler: function handler() {
- this.preventCatch = false;
- }
- }, {
- name: "itemload",
- handler: function handler(_, item) {
- var this$1 = this;
- var source = item.source;
- var type = item.type;
- var alt = item.alt;
- this.setItem(item, " ");
- if (!source) {
- return;
- }
- var matches;
- if (type === "image" || source.match(/\.(jp(e)?g|png|gif|svg)$/i)) {
- getImage(source).then(function(img) {
- return this$1.setItem(item, ' ');
- }, function() {
- return this$1.setError(item);
- });
- } else if (type === "video" || source.match(/\.(mp4|webm|ogv)$/i)) {
- var video = $(" ');
- attr(video, "src", source);
- on(video, "error", function() {
- return this$1.setError(item);
- });
- on(video, "loadedmetadata", function() {
- attr(video, {
- width: video.videoWidth,
- height: video.videoHeight
- });
- this$1.setItem(item, video);
- });
- } else if (type === "iframe") {
- this.setItem(item, '');
- } else if (matches = source.match(/\/\/.*?youtube(-nocookie)?\.[a-z]+\/watch\?v=([^&\s]+)/) || source.match(/()youtu\.be\/(.*)/)) {
- var id = matches[2];
- var setIframe = function(width, height) {
- if (width === void 0) width = 640;
- if (height === void 0) height = 450;
- return this$1.setItem(item, getIframe("//www.youtube" + (matches[1] || "") + ".com/embed/" + id, width, height, this$1.videoAutoplay));
- };
- getImage("//img.youtube.com/vi/" + id + "/maxresdefault.jpg").then(function(ref) {
- var width = ref.width;
- var height = ref.height;
- if (width === 120 && height === 90) {
- getImage("//img.youtube.com/vi/" + id + "/0.jpg").then(function(ref) {
- var width = ref.width;
- var height = ref.height;
- return setIframe(width, height);
- }, setIframe);
- } else {
- setIframe(width, height);
- }
- }, setIframe);
- } else if (matches = source.match(/(\/\/.*?)vimeo\.[a-z]+\/([0-9]+).*?/)) {
- ajax("//vimeo.com/api/oembed.json?maxwidth=1920&url=" + encodeURI(source), {
- responseType: "json"
- }).then(function(ref) {
- var ref_response = ref.response;
- var height = ref_response.height;
- var width = ref_response.width;
- return this$1.setItem(item, getIframe("//player.vimeo.com/video/" + matches[2], width, height, this$1.videoAutoplay));
- });
- }
- }
- } ],
- methods: {
- loadItem: function loadItem(index) {
- if (index === void 0) index = this.index;
- var item = this.getItem(index);
- if (item.content) {
- return;
- }
- trigger(this.$el, "itemload", [ item ]);
- },
- getItem: function getItem(index) {
- if (index === void 0) index = this.index;
- return this.items[index] || {};
- },
- setItem: function setItem(item, content) {
- assign(item, {
- content: content
- });
- var el = html(this.slides[this.items.indexOf(item)], content);
- trigger(this.$el, "itemloaded", [ this, el ]);
- UIkit.update(el);
- },
- setError: function setError(item) {
- this.setItem(item, ' ');
- },
- showControls: function showControls() {
- clearTimeout(this.controlsTimer);
- this.controlsTimer = setTimeout(this.hideControls, this.delayControls);
- addClass(this.$el, "uk-active", "uk-transition-active");
- },
- hideControls: function hideControls() {
- removeClass(this.$el, "uk-active", "uk-transition-active");
- }
- }
- });
- function getIframe(src, width, height, autoplay) {
- return '';
- }
- }
- function plugin$2(UIkit) {
- if (plugin$2.installed) {
- return;
- }
- UIkit.use(plugin$3);
- var util = UIkit.util;
- var $$ = util.$$;
- var assign = util.assign;
- var data = util.data;
- var index = util.index;
- var ref = UIkit.components.lightboxPanel;
- var options = ref.options;
- UIkit.component("lightbox", {
- attrs: true,
- props: assign({
- toggle: String
- }, options.props),
- defaults: assign({
- toggle: "a"
- }, Object.keys(options.props).reduce(function(defaults, key) {
- defaults[key] = options.defaults[key];
- return defaults;
- }, {})),
- computed: {
- toggles: function toggles(ref, $el) {
- var toggle = ref.toggle;
- return $$(toggle, $el);
- }
- },
- disconnected: function disconnected() {
- this._destroy();
- },
- events: [ {
- name: "click",
- delegate: function delegate() {
- return this.toggle + ":not(.uk-disabled)";
- },
- handler: function handler(e) {
- e.preventDefault();
- e.current.blur();
- this.show(index(this.toggles, e.current));
- }
- } ],
- update: function update(data) {
- data.toggles = data.toggles || this.toggles;
- if (this.panel && this.animation) {
- this.panel.$props.animation = this.animation;
- this.panel.$emit();
- }
- if (!this.panel || isEqualList(data.toggles, this.toggles)) {
- return;
- }
- data.toggles = this.toggles;
- this._destroy();
- this._init();
- },
- methods: {
- _init: function _init() {
- return this.panel = this.panel || UIkit.lightboxPanel(assign({}, this.$props, {
- items: this.toggles.reduce(function(items, el) {
- items.push([ "href", "caption", "type", "poster", "alt" ].reduce(function(obj, attr) {
- obj[attr === "href" ? "source" : attr] = data(el, attr);
- return obj;
- }, {}));
- return items;
- }, [])
- }));
- },
- _destroy: function _destroy() {
- if (this.panel) {
- this.panel.$destroy(true);
- this.panel = null;
- }
- },
- show: function show(index) {
- if (!this.panel) {
- this._init();
- }
- return this.panel.show(index);
- },
- hide: function hide() {
- return this.panel && this.panel.hide();
- }
- }
- });
- function isEqualList(listA, listB) {
- return listA.length === listB.length && listA.every(function(el, i) {
- return el === listB[i];
- });
- }
- }
- function plugin$6(UIkit) {
- var obj;
- if (plugin$6.installed) {
- return;
- }
- var ref = UIkit.util;
- var append = ref.append;
- var apply = ref.apply;
- var closest = ref.closest;
- var css = ref.css;
- var pointerEnter = ref.pointerEnter;
- var pointerLeave = ref.pointerLeave;
- var remove = ref.remove;
- var toFloat = ref.toFloat;
- var Transition = ref.Transition;
- var trigger = ref.trigger;
- var containers = {};
- UIkit.component("notification", {
- functional: true,
- args: [ "message", "status" ],
- defaults: {
- message: "",
- status: "",
- timeout: 5e3,
- group: null,
- pos: "top-center",
- clsClose: "uk-notification-close",
- clsMsg: "uk-notification-message"
- },
- created: function created() {
- if (!containers[this.pos]) {
- containers[this.pos] = append(UIkit.container, '
');
- }
- var container = css(containers[this.pos], "display", "block");
- this.$mount(append(container, '"));
- },
- ready: function ready() {
- var this$1 = this;
- var marginBottom = toFloat(css(this.$el, "marginBottom"));
- Transition.start(css(this.$el, {
- opacity: 0,
- marginTop: -this.$el.offsetHeight,
- marginBottom: 0
- }), {
- opacity: 1,
- marginTop: 0,
- marginBottom: marginBottom
- }).then(function() {
- if (this$1.timeout) {
- this$1.timer = setTimeout(this$1.close, this$1.timeout);
- }
- });
- },
- events: (obj = {
- click: function click(e) {
- if (closest(e.target, 'a[href="#"]')) {
- e.preventDefault();
- }
- this.close();
- }
- }, obj[pointerEnter] = function() {
- if (this.timer) {
- clearTimeout(this.timer);
- }
- }, obj[pointerLeave] = function() {
- if (this.timeout) {
- this.timer = setTimeout(this.close, this.timeout);
- }
- }, obj),
- methods: {
- close: function close(immediate) {
- var this$1 = this;
- var removeFn = function() {
- trigger(this$1.$el, "close", [ this$1 ]);
- remove(this$1.$el);
- if (!containers[this$1.pos].children.length) {
- css(containers[this$1.pos], "display", "none");
- }
- };
- if (this.timer) {
- clearTimeout(this.timer);
- }
- if (immediate) {
- removeFn();
- } else {
- Transition.start(this.$el, {
- opacity: 0,
- marginTop: -this.$el.offsetHeight,
- marginBottom: 0
- }).then(removeFn);
- }
- }
- }
- });
- UIkit.notification.closeAll = function(group, immediate) {
- apply(document.body, function(el) {
- var notification = UIkit.getComponent(el, "notification");
- if (notification && (!group || group === notification.group)) {
- notification.close(immediate);
- }
- });
- };
- }
- function plugin$8(UIkit) {
- if (plugin$8.installed) {
- return;
- }
- var mixin = UIkit.mixin;
- var util = UIkit.util;
- var css = util.css;
- var Dimensions = util.Dimensions;
- var each = util.each;
- var getImage = util.getImage;
- var includes = util.includes;
- var isNumber = util.isNumber;
- var isUndefined = util.isUndefined;
- var toFloat = util.toFloat;
- var props = [ "x", "y", "bgx", "bgy", "rotate", "scale", "color", "backgroundColor", "borderColor", "opacity", "blur", "hue", "grayscale", "invert", "saturate", "sepia", "fopacity" ];
- mixin.parallax = {
- props: props.reduce(function(props, prop) {
- props[prop] = "list";
- return props;
- }, {
- media: "media"
- }),
- defaults: props.reduce(function(defaults, prop) {
- defaults[prop] = undefined;
- return defaults;
- }, {
- media: false
- }),
- computed: {
- props: function props$1(properties, $el) {
- var this$1 = this;
- return props.reduce(function(props, prop) {
- if (isUndefined(properties[prop])) {
- return props;
- }
- var isColor = prop.match(/color/i);
- var isCssProp = isColor || prop === "opacity";
- var pos, bgPos, diff;
- var steps = properties[prop].slice(0);
- if (isCssProp) {
- css($el, prop, "");
- }
- if (steps.length < 2) {
- steps.unshift((prop === "scale" ? 1 : isCssProp ? css($el, prop) : 0) || 0);
- }
- var unit = includes(steps.join(""), "%") ? "%" : "px";
- if (isColor) {
- var ref = $el.style;
- var color = ref.color;
- steps = steps.map(function(step) {
- return parseColor($el, step);
- });
- $el.style.color = color;
- } else {
- steps = steps.map(toFloat);
- }
- if (prop.match(/^bg/)) {
- css($el, "background-position-" + prop[2], "");
- bgPos = css($el, "backgroundPosition").split(" ")[prop[2] === "x" ? 0 : 1];
- if (this$1.covers) {
- var min = Math.min.apply(Math, steps);
- var max = Math.max.apply(Math, steps);
- var down = steps.indexOf(min) < steps.indexOf(max);
- diff = max - min;
- steps = steps.map(function(step) {
- return step - (down ? min : max);
- });
- pos = (down ? -diff : 0) + "px";
- } else {
- pos = bgPos;
- }
- }
- props[prop] = {
- steps: steps,
- unit: unit,
- pos: pos,
- bgPos: bgPos,
- diff: diff
- };
- return props;
- }, {});
- },
- bgProps: function bgProps() {
- var this$1 = this;
- return [ "bgx", "bgy" ].filter(function(bg) {
- return bg in this$1.props;
- });
- },
- covers: function covers$1(_, $el) {
- return covers($el);
- }
- },
- disconnected: function disconnected() {
- delete this._image;
- },
- update: [ {
- read: function read(data) {
- var this$1 = this;
- data.active = !this.media || window.matchMedia(this.media).matches;
- if (data.image) {
- data.image.dimEl = {
- width: this.$el.offsetWidth,
- height: this.$el.offsetHeight
- };
- }
- if ("image" in data || !this.covers || !this.bgProps.length) {
- return;
- }
- var src = css(this.$el, "backgroundImage").replace(/^none|url\(["']?(.+?)["']?\)$/, "$1");
- if (!src) {
- return;
- }
- data.image = false;
- getImage(src).then(function(img) {
- data.image = {
- width: img.naturalWidth,
- height: img.naturalHeight
- };
- this$1.$emit();
- });
- },
- write: function write(ref) {
- var this$1 = this;
- var image = ref.image;
- var active = ref.active;
- if (!image) {
- return;
- }
- if (!active) {
- css(this.$el, {
- backgroundSize: "",
- backgroundRepeat: ""
- });
- return;
- }
- var dimEl = image.dimEl;
- var dim = Dimensions.cover(image, dimEl);
- this.bgProps.forEach(function(prop) {
- var ref = this$1.props[prop];
- var diff = ref.diff;
- var bgPos = ref.bgPos;
- var steps = ref.steps;
- var attr = prop === "bgy" ? "height" : "width";
- var span = dim[attr] - dimEl[attr];
- if (!bgPos.match(/%$|0px/)) {
- return;
- }
- if (span < diff) {
- dimEl[attr] = dim[attr] + diff - span;
- } else if (span > diff) {
- var bgPosFloat = parseFloat(bgPos);
- if (bgPosFloat) {
- this$1.props[prop].steps = steps.map(function(step) {
- return step - (span - diff) / (100 / bgPosFloat);
- });
- }
- }
- dim = Dimensions.cover(image, dimEl);
- });
- css(this.$el, {
- backgroundSize: dim.width + "px " + dim.height + "px",
- backgroundRepeat: "no-repeat"
- });
- },
- events: [ "load", "resize" ]
- } ],
- methods: {
- reset: function reset() {
- var this$1 = this;
- each(this.getCss(0), function(_, prop) {
- return css(this$1.$el, prop, "");
- });
- },
- getCss: function getCss(percent) {
- var ref = this;
- var props = ref.props;
- var translated = false;
- return Object.keys(props).reduce(function(css, prop) {
- var ref = props[prop];
- var steps = ref.steps;
- var unit = ref.unit;
- var pos = ref.pos;
- var value = getValue(steps, percent);
- switch (prop) {
- case "x":
- case "y":
- if (translated) {
- break;
- }
- var ref$1 = [ "x", "y" ].map(function(dir) {
- return prop === dir ? value + unit : props[dir] ? getValue(props[dir].steps, percent) + props[dir].unit : 0;
- });
- var x = ref$1[0];
- var y = ref$1[1];
- translated = css.transform += " translate3d(" + x + ", " + y + ", 0)";
- break;
-
- case "rotate":
- css.transform += " rotate(" + value + "deg)";
- break;
-
- case "scale":
- css.transform += " scale(" + value + ")";
- break;
-
- case "bgy":
- case "bgx":
- css["background-position-" + prop[2]] = "calc(" + pos + " + " + (value + unit) + ")";
- break;
-
- case "color":
- case "backgroundColor":
- case "borderColor":
- var ref$2 = getStep(steps, percent);
- var start = ref$2[0];
- var end = ref$2[1];
- var p = ref$2[2];
- css[prop] = "rgba(" + start.map(function(value, i) {
- value = value + p * (end[i] - value);
- return i === 3 ? toFloat(value) : parseInt(value, 10);
- }).join(",") + ")";
- break;
-
- case "blur":
- css.filter += " blur(" + value + "px)";
- break;
-
- case "hue":
- css.filter += " hue-rotate(" + value + "deg)";
- break;
-
- case "fopacity":
- css.filter += " opacity(" + value + "%)";
- break;
-
- case "grayscale":
- case "invert":
- case "saturate":
- case "sepia":
- css.filter += " " + prop + "(" + value + "%)";
- break;
-
- default:
- css[prop] = value;
- }
- return css;
- }, {
- transform: "",
- filter: ""
- });
- }
- }
- };
- function parseColor(el, color) {
- return css(css(el, "color", color), "color").split(/[(),]/g).slice(1, -1).concat(1).slice(0, 4).map(function(n) {
- return toFloat(n);
- });
- }
- function getStep(steps, percent) {
- var count = steps.length - 1;
- var index = Math.min(Math.floor(count * percent), count - 1);
- var step = steps.slice(index, index + 2);
- step.push(percent === 1 ? 1 : percent % (1 / count) * count);
- return step;
- }
- function getValue(steps, percent) {
- var ref = getStep(steps, percent);
- var start = ref[0];
- var end = ref[1];
- var p = ref[2];
- return (isNumber(start) ? start + Math.abs(start - end) * p * (start < end ? 1 : -1) : +end).toFixed(2);
- }
- function covers(el) {
- var ref = el.style;
- var backgroundSize = ref.backgroundSize;
- var covers = css(css(el, "backgroundSize", ""), "backgroundSize") === "cover";
- el.style.backgroundSize = backgroundSize;
- return covers;
- }
- }
- function plugin$7(UIkit) {
- if (plugin$7.installed) {
- return;
- }
- UIkit.use(plugin$8);
- var mixin = UIkit.mixin;
- var util = UIkit.util;
- var clamp = util.clamp;
- var css = util.css;
- var scrolledOver = util.scrolledOver;
- var query = util.query;
- UIkit.component("parallax", {
- mixins: [ mixin.parallax ],
- props: {
- target: String,
- viewport: Number,
- easing: Number
- },
- defaults: {
- target: false,
- viewport: 1,
- easing: 1
- },
- computed: {
- target: function target(ref, $el) {
- var target = ref.target;
- return target && query(target, $el) || $el;
- }
- },
- update: [ {
- read: function read(ref) {
- var percent = ref.percent;
- return {
- prev: percent,
- percent: ease(scrolledOver(this.target) / (this.viewport || 1), this.easing)
- };
- },
- write: function write(ref, ref$1) {
- var prev = ref.prev;
- var percent = ref.percent;
- var active = ref.active;
- var type = ref$1.type;
- if (type !== "scroll") {
- prev = false;
- }
- if (!active) {
- this.reset();
- return;
- }
- if (prev !== percent) {
- css(this.$el, this.getCss(percent));
- }
- },
- events: [ "scroll", "load", "resize" ]
- } ]
- });
- function ease(percent, easing) {
- return clamp(percent * (1 - (easing - easing * percent)));
- }
- }
- function SliderReactive(UIkit) {
- var ref = UIkit.util;
- var removeClass = ref.removeClass;
- return {
- update: [ {
- write: function write() {
- if (this.stack.length || this.dragging) {
- return;
- }
- var index = this.getValidIndex();
- delete this.index;
- removeClass(this.slides, this.clsActive, this.clsActivated);
- this.show(index);
- },
- events: [ "load", "resize" ]
- } ]
- };
- }
- function TransitionerPlugin$1(UIkit) {
- var ref = UIkit.util;
- var assign = ref.assign;
- var clamp = ref.clamp;
- var createEvent = ref.createEvent;
- var css = ref.css;
- var Deferred = ref.Deferred;
- var includes = ref.includes;
- var index = ref.index;
- var isRtl = ref.isRtl;
- var noop = ref.noop;
- var sortBy = ref.sortBy;
- var toNodes = ref.toNodes;
- var Transition = ref.Transition;
- var trigger = ref.trigger;
- var Transitioner = assign(function(prev, next, dir, ref) {
- var center = ref.center;
- var easing = ref.easing;
- var list = ref.list;
- var deferred = new Deferred();
- var from = prev ? Transitioner.getLeft(prev, list, center) : Transitioner.getLeft(next, list, center) + next.offsetWidth * dir, to = next ? Transitioner.getLeft(next, list, center) : from + prev.offsetWidth * dir * (isRtl ? -1 : 1);
- return {
- dir: dir,
- show: function show(duration, percent, linear) {
- if (percent === void 0) percent = 0;
- var timing = linear ? "linear" : easing;
- duration -= Math.round(duration * clamp(percent, -1, 1));
- this.translate(percent);
- prev && this.updateTranslates();
- percent = prev ? percent : clamp(percent, 0, 1);
- triggerUpdate(this.getItemIn(), "itemin", {
- percent: percent,
- duration: duration,
- timing: timing,
- dir: dir
- });
- prev && triggerUpdate(this.getItemIn(true), "itemout", {
- percent: 1 - percent,
- duration: duration,
- timing: timing,
- dir: dir
- });
- Transition.start(list, {
- transform: translate(-to * (isRtl ? -1 : 1), "px")
- }, duration, timing).then(deferred.resolve, noop);
- return deferred.promise;
- },
- stop: function stop() {
- return Transition.stop(list);
- },
- cancel: function cancel() {
- Transition.cancel(list);
- },
- reset: function reset() {
- css(list, "transform", "");
- },
- forward: function forward(duration, percent) {
- if (percent === void 0) percent = this.percent();
- Transition.cancel(list);
- return this.show(duration, percent, true);
- },
- translate: function translate$1(percent) {
- var distance = this.getDistance() * dir * (isRtl ? -1 : 1);
- css(list, "transform", translate(clamp(-to + (distance - distance * percent), -Transitioner.getWidth(list), list.offsetWidth) * (isRtl ? -1 : 1), "px"));
- this.updateTranslates();
- if (prev) {
- percent = clamp(percent, -1, 1);
- triggerUpdate(this.getItemIn(), "itemtranslatein", {
- percent: percent,
- dir: dir
- });
- triggerUpdate(this.getItemIn(true), "itemtranslateout", {
- percent: 1 - percent,
- dir: dir
- });
- }
- },
- percent: function percent() {
- return Math.abs((css(list, "transform").split(",")[4] * (isRtl ? -1 : 1) + from) / (to - from));
- },
- getDistance: function getDistance() {
- return Math.abs(to - from);
- },
- getItemIn: function getItemIn(out) {
- if (out === void 0) out = false;
- var actives = this.getActives();
- var all = sortBy(slides(list), "offsetLeft");
- var i = index(all, actives[dir * (out ? -1 : 1) > 0 ? actives.length - 1 : 0]);
- return ~i && all[i + (prev && !out ? dir : 0)];
- },
- getActives: function getActives() {
- var left = Transitioner.getLeft(prev || next, list, center);
- return sortBy(slides(list).filter(function(slide) {
- var slideLeft = Transitioner.getElLeft(slide, list);
- return slideLeft >= left && slideLeft + slide.offsetWidth <= list.offsetWidth + left;
- }), "offsetLeft");
- },
- updateTranslates: function updateTranslates() {
- var actives = this.getActives();
- slides(list).forEach(function(slide) {
- var isActive = includes(actives, slide);
- triggerUpdate(slide, "itemtranslate" + (isActive ? "in" : "out"), {
- percent: isActive ? 1 : 0,
- dir: slide.offsetLeft <= next.offsetLeft ? 1 : -1
- });
- });
- }
- };
- }, {
- getLeft: function getLeft(el, list, center) {
- var left = this.getElLeft(el, list);
- return center ? left - this.center(el, list) : Math.min(left, this.getMax(list));
- },
- getMax: function getMax(list) {
- return Math.max(0, this.getWidth(list) - list.offsetWidth);
- },
- getWidth: function getWidth(list) {
- return slides(list).reduce(function(right, el) {
- return el.offsetWidth + right;
- }, 0);
- },
- getMaxWidth: function getMaxWidth(list) {
- return slides(list).reduce(function(right, el) {
- return Math.max(right, el.offsetWidth);
- }, 0);
- },
- center: function center(el, list) {
- return list.offsetWidth / 2 - el.offsetWidth / 2;
- },
- getElLeft: function getElLeft(el, list) {
- return (el.offsetLeft + (isRtl ? el.offsetWidth - list.offsetWidth : 0)) * (isRtl ? -1 : 1);
- }
- });
- function triggerUpdate(el, type, data) {
- trigger(el, createEvent(type, false, false, data));
- }
- function slides(list) {
- return toNodes(list.children);
- }
- return Transitioner;
- }
- function ParallaxPlugin(UIkit, parent) {
- UIkit.use(plugin$8);
- var mixin = UIkit.mixin;
- var UIkit_util = UIkit.util;
- var closest = UIkit_util.closest;
- var css = UIkit_util.css;
- var endsWith = UIkit_util.endsWith;
- var noop = UIkit_util.noop;
- var Transition = UIkit_util.Transition;
- return {
- mixins: [ mixin.parallax ],
- computed: {
- item: function item() {
- var slider = UIkit.getComponent(closest(this.$el, ".uk-" + parent), parent);
- return slider && closest(this.$el, slider.slidesSelector);
- }
- },
- events: [ {
- name: "itemshown",
- self: true,
- el: function el() {
- return this.item;
- },
- handler: function handler() {
- css(this.$el, this.getCss(.5));
- }
- }, {
- name: "itemin itemout",
- self: true,
- el: function el() {
- return this.item;
- },
- handler: function handler(ref) {
- var type = ref.type;
- var ref_detail = ref.detail;
- var percent = ref_detail.percent;
- var duration = ref_detail.duration;
- var timing = ref_detail.timing;
- var dir = ref_detail.dir;
- Transition.cancel(this.$el);
- css(this.$el, this.getCss(getCurrent(type, dir, percent)));
- Transition.start(this.$el, this.getCss(isIn(type) ? .5 : dir > 0 ? 1 : 0), duration, timing).catch(noop);
- }
- }, {
- name: "transitioncanceled transitionend",
- self: true,
- el: function el() {
- return this.item;
- },
- handler: function handler() {
- Transition.cancel(this.$el);
- }
- }, {
- name: "itemtranslatein itemtranslateout",
- self: true,
- el: function el() {
- return this.item;
- },
- handler: function handler(ref) {
- var type = ref.type;
- var ref_detail = ref.detail;
- var percent = ref_detail.percent;
- var dir = ref_detail.dir;
- Transition.cancel(this.$el);
- css(this.$el, this.getCss(getCurrent(type, dir, percent)));
- }
- } ]
- };
- function isIn(type) {
- return endsWith(type, "in");
- }
- function getCurrent(type, dir, percent) {
- percent /= 2;
- return !isIn(type) ? dir < 0 ? percent : 1 - percent : dir < 0 ? 1 - percent : percent;
- }
- }
- function plugin$9(UIkit) {
- if (plugin$9.installed) {
- return;
- }
- UIkit.use(plugin$5);
- var mixin = UIkit.mixin;
- var UIkit_util = UIkit.util;
- var $ = UIkit_util.$;
- var $$ = UIkit_util.$$;
- var addClass = UIkit_util.addClass;
- var css = UIkit_util.css;
- var data = UIkit_util.data;
- var includes = UIkit_util.includes;
- var isNumeric = UIkit_util.isNumeric;
- var isUndefined = UIkit_util.isUndefined;
- var offset = UIkit_util.offset;
- var toggleClass = UIkit_util.toggleClass;
- var toFloat = UIkit_util.toFloat;
- var Transitioner = TransitionerPlugin$1(UIkit);
- UIkit.component("slider-parallax", ParallaxPlugin(UIkit, "slider"));
- UIkit.component("slider", {
- mixins: [ mixin.class, mixin.slider, SliderReactive(UIkit) ],
- props: {
- center: Boolean,
- sets: Boolean
- },
- defaults: {
- center: false,
- sets: false,
- attrItem: "uk-slider-item",
- selList: ".uk-slider-items",
- selNav: ".uk-slider-nav",
- clsContainer: "uk-slider-container",
- Transitioner: Transitioner
- },
- computed: {
- avgWidth: function avgWidth() {
- return Transitioner.getWidth(this.list) / this.length;
- },
- finite: function finite(ref) {
- var finite = ref.finite;
- return finite || Transitioner.getWidth(this.list) < this.list.offsetWidth + Transitioner.getMaxWidth(this.list) + this.center;
- },
- maxIndex: function maxIndex() {
- var this$1 = this;
- if (!this.finite || this.center && !this.sets) {
- return this.length - 1;
- }
- if (this.center) {
- return this.sets[this.sets.length - 1];
- }
- css(this.slides, "order", "");
- var max = Transitioner.getMax(this.list);
- var i = this.length;
- while (i--) {
- if (Transitioner.getElLeft(this$1.list.children[i], this$1.list) < max) {
- return Math.min(i + 1, this$1.length - 1);
- }
- }
- return 0;
- },
- sets: function sets(ref) {
- var this$1 = this;
- var sets = ref.sets;
- var width = this.list.offsetWidth / (this.center ? 2 : 1);
- var left = 0;
- var leftCenter = width;
- sets = sets && this.slides.reduce(function(sets, slide, i) {
- var dim = offset(slide);
- if (dim.right > left) {
- if (!this$1.center && i > this$1.maxIndex) {
- i = this$1.maxIndex;
- }
- if (!includes(sets, i)) {
- var cmp = this$1.slides[i + 1];
- if (this$1.center && cmp && dim.width < leftCenter - offset(cmp).width / 2) {
- leftCenter -= dim.width;
- } else {
- leftCenter = width;
- sets.push(i);
- left = dim.left + width + (this$1.center ? dim.width / 2 : 0);
- }
- }
- }
- return sets;
- }, []);
- return sets && sets.length && sets;
- },
- transitionOptions: function transitionOptions() {
- return {
- center: this.center,
- list: this.list
- };
- }
- },
- connected: function connected() {
- toggleClass(this.$el, this.clsContainer, !$("." + this.clsContainer, this.$el));
- },
- update: {
- write: function write() {
- var this$1 = this;
- $$("[" + this.attrItem + "],[data-" + this.attrItem + "]", this.$el).forEach(function(el) {
- var index = data(el, this$1.attrItem);
- this$1.maxIndex && toggleClass(el, "uk-hidden", isNumeric(index) && (this$1.sets && !includes(this$1.sets, toFloat(index)) || index > this$1.maxIndex));
- });
- },
- events: [ "load", "resize" ]
- },
- events: {
- beforeitemshow: function beforeitemshow(e) {
- var this$1 = this;
- if (!this.dragging && this.sets && this.stack.length < 2 && !includes(this.sets, this.index)) {
- this.index = this.getValidIndex();
- }
- var diff = Math.abs(this.index - this.prevIndex + (this.dir > 0 && this.index < this.prevIndex || this.dir < 0 && this.index > this.prevIndex ? (this.maxIndex + 1) * this.dir : 0));
- if (!this.dragging && diff > 1) {
- for (var i = 0; i < diff; i++) {
- this$1.stack.splice(1, 0, this$1.dir > 0 ? "next" : "previous");
- }
- e.preventDefault();
- return;
- }
- this.duration = speedUp(this.avgWidth / this.velocity) * ((this.dir < 0 || !this.slides[this.prevIndex] ? this.slides[this.index] : this.slides[this.prevIndex]).offsetWidth / this.avgWidth);
- this.reorder();
- },
- itemshow: function itemshow() {
- !isUndefined(this.prevIndex) && addClass(this._getTransitioner().getItemIn(), this.clsActive);
- },
- itemshown: function itemshown() {
- var this$1 = this;
- var actives = this._getTransitioner(this.index).getActives();
- this.slides.forEach(function(slide) {
- return toggleClass(slide, this$1.clsActive, includes(actives, slide));
- });
- (!this.sets || includes(this.sets, toFloat(this.index))) && this.slides.forEach(function(slide) {
- return toggleClass(slide, this$1.clsActivated, includes(actives, slide));
- });
- }
- },
- methods: {
- reorder: function reorder() {
- var this$1 = this;
- css(this.slides, "order", "");
- if (this.finite) {
- return;
- }
- var index = this.dir > 0 && this.slides[this.prevIndex] ? this.prevIndex : this.index;
- this.slides.forEach(function(slide, i) {
- return css(slide, "order", this$1.dir > 0 && i < index ? 1 : this$1.dir < 0 && i >= this$1.index ? -1 : "");
- });
- if (!this.center) {
- return;
- }
- var next = this.slides[index];
- var width = this.list.offsetWidth / 2 - next.offsetWidth / 2;
- var j = 0;
- while (width > 0) {
- var slideIndex = this$1.getIndex(--j + index, index);
- var slide = this$1.slides[slideIndex];
- css(slide, "order", slideIndex > index ? -2 : -1);
- width -= slide.offsetWidth;
- }
- },
- getValidIndex: function getValidIndex(index, prevIndex) {
- var this$1 = this;
- if (index === void 0) index = this.index;
- if (prevIndex === void 0) prevIndex = this.prevIndex;
- index = this.getIndex(index, prevIndex);
- if (!this.sets) {
- return index;
- }
- var prev;
- do {
- if (includes(this$1.sets, index)) {
- return index;
- }
- prev = index;
- index = this$1.getIndex(index + this$1.dir, prevIndex);
- } while (index !== prev);
- return index;
- }
- }
- });
- }
- function AnimationsPlugin$2(UIkit) {
- var mixin = UIkit.mixin;
- var UIkit_util = UIkit.util;
- var assign = UIkit_util.assign;
- var css = UIkit_util.css;
- var Animations = assign({}, mixin.slideshow.defaults.Animations, {
- fade: {
- show: function show() {
- return [ {
- opacity: 0,
- zIndex: 0
- }, {
- zIndex: -1
- } ];
- },
- percent: function percent(current) {
- return 1 - css(current, "opacity");
- },
- translate: function translate$$1(percent) {
- return [ {
- opacity: 1 - percent,
- zIndex: 0
- }, {
- zIndex: -1
- } ];
- }
- },
- scale: {
- show: function show() {
- return [ {
- opacity: 0,
- transform: scale3d(1 + .5),
- zIndex: 0
- }, {
- zIndex: -1
- } ];
- },
- percent: function percent(current) {
- return 1 - css(current, "opacity");
- },
- translate: function translate$$1(percent) {
- return [ {
- opacity: 1 - percent,
- transform: scale3d(1 + .5 * percent),
- zIndex: 0
- }, {
- zIndex: -1
- } ];
- }
- },
- pull: {
- show: function show(dir) {
- return dir < 0 ? [ {
- transform: translate(30),
- zIndex: -1
- }, {
- transform: translate(),
- zIndex: 0
- } ] : [ {
- transform: translate(-100),
- zIndex: 0
- }, {
- transform: translate(),
- zIndex: -1
- } ];
- },
- percent: function percent(current, next, dir) {
- return dir < 0 ? 1 - Animations.translated(next) : Animations.translated(current);
- },
- translate: function translate$1(percent, dir) {
- return dir < 0 ? [ {
- transform: translate(30 * percent),
- zIndex: -1
- }, {
- transform: translate(-100 * (1 - percent)),
- zIndex: 0
- } ] : [ {
- transform: translate(-percent * 100),
- zIndex: 0
- }, {
- transform: translate(30 * (1 - percent)),
- zIndex: -1
- } ];
- }
- },
- push: {
- show: function show(dir) {
- return dir < 0 ? [ {
- transform: translate(100),
- zIndex: 0
- }, {
- transform: translate(),
- zIndex: -1
- } ] : [ {
- transform: translate(-30),
- zIndex: -1
- }, {
- transform: translate(),
- zIndex: 0
- } ];
- },
- percent: function percent(current, next, dir) {
- return dir > 0 ? 1 - Animations.translated(next) : Animations.translated(current);
- },
- translate: function translate$2(percent, dir) {
- return dir < 0 ? [ {
- transform: translate(percent * 100),
- zIndex: 0
- }, {
- transform: translate(-30 * (1 - percent)),
- zIndex: -1
- } ] : [ {
- transform: translate(-30 * percent),
- zIndex: -1
- }, {
- transform: translate(100 * (1 - percent)),
- zIndex: 0
- } ];
- }
- }
- });
- return Animations;
- }
- function plugin$10(UIkit) {
- if (plugin$10.installed) {
- return;
- }
- UIkit.use(plugin$4);
- var mixin = UIkit.mixin;
- var height = UIkit.util.height;
- var Animations = AnimationsPlugin$2(UIkit);
- UIkit.component("slideshow-parallax", ParallaxPlugin(UIkit, "slideshow"));
- UIkit.component("slideshow", {
- mixins: [ mixin.class, mixin.slideshow, SliderReactive(UIkit) ],
- props: {
- ratio: String,
- minHeight: Boolean,
- maxHeight: Boolean
- },
- defaults: {
- ratio: "16:9",
- minHeight: false,
- maxHeight: false,
- selList: ".uk-slideshow-items",
- attrItem: "uk-slideshow-item",
- selNav: ".uk-slideshow-nav",
- Animations: Animations
- },
- update: {
- read: function read() {
- var ref = this.ratio.split(":").map(Number);
- var width = ref[0];
- var height = ref[1];
- height = height * this.$el.offsetWidth / width;
- if (this.minHeight) {
- height = Math.max(this.minHeight, height);
- }
- if (this.maxHeight) {
- height = Math.min(this.maxHeight, height);
- }
- return {
- height: height
- };
- },
- write: function write(ref) {
- var hgt = ref.height;
- height(this.list, Math.floor(hgt));
- },
- events: [ "load", "resize" ]
- }
- });
- }
- function plugin$11(UIkit) {
- var obj;
- if (plugin$11.installed) {
- return;
- }
- var mixin = UIkit.mixin;
- var util = UIkit.util;
- var addClass = util.addClass;
- var after = util.after;
- var assign = util.assign;
- var append = util.append;
- var attr = util.attr;
- var before = util.before;
- var closest = util.closest;
- var css = util.css;
- var height = util.height;
- var fastdom = util.fastdom;
- var getPos = util.getPos;
- var includes = util.includes;
- var index = util.index;
- var isInput = util.isInput;
- var noop = util.noop;
- var offset = util.offset;
- var off = util.off;
- var on = util.on;
- var pointerDown = util.pointerDown;
- var pointerMove = util.pointerMove;
- var pointerUp = util.pointerUp;
- var position = util.position;
- var preventClick = util.preventClick;
- var Promise = util.Promise;
- var remove = util.remove;
- var removeClass = util.removeClass;
- var toggleClass = util.toggleClass;
- var toNodes = util.toNodes;
- var Transition = util.Transition;
- var trigger = util.trigger;
- var within = util.within;
- UIkit.component("sortable", {
- mixins: [ mixin.class ],
- props: {
- group: String,
- animation: Number,
- threshold: Number,
- clsItem: String,
- clsPlaceholder: String,
- clsDrag: String,
- clsDragState: String,
- clsBase: String,
- clsNoDrag: String,
- clsEmpty: String,
- clsCustom: String,
- handle: String
- },
- defaults: {
- group: false,
- animation: 150,
- threshold: 5,
- clsItem: "uk-sortable-item",
- clsPlaceholder: "uk-sortable-placeholder",
- clsDrag: "uk-sortable-drag",
- clsDragState: "uk-drag",
- clsBase: "uk-sortable",
- clsNoDrag: "uk-sortable-nodrag",
- clsEmpty: "uk-sortable-empty",
- clsCustom: "",
- handle: false
- },
- init: function init() {
- var this$1 = this;
- [ "init", "start", "move", "end" ].forEach(function(key) {
- var fn = this$1[key];
- this$1[key] = function(e) {
- this$1.scrollY = window.pageYOffset;
- var ref = getPos(e);
- var x = ref.x;
- var y = ref.y;
- this$1.pos = {
- x: x,
- y: y
- };
- fn(e);
- };
- });
- },
- events: (obj = {}, obj[pointerDown] = "init", obj),
- update: {
- write: function write() {
- if (this.clsEmpty) {
- toggleClass(this.$el, this.clsEmpty, !this.$el.children.length);
- }
- if (!this.drag) {
- return;
- }
- offset(this.drag, {
- top: this.pos.y + this.origin.top,
- left: this.pos.x + this.origin.left
- });
- var ref = offset(this.drag);
- var top = ref.top;
- var bottom = top + this.drag.offsetHeight;
- var scroll;
- if (top > 0 && top < this.scrollY) {
- scroll = this.scrollY - 5;
- } else if (bottom < height(document) && bottom > height(window) + this.scrollY) {
- scroll = this.scrollY + 5;
- }
- scroll && setTimeout(function() {
- return window.scrollTo(window.scrollX, scroll);
- }, 5);
- }
- },
- methods: {
- init: function init(e) {
- var target = e.target;
- var button = e.button;
- var defaultPrevented = e.defaultPrevented;
- var ref = toNodes(this.$el.children).filter(function(el) {
- return within(target, el);
- });
- var placeholder = ref[0];
- if (!placeholder || isInput(e.target) || this.handle && !within(target, this.handle) || button > 0 || within(target, "." + this.clsNoDrag) || defaultPrevented) {
- return;
- }
- e.preventDefault();
- this.touched = [ this ];
- this.placeholder = placeholder;
- this.origin = assign({
- target: target,
- index: index(placeholder)
- }, this.pos);
- on(document, pointerMove, this.move);
- on(document, pointerUp, this.end);
- on(window, "scroll", this.scroll);
- if (!this.threshold) {
- this.start(e);
- }
- },
- start: function start(e) {
- this.drag = append(UIkit.container, this.placeholder.outerHTML.replace(/^$/i, "div>"));
- css(this.drag, assign({
- boxSizing: "border-box",
- width: this.placeholder.offsetWidth,
- height: this.placeholder.offsetHeight
- }, css(this.placeholder, [ "paddingLeft", "paddingRight", "paddingTop", "paddingBottom" ])));
- attr(this.drag, "uk-no-boot", "");
- addClass(this.drag, this.clsDrag, this.clsCustom);
- height(this.drag.firstElementChild, height(this.placeholder.firstElementChild));
- var ref = offset(this.placeholder);
- var left = ref.left;
- var top = ref.top;
- assign(this.origin, {
- left: left - this.pos.x,
- top: top - this.pos.y
- });
- addClass(this.placeholder, this.clsPlaceholder);
- addClass(this.$el.children, this.clsItem);
- addClass(document.documentElement, this.clsDragState);
- trigger(this.$el, "start", [ this, this.placeholder, this.drag ]);
- this.move(e);
- },
- move: function move(e) {
- if (!this.drag) {
- if (Math.abs(this.pos.x - this.origin.x) > this.threshold || Math.abs(this.pos.y - this.origin.y) > this.threshold) {
- this.start(e);
- }
- return;
- }
- this.$emit();
- var target = e.type === "mousemove" ? e.target : document.elementFromPoint(this.pos.x - document.body.scrollLeft, this.pos.y - document.body.scrollTop);
- var sortable = getSortable(target);
- var previous = getSortable(this.placeholder);
- var move = sortable !== previous;
- if (!sortable || within(target, this.placeholder) || move && (!sortable.group || sortable.group !== previous.group)) {
- return;
- }
- target = sortable.$el === target.parentNode && target || toNodes(sortable.$el.children).filter(function(element) {
- return within(target, element);
- })[0];
- if (move) {
- previous.remove(this.placeholder);
- } else if (!target) {
- return;
- }
- sortable.insert(this.placeholder, target);
- if (!includes(this.touched, sortable)) {
- this.touched.push(sortable);
- }
- },
- scroll: function scroll() {
- var scroll = window.pageYOffset;
- if (scroll !== this.scrollY) {
- this.pos.y += scroll - this.scrollY;
- this.scrollY = scroll;
- this.$emit();
- }
- },
- end: function end(e) {
- off(document, pointerMove, this.move);
- off(document, pointerUp, this.end);
- off(window, "scroll", this.scroll);
- if (!this.drag) {
- if (e.type !== "mouseup" && within(e.target, "a[href]")) {
- location.href = closest(e.target, "a[href]").href;
- }
- return;
- }
- preventClick();
- var sortable = getSortable(this.placeholder);
- if (this === sortable) {
- if (this.origin.index !== index(this.placeholder)) {
- trigger(this.$el, "moved", [ this, this.placeholder ]);
- }
- } else {
- trigger(sortable.$el, "added", [ sortable, this.placeholder ]);
- trigger(this.$el, "removed", [ this, this.placeholder ]);
- }
- trigger(this.$el, "stop", [ this ]);
- remove(this.drag);
- this.drag = null;
- var classes = this.touched.map(function(sortable) {
- return sortable.clsPlaceholder + " " + sortable.clsItem;
- }).join(" ");
- this.touched.forEach(function(sortable) {
- return removeClass(sortable.$el.children, classes);
- });
- removeClass(document.documentElement, this.clsDragState);
- },
- insert: function insert(element, target) {
- var this$1 = this;
- addClass(this.$el.children, this.clsItem);
- var insert = function() {
- if (target) {
- if (!within(element, this$1.$el) || isPredecessor(element, target)) {
- before(target, element);
- } else {
- after(target, element);
- }
- } else {
- append(this$1.$el, element);
- }
- };
- if (this.animation) {
- this.animate(insert);
- } else {
- insert();
- }
- },
- remove: function remove$1(element) {
- if (!within(element, this.$el)) {
- return;
- }
- if (this.animation) {
- this.animate(function() {
- return remove(element);
- });
- } else {
- remove(element);
- }
- },
- animate: function animate(action) {
- var this$1 = this;
- var props = [];
- var children = toNodes(this.$el.children);
- var reset = {
- position: "",
- width: "",
- height: "",
- pointerEvents: "",
- top: "",
- left: "",
- bottom: "",
- right: ""
- };
- children.forEach(function(el) {
- props.push(assign({
- position: "absolute",
- pointerEvents: "none",
- width: el.offsetWidth,
- height: el.offsetHeight
- }, position(el)));
- });
- action();
- children.forEach(Transition.cancel);
- css(this.$el.children, reset);
- UIkit.update(this.$el);
- fastdom.flush();
- css(this.$el, "minHeight", height(this.$el));
- var positions = children.map(function(el) {
- return position(el);
- });
- Promise.all(children.map(function(el, i) {
- return Transition.start(css(el, props[i]), positions[i], this$1.animation);
- })).then(function() {
- css(this$1.$el, "minHeight", "");
- css(children, reset);
- UIkit.update(this$1.$el);
- fastdom.flush();
- }, noop);
- }
- }
- });
- function getSortable(element) {
- return element && (UIkit.getComponent(element, "sortable") || getSortable(element.parentNode));
- }
- function isPredecessor(element, target) {
- return element.parentNode === target.parentNode && index(element) > index(target);
- }
- }
- function plugin$12(UIkit) {
- var obj;
- if (plugin$12.installed) {
- return;
- }
- var util = UIkit.util;
- var mixin = UIkit.mixin;
- var append = util.append;
- var attr = util.attr;
- var flipPosition = util.flipPosition;
- var hasAttr = util.hasAttr;
- var includes = util.includes;
- var isTouch = util.isTouch;
- var isVisible = util.isVisible;
- var matches = util.matches;
- var on = util.on;
- var pointerDown = util.pointerDown;
- var pointerEnter = util.pointerEnter;
- var pointerLeave = util.pointerLeave;
- var remove = util.remove;
- var within = util.within;
- var actives = [];
- UIkit.component("tooltip", {
- attrs: true,
- args: "title",
- mixins: [ mixin.container, mixin.togglable, mixin.position ],
- props: {
- delay: Number,
- title: String
- },
- defaults: {
- pos: "top",
- title: "",
- delay: 0,
- animation: [ "uk-animation-scale-up" ],
- duration: 100,
- cls: "uk-active",
- clsPos: "uk-tooltip"
- },
- beforeConnect: function beforeConnect() {
- this._hasTitle = hasAttr(this.$el, "title");
- attr(this.$el, {
- title: "",
- "aria-expanded": false
- });
- },
- disconnected: function disconnected() {
- this.hide();
- attr(this.$el, {
- title: this._hasTitle ? this.title : null,
- "aria-expanded": null
- });
- },
- methods: {
- show: function show() {
- var this$1 = this;
- if (includes(actives, this)) {
- return;
- }
- actives.forEach(function(active) {
- return active.hide();
- });
- actives.push(this);
- this._unbind = on(document, "click", function(e) {
- return !within(e.target, this$1.$el) && this$1.hide();
- });
- clearTimeout(this.showTimer);
- this.tooltip = append(this.container, '");
- attr(this.$el, "aria-expanded", true);
- this.positionAt(this.tooltip, this.$el);
- this.origin = this.getAxis() === "y" ? flipPosition(this.dir) + "-" + this.align : this.align + "-" + flipPosition(this.dir);
- this.showTimer = setTimeout(function() {
- this$1.toggleElement(this$1.tooltip, true);
- this$1.hideTimer = setInterval(function() {
- if (!isVisible(this$1.$el)) {
- this$1.hide();
- }
- }, 150);
- }, this.delay);
- },
- hide: function hide() {
- var index = actives.indexOf(this);
- if (!~index || matches(this.$el, "input") && this.$el === document.activeElement) {
- return;
- }
- actives.splice(index, 1);
- clearTimeout(this.showTimer);
- clearInterval(this.hideTimer);
- attr(this.$el, "aria-expanded", false);
- this.toggleElement(this.tooltip, false);
- this.tooltip && remove(this.tooltip);
- this.tooltip = false;
- this._unbind();
- }
- },
- events: (obj = {}, obj["focus " + pointerEnter + " " + pointerDown] = function(e) {
- if (e.type !== pointerDown || !isTouch(e)) {
- this.show();
- }
- }, obj.blur = "hide", obj[pointerLeave] = function(e) {
- if (!isTouch(e)) {
- this.hide();
- }
- }, obj)
- });
- }
- function plugin$13(UIkit) {
- if (plugin$13.installed) {
- return;
- }
- var ref = UIkit.util;
- var addClass = ref.addClass;
- var ajax = ref.ajax;
- var matches = ref.matches;
- var noop = ref.noop;
- var on = ref.on;
- var removeClass = ref.removeClass;
- var trigger = ref.trigger;
- UIkit.component("upload", {
- props: {
- allow: String,
- clsDragover: String,
- concurrent: Number,
- maxSize: Number,
- method: String,
- mime: String,
- msgInvalidMime: String,
- msgInvalidName: String,
- msgInvalidSize: String,
- multiple: Boolean,
- name: String,
- params: Object,
- type: String,
- url: String
- },
- defaults: {
- allow: false,
- clsDragover: "uk-dragover",
- concurrent: 1,
- maxSize: 0,
- method: "POST",
- mime: false,
- msgInvalidMime: "Invalid File Type: %s",
- msgInvalidName: "Invalid File Name: %s",
- msgInvalidSize: "Invalid File Size: %s Bytes Max",
- multiple: false,
- name: "files[]",
- params: {},
- type: "",
- url: "",
- abort: noop,
- beforeAll: noop,
- beforeSend: noop,
- complete: noop,
- completeAll: noop,
- error: noop,
- fail: noop,
- load: noop,
- loadEnd: noop,
- loadStart: noop,
- progress: noop
- },
- events: {
- change: function change(e) {
- if (!matches(e.target, 'input[type="file"]')) {
- return;
- }
- e.preventDefault();
- if (e.target.files) {
- this.upload(e.target.files);
- }
- e.target.value = "";
- },
- drop: function drop(e) {
- stop(e);
- var transfer = e.dataTransfer;
- if (!transfer || !transfer.files) {
- return;
- }
- removeClass(this.$el, this.clsDragover);
- this.upload(transfer.files);
- },
- dragenter: function dragenter(e) {
- stop(e);
- },
- dragover: function dragover(e) {
- stop(e);
- addClass(this.$el, this.clsDragover);
- },
- dragleave: function dragleave(e) {
- stop(e);
- removeClass(this.$el, this.clsDragover);
- }
- },
- methods: {
- upload: function upload(files) {
- var this$1 = this;
- if (!files.length) {
- return;
- }
- trigger(this.$el, "upload", [ files ]);
- for (var i = 0; i < files.length; i++) {
- if (this$1.maxSize && this$1.maxSize * 1e3 < files[i].size) {
- this$1.fail(this$1.msgInvalidSize.replace("%s", this$1.allow));
- return;
- }
- if (this$1.allow && !match(this$1.allow, files[i].name)) {
- this$1.fail(this$1.msgInvalidName.replace("%s", this$1.allow));
- return;
- }
- if (this$1.mime && !match(this$1.mime, files[i].type)) {
- this$1.fail(this$1.msgInvalidMime.replace("%s", this$1.mime));
- return;
- }
- }
- if (!this.multiple) {
- files = [ files[0] ];
- }
- this.beforeAll(this, files);
- var chunks = chunk(files, this.concurrent);
- var upload = function(files) {
- var data = new FormData();
- files.forEach(function(file) {
- return data.append(this$1.name, file);
- });
- for (var key in this$1.params) {
- data.append(key, this$1.params[key]);
- }
- ajax(this$1.url, {
- data: data,
- method: this$1.method,
- responseType: this$1.type,
- beforeSend: function(env) {
- var xhr = env.xhr;
- xhr.upload && on(xhr.upload, "progress", this$1.progress);
- [ "loadStart", "load", "loadEnd", "abort" ].forEach(function(type) {
- return on(xhr, type.toLowerCase(), this$1[type]);
- });
- this$1.beforeSend(env);
- }
- }).then(function(xhr) {
- this$1.complete(xhr);
- if (chunks.length) {
- upload(chunks.shift());
- } else {
- this$1.completeAll(xhr);
- }
- }, function(e) {
- return this$1.error(e.message);
- });
- };
- upload(chunks.shift());
- }
- }
- });
- function match(pattern, path) {
- return path.match(new RegExp("^" + pattern.replace(/\//g, "\\/").replace(/\*\*/g, "(\\/[^\\/]+)*").replace(/\*/g, "[^\\/]+").replace(/((?!\\))\?/g, "$1.") + "$", "i"));
- }
- function chunk(files, size) {
- var chunks = [];
- for (var i = 0; i < files.length; i += size) {
- var chunk = [];
- for (var j = 0; j < size; j++) {
- chunk.push(files[i + j]);
- }
- chunks.push(chunk);
- }
- return chunks;
- }
- function stop(e) {
- e.preventDefault();
- e.stopPropagation();
- }
- }
- UIkit$2.use(plugin);
- UIkit$2.use(plugin$1);
- UIkit$2.use(plugin$2);
- UIkit$2.use(plugin$6);
- UIkit$2.use(plugin$7);
- UIkit$2.use(plugin$9);
- UIkit$2.use(plugin$10);
- UIkit$2.use(plugin$11);
- UIkit$2.use(plugin$12);
- UIkit$2.use(plugin$13);
- {
- boot(UIkit$2);
- }
- return UIkit$2;
-});
-
-(function(global, factory) {
- typeof exports === "object" && typeof module !== "undefined" ? module.exports = factory() : typeof define === "function" && define.amd ? define("uikiticons", factory) : global.UIkitIcons = factory();
-})(this, function() {
- "use strict";
- var album = ' ';
- var ban = ' ';
- var behance = ' ';
- var bell = ' ';
- var bold = ' ';
- var bolt = ' ';
- var bookmark = ' ';
- var calendar = ' ';
- var camera = ' ';
- var cart = ' ';
- var check = ' ';
- var clock = ' ';
- var close = ' ';
- var code = ' ';
- var cog = ' ';
- var comment = ' ';
- var commenting = ' ';
- var comments = ' ';
- var copy = ' ';
- var database = ' ';
- var desktop = ' ';
- var download = ' ';
- var dribbble = ' ';
- var expand = ' ';
- var facebook = ' ';
- var file = ' ';
- var flickr = ' ';
- var folder = ' ';
- var forward = ' ';
- var foursquare = ' ';
- var future = ' ';
- var github = ' ';
- var gitter = ' ';
- var google = ' ';
- var grid = ' ';
- var happy = ' ';
- var hashtag = ' ';
- var heart = ' ';
- var history = ' ';
- var home = ' ';
- var image = ' ';
- var info = ' ';
- var instagram = ' ';
- var italic = ' ';
- var joomla = ' ';
- var laptop = ' ';
- var lifesaver = ' ';
- var link = ' ';
- var linkedin = ' ';
- var list = ' ';
- var location = ' ';
- var lock = ' ';
- var mail = ' ';
- var menu = ' ';
- var minus = ' ';
- var more = ' ';
- var move = ' ';
- var nut = ' ';
- var pagekit = ' ';
- var pencil = ' ';
- var phone = ' ';
- var pinterest = ' ';
- var play = ' ';
- var plus = ' ';
- var pull = ' ';
- var push = ' ';
- var question = ' ';
- var receiver = ' ';
- var refresh = ' ';
- var reply = ' ';
- var rss = ' ';
- var search = ' ';
- var server = ' ';
- var settings = ' ';
- var shrink = ' ';
- var social = ' ';
- var soundcloud = ' ';
- var star = ' ';
- var strikethrough = ' ';
- var table = ' ';
- var tablet = ' ';
- var tag = ' ';
- var thumbnails = ' ';
- var trash = ' ';
- var tripadvisor = ' ';
- var tumblr = ' ';
- var tv = ' ';
- var twitter = ' ';
- var uikit = ' ';
- var unlock = ' ';
- var upload = ' ';
- var user = ' ';
- var users = ' ';
- var vimeo = ' ';
- var warning = ' ';
- var whatsapp = ' ';
- var wordpress = ' ';
- var world = ' ';
- var xing = ' ';
- var yelp = ' ';
- var youtube = ' ';
- var Icons = {
- album: album,
- ban: ban,
- behance: behance,
- bell: bell,
- bold: bold,
- bolt: bolt,
- bookmark: bookmark,
- calendar: calendar,
- camera: camera,
- cart: cart,
- check: check,
- clock: clock,
- close: close,
- code: code,
- cog: cog,
- comment: comment,
- commenting: commenting,
- comments: comments,
- copy: copy,
- database: database,
- desktop: desktop,
- download: download,
- dribbble: dribbble,
- expand: expand,
- facebook: facebook,
- file: file,
- flickr: flickr,
- folder: folder,
- forward: forward,
- foursquare: foursquare,
- future: future,
- github: github,
- gitter: gitter,
- google: google,
- grid: grid,
- happy: happy,
- hashtag: hashtag,
- heart: heart,
- history: history,
- home: home,
- image: image,
- info: info,
- instagram: instagram,
- italic: italic,
- joomla: joomla,
- laptop: laptop,
- lifesaver: lifesaver,
- link: link,
- linkedin: linkedin,
- list: list,
- location: location,
- lock: lock,
- mail: mail,
- menu: menu,
- minus: minus,
- more: more,
- move: move,
- nut: nut,
- pagekit: pagekit,
- pencil: pencil,
- phone: phone,
- pinterest: pinterest,
- play: play,
- plus: plus,
- pull: pull,
- push: push,
- question: question,
- receiver: receiver,
- refresh: refresh,
- reply: reply,
- rss: rss,
- search: search,
- server: server,
- settings: settings,
- shrink: shrink,
- social: social,
- soundcloud: soundcloud,
- star: star,
- strikethrough: strikethrough,
- table: table,
- tablet: tablet,
- tag: tag,
- thumbnails: thumbnails,
- trash: trash,
- tripadvisor: tripadvisor,
- tumblr: tumblr,
- tv: tv,
- twitter: twitter,
- uikit: uikit,
- unlock: unlock,
- upload: upload,
- user: user,
- users: users,
- vimeo: vimeo,
- warning: warning,
- whatsapp: whatsapp,
- wordpress: wordpress,
- world: world,
- xing: xing,
- yelp: yelp,
- youtube: youtube,
- "500px": ' ',
- "arrow-down": ' ',
- "arrow-left": ' ',
- "arrow-right": ' ',
- "arrow-up": ' ',
- "chevron-down": ' ',
- "chevron-left": ' ',
- "chevron-right": ' ',
- "chevron-up": ' ',
- "cloud-download": ' ',
- "cloud-upload": ' ',
- "credit-card": ' ',
- "file-edit": ' ',
- "git-branch": ' ',
- "git-fork": ' ',
- "github-alt": ' ',
- "google-plus": ' ',
- "minus-circle": ' ',
- "more-vertical": ' ',
- "paint-bucket": ' ',
- "phone-landscape": ' ',
- "play-circle": ' ',
- "plus-circle": ' ',
- "quote-right": ' ',
- "sign-in": ' ',
- "sign-out": ' ',
- "tablet-landscape": ' ',
- "triangle-down": ' ',
- "triangle-left": ' ',
- "triangle-right": ' ',
- "triangle-up": ' ',
- "video-camera": ' '
- };
- function plugin(UIkit) {
- if (plugin.installed) {
- return;
- }
- UIkit.icon.add(Icons);
- }
- if (typeof window !== "undefined" && window.UIkit) {
- window.UIkit.use(plugin);
- }
- return plugin;
-});
-
-(function() {
- "use strict";
- var _$JSONLoader_2 = {
- load: load
- };
- function load(location, callback) {
- var xhr = getXHR();
- xhr.open("GET", location, true);
- xhr.onreadystatechange = createStateChangeListener(xhr, callback);
- xhr.send();
- }
- function createStateChangeListener(xhr, callback) {
- return function() {
- if (xhr.readyState === 4 && xhr.status === 200) {
- try {
- callback(null, JSON.parse(xhr.responseText));
- } catch (err) {
- callback(err, null);
- }
- }
- };
- }
- function getXHR() {
- return window.XMLHttpRequest ? new window.XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");
- }
- "use strict";
- var _$OptionsValidator_3 = function OptionsValidator(params) {
- if (!validateParams(params)) {
- throw new Error("-- OptionsValidator: required options missing");
- }
- if (!(this instanceof OptionsValidator)) {
- return new OptionsValidator(params);
- }
- var requiredOptions = params.required;
- this.getRequiredOptions = function() {
- return requiredOptions;
- };
- this.validate = function(parameters) {
- var errors = [];
- requiredOptions.forEach(function(requiredOptionName) {
- if (typeof parameters[requiredOptionName] === "undefined") {
- errors.push(requiredOptionName);
- }
- });
- return errors;
- };
- function validateParams(params) {
- if (!params) {
- return false;
- }
- return typeof params.required !== "undefined" && params.required instanceof Array;
- }
- };
- "use strict";
- function fuzzysearch(needle, haystack) {
- var tlen = haystack.length;
- var qlen = needle.length;
- if (qlen > tlen) {
- return false;
- }
- if (qlen === tlen) {
- return needle === haystack;
- }
- outer: for (var i = 0, j = 0; i < qlen; i++) {
- var nch = needle.charCodeAt(i);
- while (j < tlen) {
- if (haystack.charCodeAt(j++) === nch) {
- continue outer;
- }
- }
- return false;
- }
- return true;
- }
- var _$fuzzysearch_1 = fuzzysearch;
- "use strict";
- var _$FuzzySearchStrategy_5 = new FuzzySearchStrategy();
- function FuzzySearchStrategy() {
- this.matches = function(string, crit) {
- return _$fuzzysearch_1(crit.toLowerCase(), string.toLowerCase());
- };
- }
- "use strict";
- var _$LiteralSearchStrategy_6 = new LiteralSearchStrategy();
- function LiteralSearchStrategy() {
- this.matches = function(str, crit) {
- if (typeof str !== "string") {
- return false;
- }
- str = str.trim();
- return str.toLowerCase().indexOf(crit.toLowerCase()) >= 0;
- };
- }
- "use strict";
- var _$Repository_4 = {
- put: put,
- clear: clear,
- search: search,
- setOptions: setOptions
- };
- function NoSort() {
- return 0;
- }
- var data = [];
- var opt = {};
- opt.fuzzy = false;
- opt.limit = 10;
- opt.searchStrategy = opt.fuzzy ? _$FuzzySearchStrategy_5 : _$LiteralSearchStrategy_6;
- opt.sort = NoSort;
- function put(data) {
- if (isObject(data)) {
- return addObject(data);
- }
- if (isArray(data)) {
- return addArray(data);
- }
- return undefined;
- }
- function clear() {
- data.length = 0;
- return data;
- }
- function isObject(obj) {
- return Boolean(obj) && Object.prototype.toString.call(obj) === "[object Object]";
- }
- function isArray(obj) {
- return Boolean(obj) && Object.prototype.toString.call(obj) === "[object Array]";
- }
- function addObject(_data) {
- data.push(_data);
- return data;
- }
- function addArray(_data) {
- var added = [];
- clear();
- for (var i = 0, len = _data.length; i < len; i++) {
- if (isObject(_data[i])) {
- added.push(addObject(_data[i]));
- }
- }
- return added;
- }
- function search(crit) {
- if (!crit) {
- return [];
- }
- return findMatches(data, crit, opt.searchStrategy, opt).sort(opt.sort);
- }
- function setOptions(_opt) {
- opt = _opt || {};
- opt.fuzzy = _opt.fuzzy || false;
- opt.limit = _opt.limit || 10;
- opt.searchStrategy = _opt.fuzzy ? _$FuzzySearchStrategy_5 : _$LiteralSearchStrategy_6;
- opt.sort = _opt.sort || NoSort;
- }
- function findMatches(data, crit, strategy, opt) {
- var matches = [];
- for (var i = 0; i < data.length && matches.length < opt.limit; i++) {
- var match = findMatchesInObject(data[i], crit, strategy, opt);
- if (match) {
- matches.push(match);
- }
- }
- return matches;
- }
- function findMatchesInObject(obj, crit, strategy, opt) {
- for (var key in obj) {
- if (!isExcluded(obj[key], opt.exclude) && strategy.matches(obj[key], crit)) {
- return obj;
- }
- }
- }
- function isExcluded(term, excludedTerms) {
- var excluded = false;
- excludedTerms = excludedTerms || [];
- for (var i = 0, len = excludedTerms.length; i < len; i++) {
- var excludedTerm = excludedTerms[i];
- if (!excluded && new RegExp(term).test(excludedTerm)) {
- excluded = true;
- }
- }
- return excluded;
- }
- "use strict";
- var _$Templater_7 = {
- compile: compile,
- setOptions: __setOptions_7
- };
- var options = {};
- options.pattern = /\{(.*?)\}/g;
- options.template = "";
- options.middleware = function() {};
- function __setOptions_7(_options) {
- options.pattern = _options.pattern || options.pattern;
- options.template = _options.template || options.template;
- if (typeof _options.middleware === "function") {
- options.middleware = _options.middleware;
- }
- }
- function compile(data) {
- return options.template.replace(options.pattern, function(match, prop) {
- var value = options.middleware(prop, data[prop], options.template);
- if (typeof value !== "undefined") {
- return value;
- }
- return data[prop] || match;
- });
- }
- "use strict";
- var _$utils_9 = {
- merge: merge,
- isJSON: isJSON
- };
- function merge(defaultParams, mergeParams) {
- var mergedOptions = {};
- for (var option in defaultParams) {
- if (Object.prototype.hasOwnProperty.call(defaultParams, option)) {
- mergedOptions[option] = defaultParams[option];
- if (typeof mergeParams[option] !== "undefined") {
- mergedOptions[option] = mergeParams[option];
- }
- }
- }
- return mergedOptions;
- }
- function isJSON(json) {
- try {
- if (json instanceof Object && JSON.parse(JSON.stringify(json))) {
- return true;
- }
- return false;
- } catch (err) {
- return false;
- }
- }
- var _$src_8 = {};
- (function(window) {
- "use strict";
- var options = {
- searchInput: null,
- resultsContainer: null,
- json: [],
- searchResultTemplate: ' {title} ',
- templateMiddleware: function() {},
- sortMiddleware: function() {
- return 0;
- },
- noResultsText: "No results found",
- limit: 10,
- fuzzy: false,
- exclude: []
- };
- var requiredOptions = [ "searchInput", "resultsContainer", "json" ];
- var optionsValidator = _$OptionsValidator_3({
- required: requiredOptions
- });
- window.SimpleJekyllSearch = function(_options) {
- var errors = optionsValidator.validate(_options);
- if (errors.length > 0) {
- throwError("You must specify the following required options: " + requiredOptions);
- }
- options = _$utils_9.merge(options, _options);
- _$Templater_7.setOptions({
- template: options.searchResultTemplate,
- middleware: options.templateMiddleware
- });
- _$Repository_4.setOptions({
- fuzzy: options.fuzzy,
- limit: options.limit,
- sort: options.sortMiddleware
- });
- if (_$utils_9.isJSON(options.json)) {
- initWithJSON(options.json);
- } else {
- initWithURL(options.json);
- }
- return {
- search: search
- };
- };
- window.SimpleJekyllSearch.init = window.SimpleJekyllSearch;
- if (typeof window.SimpleJekyllSearchInit === "function") {
- window.SimpleJekyllSearchInit.call(this, window.SimpleJekyllSearch);
- }
- function initWithJSON(json) {
- _$Repository_4.put(json);
- registerInput();
- }
- function initWithURL(url) {
- _$JSONLoader_2.load(url, function(err, json) {
- if (err) {
- throwError("failed to get JSON (" + url + ")");
- }
- initWithJSON(json);
- });
- }
- function emptyResultsContainer() {
- options.resultsContainer.innerHTML = "";
- }
- function appendToResultsContainer(text) {
- options.resultsContainer.innerHTML += text;
- }
- function registerInput() {
- options.searchInput.addEventListener("keyup", function(e) {
- if (isWhitelistedKey(e.which)) {
- emptyResultsContainer();
- search(e.target.value);
- }
- });
- }
- function search(query) {
- if (isValidQuery(query)) {
- emptyResultsContainer();
- render(_$Repository_4.search(query));
- }
- }
- function render(results) {
- var len = results.length;
- if (len === 0) {
- return appendToResultsContainer(options.noResultsText);
- }
- for (var i = 0; i < len; i++) {
- appendToResultsContainer(_$Templater_7.compile(results[i]));
- }
- }
- function isValidQuery(query) {
- return query && query.length > 0;
- }
- function isWhitelistedKey(key) {
- return [ 13, 16, 20, 37, 38, 39, 40, 91 ].indexOf(key) === -1;
- }
- function throwError(message) {
- throw new Error("SimpleJekyllSearch --- " + message);
- }
- })(window);
-})();
\ No newline at end of file
diff --git a/assets/posts/7C04AAA0EE9E3886.png b/assets/posts/7C04AAA0EE9E3886.png
deleted file mode 100644
index 8af764e0b5..0000000000
Binary files a/assets/posts/7C04AAA0EE9E3886.png and /dev/null differ
diff --git a/assets/posts/SVG/logo.svg b/assets/posts/SVG/logo.svg
deleted file mode 100644
index 886b00f891..0000000000
--- a/assets/posts/SVG/logo.svg
+++ /dev/null
@@ -1 +0,0 @@
-logo
\ No newline at end of file
diff --git a/assets/posts/books.svg b/assets/posts/books.svg
deleted file mode 100644
index 6e5638ac37..0000000000
--- a/assets/posts/books.svg
+++ /dev/null
@@ -1,51 +0,0 @@
-
-
-
- Books
- Created with Sketch.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/assets/posts/box.svg b/assets/posts/box.svg
deleted file mode 100644
index 625e607a25..0000000000
--- a/assets/posts/box.svg
+++ /dev/null
@@ -1,100 +0,0 @@
-
-
-
- Box
- Created with Sketch.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/assets/posts/city.svg b/assets/posts/city.svg
deleted file mode 100644
index 337229f80d..0000000000
--- a/assets/posts/city.svg
+++ /dev/null
@@ -1,188 +0,0 @@
-
-
-
- Style 9
- Created with Sketch.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/assets/posts/imac.svg b/assets/posts/imac.svg
deleted file mode 100644
index 881398574d..0000000000
--- a/assets/posts/imac.svg
+++ /dev/null
@@ -1,47 +0,0 @@
-
-
-
- iMac
- Created with Sketch.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/assets/posts/image1.png b/assets/posts/image1.png
deleted file mode 100644
index a7125c3140..0000000000
Binary files a/assets/posts/image1.png and /dev/null differ
diff --git a/assets/posts/logo.png b/assets/posts/logo.png
deleted file mode 100644
index 4b1793c8b5..0000000000
Binary files a/assets/posts/logo.png and /dev/null differ
diff --git a/assets/posts/logo.svg b/assets/posts/logo.svg
deleted file mode 100644
index 4cf1acadf5..0000000000
--- a/assets/posts/logo.svg
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-logo
-
-
-
diff --git a/assets/posts/old.logo.svg b/assets/posts/old.logo.svg
deleted file mode 100755
index c12f862550..0000000000
--- a/assets/posts/old.logo.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/assets/posts/safe.svg b/assets/posts/safe.svg
deleted file mode 100644
index 4ece36002d..0000000000
--- a/assets/posts/safe.svg
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-
- Safe
- Created with Sketch.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/assets/posts/sky.svg b/assets/posts/sky.svg
deleted file mode 100644
index 3913866cb0..0000000000
--- a/assets/posts/sky.svg
+++ /dev/null
@@ -1,113 +0,0 @@
-
-
-
- Style 1
- Created with Sketch.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/assets/posts/slideshow-1/image1.png b/assets/posts/slideshow-1/image1.png
deleted file mode 100644
index a7125c3140..0000000000
Binary files a/assets/posts/slideshow-1/image1.png and /dev/null differ
diff --git a/assets/posts/teacup.svg b/assets/posts/teacup.svg
deleted file mode 100644
index 729cf60ed3..0000000000
--- a/assets/posts/teacup.svg
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
- Teacup
- Created with Sketch.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/assets/posts/touch-icon.png b/assets/posts/touch-icon.png
deleted file mode 100644
index 243615bb9f..0000000000
Binary files a/assets/posts/touch-icon.png and /dev/null differ
diff --git a/assets/posts/touch-icon.svg b/assets/posts/touch-icon.svg
deleted file mode 100644
index cc1205e398..0000000000
--- a/assets/posts/touch-icon.svg
+++ /dev/null
@@ -1 +0,0 @@
-Asset 1
\ No newline at end of file
diff --git a/changelog.md b/changelog.md
deleted file mode 100644
index 8bac050030..0000000000
--- a/changelog.md
+++ /dev/null
@@ -1,7 +0,0 @@
----
-layout: changelog
-title: Changelog
-permalink: /changelog/
----
-
-Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.
diff --git a/collections.json b/collections.json
deleted file mode 100644
index 594a064876..0000000000
--- a/collections.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "version": "THEVERSION",
- "collections": [
- {
- "name": "browser",
- "repo": "https://github.com/blockstack/blockstack-browser"
- },
- {
- "name": "core",
- "repo": "https://github.com/blockstack/blockstack-core"
- }
- ]
-}
diff --git a/contact.md b/contact.md
deleted file mode 100644
index 00c0d0f968..0000000000
--- a/contact.md
+++ /dev/null
@@ -1,14 +0,0 @@
----
-layout: contact
-title: Got Any Questions
-permalink: /contact/
-formspree:
- email: my_name@gmail.com
- redirect: /thanks/
----
-
-##### Morbi varius in accumsan blandit, elit ligula velit, luctus mattis ante nulla nulla.
-
-Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt.
-
-{% include map.html latitude="40.6700" longitude="-73.9400" zoom="16" %}
diff --git a/contribute.md b/contribute.md
new file mode 100644
index 0000000000..b2f6db1b02
--- /dev/null
+++ b/contribute.md
@@ -0,0 +1,18 @@
+# Contribute
+
+### Contribute to Stacks Core
+
+There is a [detailed contribution guide](https://github.com/stacks-network/stacks-core/blob/master/CONTRIBUTING.md) that lives in the Stacks core GitHub repository that is the best place to get started contributing to Stacks.
+
+### Contribute to these Docs
+
+The Stacks docs are built using GitBook with a two-way sync with the [docs repository on GitHub](https://github.com/stacks-network/docs).
+
+Because of this two-way sync, you can contribute to the documentation in one of two ways:
+
+1. You can fork the docs repo, add your change, and then create a PR to be merged into the main docs
+2. You can create an issue, and someone that works on the docs will take a look and implement it if it is a necessary change
+
+What kinds of changes are we looking for?
+
+If you see a typo, a missing tutorial, an unclear explanation, or really anything else you think could improve the quality of the documentation, please feel free to open an issue or create a pull request.
diff --git a/docs/build/.gitbook.yaml b/docs/build/.gitbook.yaml
new file mode 100644
index 0000000000..253e89b1e5
--- /dev/null
+++ b/docs/build/.gitbook.yaml
@@ -0,0 +1,36 @@
+root: ./
+
+redirects:
+ guides-and-tutorials/hello-stacks-quickstart-tutorial: README.md
+ guides-and-tutorials/clarity-crash-course: clarity-crash-course.md
+
+ # bitcoin-integration redirects
+ guides-and-tutorials/bitcoin-integration/sending-bitcoin-with-leather-wallet: bitcoin-integration/sending-bitcoin-with-leather.md
+ guides-and-tutorials/bitcoin-integration/parsing-a-bitcoin-transaction: bitcoin-integration/parsing-a-bitcoin-transaction.md
+ guides-and-tutorials/bitcoin-integration/verifying-a-bitcoin-transaction: bitcoin-integration/verifying-a-bitcoin-transaction.md
+
+ # create-tokens redirects
+ guides-and-tutorials/tokens/creating-a-nft: create-tokens/creating-a-nft.md
+ guides-and-tutorials/tokens/creating-a-fungible-token: create-tokens/creating-a-ft.md
+
+ # build-a-frontend redirects
+ guides-and-tutorials/frontend/authentication-with-stacks.js: build-a-frontend/authentication-with-stacks.js.md
+ guides-and-tutorials/frontend/post-conditions-with-stacks.js: build-a-frontend/post-conditions-with-stacks.js.md
+ guides-and-tutorials/frontend/sending-transactions-with-stacks.js: build-a-frontend/sending-transactions-with-stacks.js.md
+
+ # testing-smart-contracts redirects
+ guides-and-tutorials/testing-smart-contracts/fuzz-testing: testing-smart-contracts/fuzz-testing.md
+
+ # sbtc redirects
+ guides-and-tutorials/sbtc/best-practices-for-running-an-sbtc-signer: sbtc/best-practices-for-running-an-sbtc-signer.md
+ guides-and-tutorials/sbtc/earn-sbtc-rewards: sbtc/how-to-earn-sbtc-rewards.md
+ guides-and-tutorials/sbtc/how-to-run-sbtc-signer: sbtc/how-to-run-sbtc-signer.md
+ guides-and-tutorials/sbtc/how-to-use-the-sbtc-bridge: sbtc/how-to-use-the-sbtc-bridge.md
+ guides-and-tutorials/sbtc/sbtc-builder-quickstart: sbtc/sbtc-builder-quickstart.md
+
+ # oracles redirects
+ guides-and-tutorials/oracles: price-oracles.md
+
+ # misc.-guides redirects
+ guides-and-tutorials/build-a-borrowing-and-lending-protocol: misc.-guides/build-a-borrowing-and-lending-protocol.md
+ guides-and-tutorials/community-tutorials: misc.-guides/community-tutorials.md
diff --git a/docs/build/.gitbook/assets/Frame 316125324 (1).jpg b/docs/build/.gitbook/assets/Frame 316125324 (1).jpg
new file mode 100644
index 0000000000..8964e1069c
Binary files /dev/null and b/docs/build/.gitbook/assets/Frame 316125324 (1).jpg differ
diff --git a/docs/build/.gitbook/assets/Frame 316125324.jpg b/docs/build/.gitbook/assets/Frame 316125324.jpg
new file mode 100644
index 0000000000..8964e1069c
Binary files /dev/null and b/docs/build/.gitbook/assets/Frame 316125324.jpg differ
diff --git a/docs/build/.gitbook/assets/Frame 316126251.jpg b/docs/build/.gitbook/assets/Frame 316126251.jpg
new file mode 100644
index 0000000000..ecaaf0c522
Binary files /dev/null and b/docs/build/.gitbook/assets/Frame 316126251.jpg differ
diff --git a/docs/build/.gitbook/assets/GcHiZWjXgAA21Kf.jpeg b/docs/build/.gitbook/assets/GcHiZWjXgAA21Kf.jpeg
new file mode 100644
index 0000000000..0209b9426a
Binary files /dev/null and b/docs/build/.gitbook/assets/GcHiZWjXgAA21Kf.jpeg differ
diff --git a/docs/build/.gitbook/assets/Group 316124778 (1)-with-fordefi.png b/docs/build/.gitbook/assets/Group 316124778 (1)-with-fordefi.png
new file mode 100644
index 0000000000..5bfe3c487a
Binary files /dev/null and b/docs/build/.gitbook/assets/Group 316124778 (1)-with-fordefi.png differ
diff --git a/docs/build/.gitbook/assets/Group 316124778 (2)-with-fordefi.png b/docs/build/.gitbook/assets/Group 316124778 (2)-with-fordefi.png
new file mode 100644
index 0000000000..9b806f1b58
Binary files /dev/null and b/docs/build/.gitbook/assets/Group 316124778 (2)-with-fordefi.png differ
diff --git a/docs/build/.gitbook/assets/Group 316124778 (3)-with-fordefi.png b/docs/build/.gitbook/assets/Group 316124778 (3)-with-fordefi.png
new file mode 100644
index 0000000000..3319d3c070
Binary files /dev/null and b/docs/build/.gitbook/assets/Group 316124778 (3)-with-fordefi.png differ
diff --git a/docs/build/.gitbook/assets/Group 316124778 (4)-with-fordefi.png b/docs/build/.gitbook/assets/Group 316124778 (4)-with-fordefi.png
new file mode 100644
index 0000000000..86eb052ce8
Binary files /dev/null and b/docs/build/.gitbook/assets/Group 316124778 (4)-with-fordefi.png differ
diff --git a/docs/build/.gitbook/assets/Group 316124779-with-asigna.png b/docs/build/.gitbook/assets/Group 316124779-with-asigna.png
new file mode 100644
index 0000000000..72f2b66bcc
Binary files /dev/null and b/docs/build/.gitbook/assets/Group 316124779-with-asigna.png differ
diff --git a/docs/build/.gitbook/assets/Group 316124780 (1)-with-asigna.png b/docs/build/.gitbook/assets/Group 316124780 (1)-with-asigna.png
new file mode 100644
index 0000000000..660e948434
Binary files /dev/null and b/docs/build/.gitbook/assets/Group 316124780 (1)-with-asigna.png differ
diff --git a/docs/build/.gitbook/assets/Group 316124780-with-asigna.png b/docs/build/.gitbook/assets/Group 316124780-with-asigna.png
new file mode 100644
index 0000000000..d06a74bc72
Binary files /dev/null and b/docs/build/.gitbook/assets/Group 316124780-with-asigna.png differ
diff --git a/docs/build/.gitbook/assets/authentication.jpg b/docs/build/.gitbook/assets/authentication.jpg
new file mode 100644
index 0000000000..f3dd58eb80
Binary files /dev/null and b/docs/build/.gitbook/assets/authentication.jpg differ
diff --git a/docs/build/.gitbook/assets/bitcoin-clarity.png b/docs/build/.gitbook/assets/bitcoin-clarity.png
new file mode 100644
index 0000000000..3f5455fa3d
Binary files /dev/null and b/docs/build/.gitbook/assets/bitcoin-clarity.png differ
diff --git a/docs/build/.gitbook/assets/build-a-frontend.jpg b/docs/build/.gitbook/assets/build-a-frontend.jpg
new file mode 100644
index 0000000000..9512ef0c68
Binary files /dev/null and b/docs/build/.gitbook/assets/build-a-frontend.jpg differ
diff --git a/docs/build/.gitbook/assets/build-intro.jpg b/docs/build/.gitbook/assets/build-intro.jpg
new file mode 100644
index 0000000000..052e7f91c7
Binary files /dev/null and b/docs/build/.gitbook/assets/build-intro.jpg differ
diff --git a/docs/build/.gitbook/assets/build-intro.png b/docs/build/.gitbook/assets/build-intro.png
new file mode 100644
index 0000000000..3ca2812082
Binary files /dev/null and b/docs/build/.gitbook/assets/build-intro.png differ
diff --git a/docs/build/.gitbook/assets/clarinet-diagram.png b/docs/build/.gitbook/assets/clarinet-diagram.png
new file mode 100644
index 0000000000..3ce68c0c16
Binary files /dev/null and b/docs/build/.gitbook/assets/clarinet-diagram.png differ
diff --git a/docs/build/.gitbook/assets/clarinet-js-sdk.png b/docs/build/.gitbook/assets/clarinet-js-sdk.png
new file mode 100644
index 0000000000..59518cd545
Binary files /dev/null and b/docs/build/.gitbook/assets/clarinet-js-sdk.png differ
diff --git a/docs/build/.gitbook/assets/clarinet-sdk.png b/docs/build/.gitbook/assets/clarinet-sdk.png
new file mode 100644
index 0000000000..cbae820d7a
Binary files /dev/null and b/docs/build/.gitbook/assets/clarinet-sdk.png differ
diff --git a/docs/build/.gitbook/assets/clarity-extension.png b/docs/build/.gitbook/assets/clarity-extension.png
new file mode 100644
index 0000000000..905e73353b
Binary files /dev/null and b/docs/build/.gitbook/assets/clarity-extension.png differ
diff --git a/docs/build/.gitbook/assets/clarity-playground-console.png b/docs/build/.gitbook/assets/clarity-playground-console.png
new file mode 100644
index 0000000000..835c150a8c
Binary files /dev/null and b/docs/build/.gitbook/assets/clarity-playground-console.png differ
diff --git a/docs/build/.gitbook/assets/clarity-playground.png b/docs/build/.gitbook/assets/clarity-playground.png
new file mode 100644
index 0000000000..779f958242
Binary files /dev/null and b/docs/build/.gitbook/assets/clarity-playground.png differ
diff --git a/docs/build/.gitbook/assets/clarity.jpg b/docs/build/.gitbook/assets/clarity.jpg
new file mode 100644
index 0000000000..4ab9a4fd97
Binary files /dev/null and b/docs/build/.gitbook/assets/clarity.jpg differ
diff --git a/docs/build/.gitbook/assets/custom-taproot-deposit-address.jpeg b/docs/build/.gitbook/assets/custom-taproot-deposit-address.jpeg
new file mode 100644
index 0000000000..0b67844174
Binary files /dev/null and b/docs/build/.gitbook/assets/custom-taproot-deposit-address.jpeg differ
diff --git a/docs/build/.gitbook/assets/custom-wallet-connect-modal.png b/docs/build/.gitbook/assets/custom-wallet-connect-modal.png
new file mode 100644
index 0000000000..0d3940e245
Binary files /dev/null and b/docs/build/.gitbook/assets/custom-wallet-connect-modal.png differ
diff --git a/docs/build/.gitbook/assets/deploy-contract.jpg b/docs/build/.gitbook/assets/deploy-contract.jpg
new file mode 100644
index 0000000000..8964e1069c
Binary files /dev/null and b/docs/build/.gitbook/assets/deploy-contract.jpg differ
diff --git a/docs/build/.gitbook/assets/devtools-ecosystem.png b/docs/build/.gitbook/assets/devtools-ecosystem.png
new file mode 100644
index 0000000000..007cdafd37
Binary files /dev/null and b/docs/build/.gitbook/assets/devtools-ecosystem.png differ
diff --git a/docs/build/.gitbook/assets/enable-sbtc-view.png b/docs/build/.gitbook/assets/enable-sbtc-view.png
new file mode 100644
index 0000000000..1ef8ebf4e7
Binary files /dev/null and b/docs/build/.gitbook/assets/enable-sbtc-view.png differ
diff --git a/docs/build/.gitbook/assets/example-post-condition-leather.png b/docs/build/.gitbook/assets/example-post-condition-leather.png
new file mode 100644
index 0000000000..19e2f09f22
Binary files /dev/null and b/docs/build/.gitbook/assets/example-post-condition-leather.png differ
diff --git a/docs/build/.gitbook/assets/image (1).png b/docs/build/.gitbook/assets/image (1).png
new file mode 100644
index 0000000000..90ba3f571b
Binary files /dev/null and b/docs/build/.gitbook/assets/image (1).png differ
diff --git a/docs/build/.gitbook/assets/image (10)-sbtc-bridge.png b/docs/build/.gitbook/assets/image (10)-sbtc-bridge.png
new file mode 100644
index 0000000000..8177a76839
Binary files /dev/null and b/docs/build/.gitbook/assets/image (10)-sbtc-bridge.png differ
diff --git a/docs/build/.gitbook/assets/image (11)-sbtc-bridge.png b/docs/build/.gitbook/assets/image (11)-sbtc-bridge.png
new file mode 100644
index 0000000000..ac78447329
Binary files /dev/null and b/docs/build/.gitbook/assets/image (11)-sbtc-bridge.png differ
diff --git a/docs/build/.gitbook/assets/image (12)-sbtc-bridge.png b/docs/build/.gitbook/assets/image (12)-sbtc-bridge.png
new file mode 100644
index 0000000000..9210b58c1a
Binary files /dev/null and b/docs/build/.gitbook/assets/image (12)-sbtc-bridge.png differ
diff --git a/docs/build/.gitbook/assets/image (13)-sbtc-bridge.png b/docs/build/.gitbook/assets/image (13)-sbtc-bridge.png
new file mode 100644
index 0000000000..715ec833fe
Binary files /dev/null and b/docs/build/.gitbook/assets/image (13)-sbtc-bridge.png differ
diff --git a/docs/build/.gitbook/assets/image (14)-sbtc-bridge.png b/docs/build/.gitbook/assets/image (14)-sbtc-bridge.png
new file mode 100644
index 0000000000..514951c8b0
Binary files /dev/null and b/docs/build/.gitbook/assets/image (14)-sbtc-bridge.png differ
diff --git a/docs/build/.gitbook/assets/image (2).png b/docs/build/.gitbook/assets/image (2).png
new file mode 100644
index 0000000000..1c637648c3
Binary files /dev/null and b/docs/build/.gitbook/assets/image (2).png differ
diff --git a/docs/build/.gitbook/assets/image (4).png b/docs/build/.gitbook/assets/image (4).png
new file mode 100644
index 0000000000..445dd9848d
Binary files /dev/null and b/docs/build/.gitbook/assets/image (4).png differ
diff --git a/docs/build/.gitbook/assets/image (5).png b/docs/build/.gitbook/assets/image (5).png
new file mode 100644
index 0000000000..ce90bce016
Binary files /dev/null and b/docs/build/.gitbook/assets/image (5).png differ
diff --git a/docs/build/.gitbook/assets/image (6).png b/docs/build/.gitbook/assets/image (6).png
new file mode 100644
index 0000000000..850b421678
Binary files /dev/null and b/docs/build/.gitbook/assets/image (6).png differ
diff --git a/docs/build/.gitbook/assets/image (7).png b/docs/build/.gitbook/assets/image (7).png
new file mode 100644
index 0000000000..35bf7c4f53
Binary files /dev/null and b/docs/build/.gitbook/assets/image (7).png differ
diff --git a/docs/build/.gitbook/assets/image (8).png b/docs/build/.gitbook/assets/image (8).png
new file mode 100644
index 0000000000..c866b0dc8e
Binary files /dev/null and b/docs/build/.gitbook/assets/image (8).png differ
diff --git a/docs/build/.gitbook/assets/image (9)-sbtc-bridge.png b/docs/build/.gitbook/assets/image (9)-sbtc-bridge.png
new file mode 100644
index 0000000000..8f6083d420
Binary files /dev/null and b/docs/build/.gitbook/assets/image (9)-sbtc-bridge.png differ
diff --git a/docs/build/.gitbook/assets/image 11-with-fordefi.png b/docs/build/.gitbook/assets/image 11-with-fordefi.png
new file mode 100644
index 0000000000..01595e7d39
Binary files /dev/null and b/docs/build/.gitbook/assets/image 11-with-fordefi.png differ
diff --git a/docs/build/.gitbook/assets/image 16-with-fordefi.png b/docs/build/.gitbook/assets/image 16-with-fordefi.png
new file mode 100644
index 0000000000..099e6b71c7
Binary files /dev/null and b/docs/build/.gitbook/assets/image 16-with-fordefi.png differ
diff --git a/docs/build/.gitbook/assets/image 2-with-fordefi.png b/docs/build/.gitbook/assets/image 2-with-fordefi.png
new file mode 100644
index 0000000000..b9cb30d7a1
Binary files /dev/null and b/docs/build/.gitbook/assets/image 2-with-fordefi.png differ
diff --git a/docs/build/.gitbook/assets/image 22-with-fordefi.png b/docs/build/.gitbook/assets/image 22-with-fordefi.png
new file mode 100644
index 0000000000..ff2615e114
Binary files /dev/null and b/docs/build/.gitbook/assets/image 22-with-fordefi.png differ
diff --git a/docs/build/.gitbook/assets/image 3-with-fordefi.png b/docs/build/.gitbook/assets/image 3-with-fordefi.png
new file mode 100644
index 0000000000..6d0423b88b
Binary files /dev/null and b/docs/build/.gitbook/assets/image 3-with-fordefi.png differ
diff --git a/docs/build/.gitbook/assets/image 33 (1)-with-asigna.png b/docs/build/.gitbook/assets/image 33 (1)-with-asigna.png
new file mode 100644
index 0000000000..c61a905f63
Binary files /dev/null and b/docs/build/.gitbook/assets/image 33 (1)-with-asigna.png differ
diff --git a/docs/build/.gitbook/assets/image 35-with-asigna.png b/docs/build/.gitbook/assets/image 35-with-asigna.png
new file mode 100644
index 0000000000..e37f5211d0
Binary files /dev/null and b/docs/build/.gitbook/assets/image 35-with-asigna.png differ
diff --git a/docs/build/.gitbook/assets/image 36-with-asigna.png b/docs/build/.gitbook/assets/image 36-with-asigna.png
new file mode 100644
index 0000000000..45a57ac76a
Binary files /dev/null and b/docs/build/.gitbook/assets/image 36-with-asigna.png differ
diff --git a/docs/build/.gitbook/assets/image 37-with-asigna.png b/docs/build/.gitbook/assets/image 37-with-asigna.png
new file mode 100644
index 0000000000..748ca88995
Binary files /dev/null and b/docs/build/.gitbook/assets/image 37-with-asigna.png differ
diff --git a/docs/build/.gitbook/assets/image 38-with-asigna.png b/docs/build/.gitbook/assets/image 38-with-asigna.png
new file mode 100644
index 0000000000..b676da7c7e
Binary files /dev/null and b/docs/build/.gitbook/assets/image 38-with-asigna.png differ
diff --git a/docs/build/.gitbook/assets/image 4-with-fordefi.png b/docs/build/.gitbook/assets/image 4-with-fordefi.png
new file mode 100644
index 0000000000..3842a7c913
Binary files /dev/null and b/docs/build/.gitbook/assets/image 4-with-fordefi.png differ
diff --git a/docs/build/.gitbook/assets/image 40.png b/docs/build/.gitbook/assets/image 40.png
new file mode 100644
index 0000000000..a6ff2ea3fd
Binary files /dev/null and b/docs/build/.gitbook/assets/image 40.png differ
diff --git a/docs/build/.gitbook/assets/image 42 (1)-with-asigna.png b/docs/build/.gitbook/assets/image 42 (1)-with-asigna.png
new file mode 100644
index 0000000000..16b82a5480
Binary files /dev/null and b/docs/build/.gitbook/assets/image 42 (1)-with-asigna.png differ
diff --git a/docs/build/.gitbook/assets/image 43 (1)-with-asigna.png b/docs/build/.gitbook/assets/image 43 (1)-with-asigna.png
new file mode 100644
index 0000000000..8e5cfbc05e
Binary files /dev/null and b/docs/build/.gitbook/assets/image 43 (1)-with-asigna.png differ
diff --git a/docs/build/.gitbook/assets/image 44-with-asigna.png b/docs/build/.gitbook/assets/image 44-with-asigna.png
new file mode 100644
index 0000000000..e09c9131d4
Binary files /dev/null and b/docs/build/.gitbook/assets/image 44-with-asigna.png differ
diff --git a/docs/build/.gitbook/assets/image 45 (1)-with-asigna.png b/docs/build/.gitbook/assets/image 45 (1)-with-asigna.png
new file mode 100644
index 0000000000..30ad78dfbe
Binary files /dev/null and b/docs/build/.gitbook/assets/image 45 (1)-with-asigna.png differ
diff --git a/docs/build/.gitbook/assets/image 46-with-asigna.png b/docs/build/.gitbook/assets/image 46-with-asigna.png
new file mode 100644
index 0000000000..c78859d24f
Binary files /dev/null and b/docs/build/.gitbook/assets/image 46-with-asigna.png differ
diff --git a/docs/build/.gitbook/assets/image 47-with-asigna.png b/docs/build/.gitbook/assets/image 47-with-asigna.png
new file mode 100644
index 0000000000..186243f9cf
Binary files /dev/null and b/docs/build/.gitbook/assets/image 47-with-asigna.png differ
diff --git a/docs/build/.gitbook/assets/image 5-with-fordefi.png b/docs/build/.gitbook/assets/image 5-with-fordefi.png
new file mode 100644
index 0000000000..6edd5519d7
Binary files /dev/null and b/docs/build/.gitbook/assets/image 5-with-fordefi.png differ
diff --git a/docs/build/.gitbook/assets/image 6-with-fordefi.png b/docs/build/.gitbook/assets/image 6-with-fordefi.png
new file mode 100644
index 0000000000..55f9302b83
Binary files /dev/null and b/docs/build/.gitbook/assets/image 6-with-fordefi.png differ
diff --git a/docs/build/.gitbook/assets/image 7-with-fordefi.png b/docs/build/.gitbook/assets/image 7-with-fordefi.png
new file mode 100644
index 0000000000..26d2b2a603
Binary files /dev/null and b/docs/build/.gitbook/assets/image 7-with-fordefi.png differ
diff --git a/docs/build/.gitbook/assets/image 8-with-fordefi.png b/docs/build/.gitbook/assets/image 8-with-fordefi.png
new file mode 100644
index 0000000000..1d60b4bce2
Binary files /dev/null and b/docs/build/.gitbook/assets/image 8-with-fordefi.png differ
diff --git a/docs/build/.gitbook/assets/image.png b/docs/build/.gitbook/assets/image.png
new file mode 100644
index 0000000000..cc6def5437
Binary files /dev/null and b/docs/build/.gitbook/assets/image.png differ
diff --git a/docs/build/.gitbook/assets/onboarding.png b/docs/build/.gitbook/assets/onboarding.png
new file mode 100644
index 0000000000..9d194182af
Binary files /dev/null and b/docs/build/.gitbook/assets/onboarding.png differ
diff --git a/docs/build/.gitbook/assets/post-condition-modes.png b/docs/build/.gitbook/assets/post-condition-modes.png
new file mode 100644
index 0000000000..9fffadeaba
Binary files /dev/null and b/docs/build/.gitbook/assets/post-condition-modes.png differ
diff --git a/docs/build/.gitbook/assets/post-condition-stack.png b/docs/build/.gitbook/assets/post-condition-stack.png
new file mode 100644
index 0000000000..e7ef91906a
Binary files /dev/null and b/docs/build/.gitbook/assets/post-condition-stack.png differ
diff --git a/docs/build/.gitbook/assets/post-conditions-explorer.png b/docs/build/.gitbook/assets/post-conditions-explorer.png
new file mode 100644
index 0000000000..fe32989f86
Binary files /dev/null and b/docs/build/.gitbook/assets/post-conditions-explorer.png differ
diff --git a/docs/build/.gitbook/assets/post-conditions.jpg b/docs/build/.gitbook/assets/post-conditions.jpg
new file mode 100644
index 0000000000..5cab5989fe
Binary files /dev/null and b/docs/build/.gitbook/assets/post-conditions.jpg differ
diff --git a/docs/build/.gitbook/assets/pyth-pull-flow-diagram.png b/docs/build/.gitbook/assets/pyth-pull-flow-diagram.png
new file mode 100644
index 0000000000..49b2b3fac8
Binary files /dev/null and b/docs/build/.gitbook/assets/pyth-pull-flow-diagram.png differ
diff --git a/docs/build/.gitbook/assets/sbtc-clarinet-testing.jpg b/docs/build/.gitbook/assets/sbtc-clarinet-testing.jpg
new file mode 100644
index 0000000000..02201cb8ef
Binary files /dev/null and b/docs/build/.gitbook/assets/sbtc-clarinet-testing.jpg differ
diff --git a/docs/build/.gitbook/assets/sbtc-faucet.png b/docs/build/.gitbook/assets/sbtc-faucet.png
new file mode 100644
index 0000000000..00b9cf6339
Binary files /dev/null and b/docs/build/.gitbook/assets/sbtc-faucet.png differ
diff --git a/docs/build/.gitbook/assets/sbtc-integrations.png b/docs/build/.gitbook/assets/sbtc-integrations.png
new file mode 100644
index 0000000000..c7fd31dc6a
Binary files /dev/null and b/docs/build/.gitbook/assets/sbtc-integrations.png differ
diff --git a/docs/build/.gitbook/assets/send-transactions.jpg b/docs/build/.gitbook/assets/send-transactions.jpg
new file mode 100644
index 0000000000..b4a30bd236
Binary files /dev/null and b/docs/build/.gitbook/assets/send-transactions.jpg differ
diff --git a/docs/build/.gitbook/assets/stacks-bitcoin-address.png b/docs/build/.gitbook/assets/stacks-bitcoin-address.png
new file mode 100644
index 0000000000..421d595fd8
Binary files /dev/null and b/docs/build/.gitbook/assets/stacks-bitcoin-address.png differ
diff --git a/docs/build/.gitbook/assets/stacks-connect-modal.png b/docs/build/.gitbook/assets/stacks-connect-modal.png
new file mode 100644
index 0000000000..78474940ad
Binary files /dev/null and b/docs/build/.gitbook/assets/stacks-connect-modal.png differ
diff --git a/docs/build/.gitbook/assets/stacks-connect.jpg b/docs/build/.gitbook/assets/stacks-connect.jpg
new file mode 100644
index 0000000000..521c9e1b18
Binary files /dev/null and b/docs/build/.gitbook/assets/stacks-connect.jpg differ
diff --git a/docs/build/.gitbook/assets/stacks-devs-twitter-header.png b/docs/build/.gitbook/assets/stacks-devs-twitter-header.png
new file mode 100644
index 0000000000..5198600901
Binary files /dev/null and b/docs/build/.gitbook/assets/stacks-devs-twitter-header.png differ
diff --git a/docs/build/.gitbook/assets/stacksjs-learn.png b/docs/build/.gitbook/assets/stacksjs-learn.png
new file mode 100644
index 0000000000..62cf4ac9cd
Binary files /dev/null and b/docs/build/.gitbook/assets/stacksjs-learn.png differ
diff --git a/docs/build/.gitbook/assets/tx-confirmation-popup.png b/docs/build/.gitbook/assets/tx-confirmation-popup.png
new file mode 100644
index 0000000000..e934e83ff3
Binary files /dev/null and b/docs/build/.gitbook/assets/tx-confirmation-popup.png differ
diff --git a/docs/build/.gitbook/assets/use-cases.png b/docs/build/.gitbook/assets/use-cases.png
new file mode 100644
index 0000000000..b28c194aab
Binary files /dev/null and b/docs/build/.gitbook/assets/use-cases.png differ
diff --git a/docs/build/.gitbook/assets/wallet-communication-flow.png b/docs/build/.gitbook/assets/wallet-communication-flow.png
new file mode 100644
index 0000000000..1ba115e3b0
Binary files /dev/null and b/docs/build/.gitbook/assets/wallet-communication-flow.png differ
diff --git a/docs/build/.gitbook/assets/wallet-extension-template.png b/docs/build/.gitbook/assets/wallet-extension-template.png
new file mode 100644
index 0000000000..af0d603117
Binary files /dev/null and b/docs/build/.gitbook/assets/wallet-extension-template.png differ
diff --git a/docs/build/.gitbook/assets/wallet-implementation.png b/docs/build/.gitbook/assets/wallet-implementation.png
new file mode 100644
index 0000000000..5b1ad2a54a
Binary files /dev/null and b/docs/build/.gitbook/assets/wallet-implementation.png differ
diff --git a/docs/build/README.md b/docs/build/README.md
new file mode 100644
index 0000000000..f39c8c8bd6
--- /dev/null
+++ b/docs/build/README.md
@@ -0,0 +1,63 @@
+---
+description: Build powerful apps, secured by Bitcoin.
+---
+
+# Introduction
+
+
+
+
+
+New to building with Stacks? Check out these weekly virtual meets!
+
+* **Stacks DevRel office hours**: Follow and enable notifications for [@StacksDevs](https://x.com/StacksDevs) on Twitter to catch alerts for our weekly livestreams every Thursday at 10am EST. Office Hours are the easiest way to stay in the loop on product drops, live demos, community builder spotlights, and more. Stay up-to-date with release discussions, real-time walkthroughs, and builder highlights that matter.
+* **Clarity Working Group**: An open, developer-focused initiative dedicated to supporting builders across the Stacks ecosystem. The group brings together experienced Clarity engineers (“Clarity giga chads”), auditors, educators, grant project teams, and new developers to collaborate, learn, and advance smart contract development on Bitcoin. Check out the calendar [link](https://www.addevent.com/event/yc0x95fky8y4) to join every other Tuesday.
+* **AI BTC Working Group:** Join the **AI BTC Working Group**'s (WG) weekly meeting on AIBTC's twitter account, where they delve into the exciting intersection of AI and Bitcoin. Check out the calendar [link](https://www.addevent.com/event/c3qjy462xr82) to join every Thursday.
+* **Runes Capsule Webinars:** Join a weekly deep-dive into Runes Capsule architecture, Bitcoin bridging, and trust minimized design patterns on Stacks. Check out this [link](https://calendar.google.com/calendar/u/0/r?cid=b247d75eb1a11dc3ebbf0c62eb4a1c83b4a53d4d2f903eaa19d685f28f087f92%40group.calendar.google.com) to join every Sundays.
+
+
+
+{% hint style="info" %}
+Stacks ranks #5 among all crypto ecosystems for new developers in 2025! \[source: Electric Capital]
+{% endhint %}
+
+### Hello, Builders 👋
+
+Stacks is a fast, low-cost, builder-friendly layer 2 network on Bitcoin. It’s built on Bitcoin, inheriting Bitcoin’s battle-tested security. By jumping into our docs, you’re joining the Stacks builder community that’s bringing a global onchain economy to Bitcoin.
+
+If you're here on this page, hopefully you've already gotten a good sense of _what_ Stacks' purpose is, if not, head to the [Learn](https://app.gitbook.com/o/hoh4mQXTl8NvI3cETroY/s/H74xqoobupBWwBsVMJhK/) section. Or if you're still on the edge of _why_ you should build with Stacks, head to [Why Build with Stacks](get-started/introduction/why-build-with-stacks.md).
+
+***
+
+### Pick your learning path
+
+We all have different styles of learning. If you've already got a good concept of web3 fundamentals and want to get a quick taste of what the DevEx is like on Stacks, then check out the [Developer Quickstart](get-started/developer-quickstart.md). Or find the path that clicks for you — and if bandwidth allows, tackle them all!
+
+
+
+
+
+***
+
+### Who should use what
+
+| If you are… | First check out... |
+| ----------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
+| Completely new to building with Stacks | [Developer Quickstart](get-started/developer-quickstart.md) |
+| Learning smart contract development | [Clarity Crash Course](get-started/clarity-crash-course.md), [Learn Clarinet](/broken/pages/UK5Kgh2MHLoQvfoFVnLr) |
+| Preferring a structured, guided course that shows you every step to build full-stack apps | [Stacks Developer Degree](https://learnweb3.io/degrees/stacks-developer-degree/), [Bitcoin Primer](https://app.gitbook.com/s/pJEGnyzUL9M4FaVMEB15/) |
+| Wanting to integrate sBTC in your app | [sBTC guides](more-guides/sbtc/) |
+| Launching a token | [Create Tokens](get-started/create-a-token/) |
+| Interested in security / auditing / grants | [Stacks Bug Bounties](https://immunefi.com/bug-bounty/stacks/information/), [Stacks Foundation](https://stacks.org/grants) |
+| Curious about current use cases | [Use Cases](get-started/use-cases/) |
+| Searching for a complete list of devtools | [Stacks Devtools Ecosystem](stacks-devtools-ecosystem.md) |
+
+***
+
+### Still got questions?
+
+We know, it's a lot. But we, along with our large community, are always more than welcome to help you throughout your journey with Stacks.
+
+* [**Stacks Discord**](https://discord.gg/stacks): Connect with other developers and our team
+* [**Stacks Forum**](https://forum.stacks.org/): Ask questions and share projects
+* [**Stacks Twitter**](https://x.com/StacksDevs)**:** Follow us on Twitter and ask us questions there
diff --git a/docs/build/SUMMARY.md b/docs/build/SUMMARY.md
new file mode 100644
index 0000000000..79a243112d
--- /dev/null
+++ b/docs/build/SUMMARY.md
@@ -0,0 +1,103 @@
+# Table of contents
+
+## Get Started
+
+* [Introduction](README.md)
+ * [Why Build with Stacks](get-started/introduction/why-build-with-stacks.md)
+* [Developer Quickstart](get-started/developer-quickstart.md)
+* [Clarity Crash Course](get-started/clarity-crash-course.md)
+* [Create a Token](get-started/create-a-token/README.md)
+ * [Fungible Tokens](get-started/create-a-token/fungible-tokens.md)
+ * [Non-Fungible Tokens](get-started/create-a-token/non-fungible-tokens.md)
+ * [Semi-Fungible Tokens](get-started/create-a-token/semi-fungible-tokens.md)
+* [Build a Frontend](get-started/build-a-frontend/README.md)
+ * [Authentication](get-started/build-a-frontend/authentication.md)
+ * [Post-Conditions](get-started/build-a-frontend/post-conditions.md)
+ * [Sending Transactions](get-started/build-a-frontend/sending-transactions.md)
+* [Use Cases](get-started/use-cases/README.md)
+ * [Payments](get-started/use-cases/payments.md)
+ * [Art](get-started/use-cases/art.md)
+ * [DeFi](get-started/use-cases/defi.md)
+ * [Gaming](get-started/use-cases/gaming.md)
+ * [AI](get-started/use-cases/ai.md)
+
+## What's New?
+
+* [Latest Updates](whats-new/latest-updates.md)
+
+## Learn Clarinet
+
+* [Overview](clarinet/overview.md)
+* [Quickstart](clarinet/quickstart.md)
+* [Project Structure](clarinet/project-structure.md)
+* [Project Development](clarinet/project-development.md)
+* [Contract Interaction](clarinet/contract-interaction.md)
+* [Validation and Analysis](clarinet/validation-and-analysis.md)
+* [Clarity Formatter](clarinet/clarity-formatter.md)
+* [Local Blockchain Development](clarinet/local-blockchain-development.md)
+* [Unit Testing](clarinet/testing-with-clarinet-sdk.md)
+* [Mainnet Execution Simulation](clarinet/mainnet-execution-simulation.md)
+* [Contract Deployment](clarinet/contract-deployment.md)
+* [FAQ](clarinet/faq.md)
+* [Integrations](clarinet/integrations/README.md)
+ * [Clarity VSCode Extension](clarinet/integrations/clarity-vscode-extension.md)
+ * [Chainhook Integration](clarinet/integrations/chainhook.md)
+ * [Stacks.js Integration](clarinet/integrations/stacks.js.md)
+ * [sBTC Integration](clarinet/integrations/sbtc.md)
+
+## Learn Rendezvous
+
+* [Overview](rendezvous/overview.md)
+* [Quickstart](rendezvous/quickstart.md)
+
+## Learn Stacks.js
+
+* [Overview](stacks.js/overview.md)
+* [Accounts & Addresses](stacks.js/accounts-and-addresses.md)
+* [Private Keys](stacks.js/private-keys.md)
+* [Networks](stacks.js/networks.md)
+* [Read Only Calls](stacks.js/read-only-calls.md)
+* [Build Transactions](stacks.js/build-transactions.md)
+* [Contract Calls](stacks.js/contract-calls.md)
+* [Contract Deployment](stacks.js/contract-deployment.md)
+* [Address Validation](stacks.js/address-validation.md)
+* [Encoding & Decoding](stacks.js/encoding-and-decoding.md)
+* [Network Configuration](stacks.js/network-configuration.md)
+* [Unit Conversion](stacks.js/unit-conversion.md)
+* [React Native Integration](stacks.js/react-native-integration.md)
+
+## Stacks Connect
+
+* [Connect Wallet](stacks-connect/connect-wallet.md)
+* [Broadcast Transactions](stacks-connect/broadcast-transactions.md)
+* [Message Signing](stacks-connect/message-signing.md)
+* [Migration Guide](stacks-connect/migration-guide.md)
+* [Wallet Support](stacks-connect/wallet-support.md)
+* [Wallet Implementation](stacks-connect/wallet-implementation.md)
+
+## Post-Conditions
+
+* [Overview](post-conditions/overview.md)
+* [Implementing Post-Conditions](post-conditions/implementation.md)
+
+## More Guides
+
+* [sBTC](more-guides/sbtc/README.md)
+ * [sBTC Builder Quickstart](more-guides/sbtc/sbtc-builder-quickstart.md)
+ * [Bridging Bitcoin](more-guides/sbtc/bridging-bitcoin/README.md)
+ * [Depositing: Pegging BTC into sBTC](more-guides/sbtc/bridging-bitcoin/btc-to-sbtc.md)
+ * [Withdrawing: Pegging sBTC into BTC](more-guides/sbtc/bridging-bitcoin/sbtc-to-btc.md)
+* [Price Oracles](more-guides/price-oracles/README.md)
+ * [Using Pyth with Stacks](more-guides/price-oracles/pyth.md)
+ * [Using DIA with Stacks](more-guides/price-oracles/dia.md)
+* [Onboarding](more-guides/onboarding/README.md)
+ * [Signing with Turnkey](more-guides/onboarding/signing-with-turnkey.md)
+* [Verifying Bitcoin Transactions in Clarity](more-guides/verify-bitcoin-transactions-clarity/README.md)
+ * [Creating a Bitcoin Transaction](more-guides/verify-bitcoin-transactions-clarity/creating-btc-tx.md)
+ * [Parsing a Bitcoin Transaction](more-guides/verify-bitcoin-transactions-clarity/parsing-a-bitcoin-transaction.md)
+* [c32check](more-guides/c32check.md)
+* [Community Tutorials](more-guides/community-tutorials.md)
+
+***
+
+* [Stacks Devtools Ecosystem](stacks-devtools-ecosystem.md)
diff --git a/docs/build/clarinet/clarity-formatter.md b/docs/build/clarinet/clarity-formatter.md
new file mode 100644
index 0000000000..8a0cfb218f
--- /dev/null
+++ b/docs/build/clarinet/clarity-formatter.md
@@ -0,0 +1,151 @@
+# Clarity Formatter
+
+The Clarity formatter automatically shapes your smart contract code to follow standardized style rules. Consistent formatting improves readability and makes collaboration easier across teams.
+
+## Formatting philosophy
+
+The formatter applies an opinionated standard designed to make Clarity code more readable:
+
+* **Line length** – wraps lines at 80 characters by default
+* **Indentation** – uses two spaces for consistency
+* **Structure** – enforces consistent patterns for functions, let bindings, and control flow
+
+You can customize these defaults to match your preferences.
+
+### Integration points
+
+{% stepper %}
+{% step %}
+#### Clarity VS Code Extension
+
+Format directly in the editor.
+{% endstep %}
+
+{% step %}
+#### Clarinet CLI
+
+Format via command line, including entire projects.
+{% endstep %}
+{% endstepper %}
+
+## Comparison table
+
+| Aspect | Manual formatting | Clarity formatter |
+| ----------------- | ---------------------- | --------------------------- |
+| Consistency | Varies by developer | Uniform across the codebase |
+| Speed | Time-consuming | Instant |
+| Error-prone | Yes | No |
+| Team coordination | Requires a style guide | Automatic enforcement |
+
+## Best practices
+
+* **Format on save** – enable automatic formatting in VS Code
+* **Pre-commit hooks** – ensure code is formatted before commits
+* **Team adoption** – share consistent settings with your team
+
+## Formatting rules in detail
+
+### Function definitions
+
+Functions span multiple lines with consistent indentation:
+
+```clarity
+(define-public (my-func
+ (amount uint)
+ (sender principal)
+ )
+ (ok true)
+)
+```
+
+Single arguments can remain on the first line:
+
+```clarity
+(define-read-only (get-balance (who principal))
+ (ok u0)
+)
+```
+
+### Let expressions
+
+Bindings are placed on separate lines with consistent indentation:
+
+```clarity
+(let (
+ (a u1)
+ (b u2)
+)
+ (body-expression)
+)
+```
+
+### Control flow (if, match)
+
+Each branch receives its own line:
+
+```clarity
+(if condition
+ (then-expression)
+ (else-expression)
+)
+
+(match optional-value
+ value (handle-some value)
+ (handle-none)
+)
+```
+
+### Tuples and maps
+
+The formatter automatically converts to sugared syntax with proper formatting:
+
+```clarity
+;; Input: (tuple (n1 u1) (n2 u2))
+;; Output:
+{
+ n1: u1,
+ n2: u2,
+}
+```
+
+## Usage examples
+
+### VS Code integration
+
+```json
+// settings.json
+"[clarity]": {
+ "editor.formatOnSave": true
+}
+```
+
+### CLI usage
+
+```bash
+clarinet format --in-place
+```
+
+Format with custom settings:
+
+```bash
+clarinet format -i 4 -l 120 --in-place
+```
+
+Check formatting in CI/CD pipelines:
+
+```bash
+clarinet format --check
+```
+
+The `--check` flag validates that all Clarity files are properly formatted without changing them, which is ideal for continuous integration workflows.
+
+## Ignoring blocks of code
+
+Prevent formatting for specific code blocks:
+
+```clarity
+;; @format-ignore
+(define-constant something (list
+ 1 2 3 ;; Preserves custom spacing
+ 4 5 ))
+```
diff --git a/docs/build/clarinet/contract-deployment.md b/docs/build/clarinet/contract-deployment.md
new file mode 100644
index 0000000000..76ba10123e
--- /dev/null
+++ b/docs/build/clarinet/contract-deployment.md
@@ -0,0 +1,437 @@
+# Contract Deployment
+
+Clarinet provides deployment tooling that helps you move from local development to production networks. Whether you're testing on devnet, staging on testnet, or launching on mainnet, Clarinet streamlines the process.
+
+## Generating deployment plans
+
+Deployment plans are YAML files that describe how contracts are published or called. Be sure to have a valid 24 word mnemonic seed phrase specified in the target network's `.toml` file in `settings/` and then generate a plan for any network:
+
+```bash
+$ clarinet deployments generate --testnet --medium-cost
+Analyzing contracts...
+Calculating deployment costs...
+Generating deployment plan
+Created file deployments/default.testnet-plan.yaml
+```
+
+Example output structure:
+
+{% code title="deployments/default.devnet-plan.yaml" %}
+```yaml
+---
+id: 0
+name: Devnet deployment
+network: devnet
+stacks-node: "http://localhost:20443"
+bitcoin-node: "http://devnet:devnet@localhost:18443"
+plan:
+ batches:
+ - id: 0
+ transactions:
+ - contract-publish:
+ contract-name: counter
+ expected-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
+ cost: 6940
+ path: contracts/counter.clar
+ anchor-block-only: true
+ clarity-version: 2
+ epoch: "2.5"
+```
+{% endcode %}
+
+### Deployment plan structure
+
+| Field | Description |
+| -------------- | -------------------------------------------- |
+| `id` | Unique identifier for the deployment |
+| `name` | Human-readable deployment name |
+| `network` | Target network (devnet, testnet, or mainnet) |
+| `stacks-node` | RPC endpoint for the Stacks node |
+| `bitcoin-node` | RPC endpoint for the Bitcoin node |
+| `plan.batches` | Array of deployment batches |
+
+### Deployment specifications
+
+Deployment behavior is configured in two places:
+
+* **Project configuration (`Clarinet.toml`)** – Clarity versions, dependencies, epoch requirements
+* **Network configuration (`settings/.toml`)** – Account details, balances, endpoints
+
+Example network configuration:
+
+{% code title="settings/Testnet.toml" %}
+```toml
+[network]
+name = "testnet"
+deployment_fee_rate = 10
+
+[accounts.deployer]
+mnemonic = ""
+balance = 100_000_000_000_000
+derivation = "m/44'/5757'/0'/0/0"
+```
+{% endcode %}
+
+## Working with contract requirements
+
+Reference contracts that already exist on-chain—useful for standardized traits.
+
+### Adding requirements
+
+```bash
+clarinet requirements add SP2PABAF9FTAJYNFZH93XENAJ8FVY99RRM50D2JG9.nft-trait
+```
+
+Clarinet updates your configuration automatically:
+
+```toml
+[project]
+name = "my-nft-project"
+requirements = [
+ { contract_id = "SP2PABAF9FTAJYNFZH93XENAJ8FVY99RRM50D2JG9.nft-trait" }
+]
+```
+
+During deployment Clarinet downloads the contract, remaps the principal for devnet, and ensures the requirement is available before your contracts deploy.
+
+## Deploying to different networks
+
+### Devnet
+
+Devnet deploys contracts automatically when it starts:
+
+```bash
+clarinet devnet start
+```
+
+To deploy manually against a running devnet:
+
+```bash
+clarinet deployments apply --devnet
+```
+
+See [local development](local-blockchain-development.md) for more devnet configuration tips.
+
+### Testnet
+
+{% hint style="info" %}
+Prerequisites:
+
+* Request testnet STX from the faucet
+* Configure your account in `settings/Testnet.toml`
+* Validate contracts with `clarinet check`
+{% endhint %}
+
+Generate a deployment plan with cost estimation:
+
+```bash
+clarinet deployments generate --testnet --medium-cost
+```
+
+Deploy to testnet:
+
+```bash
+clarinet deployments apply --testnet
+```
+
+### Mainnet
+
+{% hint style="warning" %}
+Mainnet checklist
+{% endhint %}
+
+{% stepper %}
+{% step %}
+Finish thorough testing on testnet
+{% endstep %}
+
+{% step %}
+Audit contracts for security
+{% endstep %}
+
+{% step %}
+Ensure sufficient STX for fees
+{% endstep %}
+
+{% step %}
+Back up deployment keys securely
+{% endstep %}
+
+{% step %}
+Prefer a hardware wallet for deployment
+{% endstep %}
+{% endstepper %}
+
+Create a mainnet plan:
+
+```bash
+clarinet deployments generate --mainnet --high-cost
+```
+
+Deploy with confirmation:
+
+```bash
+clarinet deployments apply --mainnet
+```
+
+## Cost estimation and optimization
+
+Choose the right fee level for your deployment:
+
+```bash
+clarinet deployments generate --testnet --manual-cost
+```
+
+Fee options:
+
+* `--low-cost` – minimize fees, slower confirmation
+* `--medium-cost` – balanced approach
+* `--high-cost` – priority inclusion
+* `--manual-cost` – interactive selection
+
+Analyze costs before deploying:
+
+```bash
+clarinet deployments generate --testnet --medium-cost
+```
+
+## Advanced deployment configurations
+
+### Multi-batch deployments
+
+Deploy complex systems with batches:
+
+{% code title="" %}
+```yaml
+plan:
+ batches:
+ - id: 0
+ transactions:
+ - contract-publish:
+ contract-name: trait-definitions
+ path: contracts/traits.clar
+ clarity-version: 2
+ - id: 1
+ transactions:
+ - contract-publish:
+ contract-name: token
+ path: contracts/token.clar
+ - contract-publish:
+ contract-name: oracle
+ path: contracts/oracle.clar
+ - id: 2
+ transactions:
+ - contract-publish:
+ contract-name: defi-pool
+ path: contracts/defi-pool.clar
+```
+{% endcode %}
+
+Batches guarantee that dependencies deploy first, allow parallel transactions within a batch, and run batches sequentially.
+
+### Transaction types
+
+Deployment plans support different transaction types:
+
+| Transaction type | Description |
+| ------------------- | ------------------------------------------------------------------- |
+| Contract operations | Publish or call contracts, specifying sender, cost, and source path |
+| Asset transfers | Transfer STX or BTC by setting sender, recipient, and amounts |
+
+**Contract operations**
+
+```yaml
+- contract-publish:
+ contract-name: my-contract
+ expected-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
+ cost: 5960
+ path: contracts/my-contract.clar
+ clarity-version: 2
+
+- contract-call:
+ contract-id: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.my-contract
+ expected-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
+ method: initialize
+ parameters:
+ - u1000000
+ - "Token Name"
+ cost: 5960
+```
+
+**Asset transfers**
+
+```yaml
+- stx-transfer:
+ expected-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
+ recipient: ST2CY5V39NHDPWSXMW9QDT3HC3GD6Q6XX4CFRK9AG
+ mstx-amount: 1000000
+ memo: '0x48656c6c6f'
+
+- btc-transfer:
+ expected-sender: mjSrB3wS4xab3kYqFktwBzfTdPg367ZJ2d
+ recipient: bcrt1qnxknq3wqtphv7sfwy07m7e4sr6ut9yt6ed99jg
+ sats-amount: 100000000
+ sats-per-byte: 10
+```
+
+### Manual customization
+
+You can edit deployment plans for complex scenarios.
+
+{% hint style="info" %}
+Manual edits
+
+When Clarinet prompts to overwrite your plan, answer `no` to keep custom changes.
+{% endhint %}
+
+Example contract initialization batch:
+
+```yaml
+- id: 3
+ transactions:
+ - contract-call:
+ contract-id: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.token
+ method: initialize
+ parameters:
+ - u1000000
+ - { name: "My Token", symbol: "MTK", decimals: u6 }
+ expected-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
+```
+
+### Encrypted mnemonics
+
+`clarinet 3.11.0` contains support for encrypted mnemonics. This feature gives users the option to encrypt the mnemonic seed phrase in their deployment files, so if a user's machine is compromised by a filesystem reading vulnerability, the seed phrase is not leaked to the attacker.
+
+To use this feature, a user must first run `clarinet deployments encrypt`, which will prompt the user for the seed phrase and a password, then print the encrypted mnemonic to the console. The user can then put the resulting ciphertext into their deployment config file using the key `encrypted_mnemonic`. The next time the user runs `clarinet deployments apply`, they will be prompted for the password, and the mnemonic will be decrypted for use in that session.
+
+For example, if your `settings/Mainnet.toml` file looks like this:
+
+{% code title="settings/Mainnet.toml" %}
+```toml
+[network]
+name = "mainnet"
+stacks_node_rpc_address = "https://api.hiro.so"
+deployment_fee_rate = 10
+
+[accounts.deployer]
+mnemonic = "twice kind fence tip hidden tilt action fragile skin nothing glory cousin green tomorrow spring wrist shed math olympic multiply hip blue scout claw"
+```
+{% endcode %}
+
+You would then run:
+
+{% code title="terminal" %}
+```
+user@host package % clarinet deployments encrypt
+Enter mnemonic to encrypt:
+twice kind fence tip hidden tilt action fragile skin nothing glory cousin green tomorrow spring wrist shed math olympic multiply hip blue scout claw
+Enter password:
+
+encrypted_mnemonic = ""
+```
+{% endcode %}
+
+You would then replace the `mnemonic` field in your settings file with the `encrypted_mnemonic` output above:
+
+{% code title="settings/Mainnet.toml" %}
+```toml
+[accounts.deployer]
+encrypted_mnemonic = "47hYHSp4gtoBabz4X8cByJtRbvD3tBemS1zZJTkxYh2LJ7cVAHY6z74Td8bF5Dcsdpv45gDELPwfBP8Mfk64Q8TsBJNU9sf5hWMrTKPtr5h9abSdmxu4m2BewbUCi4o8znn42nAd7yphcb345YCrYLJFqFC7k9LqXvxgbQxUiFpWeyTVJPkGFa3aiQ8G5uhrv7pLCer4kRmXsmXbBvEqwEQLG7eM3TUMzUP79mHqJ1HGe2XWn"
+```
+{% endcode %}
+
+Then the next time you deploy your package, you will be prompted for the password:
+
+{% code title="terminal" %}
+```
+user@host package % clarinet deployments apply --mainnet
+
+Enter password to decrypt mnemonic for account deployer:
+```
+{% endcode %}
+
+## Common issues
+
+### Insufficient STX balance
+
+**Error**: “Insufficient STX balance for deployment”
+
+Solutions:
+
+{% stepper %}
+{% step %}
+Request testnet STX from the faucet
+{% endstep %}
+
+{% step %}
+Reduce the fee rate with `--low-cost`
+{% endstep %}
+
+{% step %}
+Check your balance:
+
+```bash
+clarinet console --testnet
+stx-account 'ST2CY5V39NHDPWSXMW9QDT3HC3GD6Q6XX4CFRK9AG
+```
+{% endstep %}
+{% endstepper %}
+
+### Contract already exists
+
+**Error**: “Contract `token` already deployed at this address”
+
+Solutions:
+
+{% stepper %}
+{% step %}
+Use a different contract name
+{% endstep %}
+
+{% step %}
+Deploy from another address
+{% endstep %}
+
+{% step %}
+On testnet, switch to a fresh account
+{% endstep %}
+{% endstepper %}
+
+### Network connection failures
+
+**Error**: “Failed to connect to testnet node”
+
+Check your network settings:
+
+```toml
+[network]
+name = "testnet"
+node_rpc_address = "https://stacks-node-api.testnet.stacks.co"
+```
+
+Alternative endpoints:
+
+* Hiro: `https://api.testnet.hiro.so`
+* Your own node
+
+Debug the connection:
+
+```bash
+curl -I https://api.testnet.hiro.so/v2/info
+```
+
+### Invalid deployment plan
+
+**Common YAML errors**
+
+* Incorrect indentation
+* Missing required fields
+* Invalid contract paths
+
+Validate and regenerate as needed:
+
+```bash
+clarinet deployments check
+clarinet deployments generate --testnet
+ls contracts/
+```
diff --git a/docs/build/clarinet/contract-interaction.md b/docs/build/clarinet/contract-interaction.md
new file mode 100644
index 0000000000..c34d27116d
--- /dev/null
+++ b/docs/build/clarinet/contract-interaction.md
@@ -0,0 +1,178 @@
+# Contract Interaction
+
+Clarinet provides powerful tools for interacting with your contracts during development. The console gives you an interactive REPL where you can call functions, inspect state, and debug issues in real time. This interactive REPL environment in the console is also referred to as the simnet.
+
+
+
+What is a simnet?
+
+* Simnet is a lightweight environment optimized for fast feedback loops, introspection and portability.
+* Simnet focuses on letting you quickly iterate on your code and test the code of the contract itself through unit testing. It’s a good preliminary debugging step before introducing the additional variables that come with a fully-fledged blockchain environment.
+* Simnet enables you to create a bunch of reports about contract analysis, execution costs, and more and is a useful tool for unit testing your smart contracts.
+* In simnet, the blockchain environment is simulated and can be run anywhere (in the terminal with clarinet console, web browsers, GitHub actions, etc).
+
+
+
+## Starting the console
+
+Use `clarinet console` to launch an interactive session with your contracts deployed to a local simulated blockchain REPL. This is also referred to as simnet.
+
+```bash
+clarinet console
+```
+
+Sample startup output:
+
+```
+clarity-repl v3.3.0
+Enter "::help" for usage hints.
+Connected to a transient in-memory database.
+```
+
+The console supports several useful flags for different development scenarios:
+
+| Option | Description |
+| --------------------------------------- | ----------------------------------------------------- |
+| `--enable-remote-data` | Connect to mainnet or testnet to query real contracts |
+| `--deployment-plan-path ` | Use a specific deployment plan |
+| `--manifest-path ` | Use an alternate `Clarinet.toml` location |
+| `--remote-data-api-url ` | Specify a custom Stacks API endpoint |
+| `--remote-data-initial-height ` | Set the starting block height for remote data |
+
+## Working with remote data
+
+One of the most powerful features is the ability to interact with real mainnet or testnet contracts from your local console. This lets you test against actual deployed contracts:
+
+```bash
+clarinet console --enable-remote-data
+```
+
+Example contract calls:
+
+```clarity
+(contract-call? 'SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token get-decimals)
+;; (ok u8)
+
+(contract-call? 'SP2C2YFP12AJZB4MABJBAJ55XECVS7E4PMMZ89YZR.arkadiko-token get-name)
+;; (ok "Arkadiko Token")
+```
+
+These capabilities help you:
+
+* Test integrations with existing protocols
+* Verify contract behavior against live chain state
+* Develop contracts that depend on mainnet deployments
+
+> **Warning: Remote data requirements**
+>
+> Before using remote data, add the target contract to `Clarinet.toml` with `clarinet requirements add SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token`.
+
+### Using the Hiro API key
+
+Avoid rate limits by setting the `HIRO_API_KEY` environment variable before launching the console. Clarinet forwards this key in the `x-api-key` header for all requests:
+
+```bash
+export HIRO_API_KEY=your_api_key_here
+clarinet console --enable-remote-data
+```
+
+You can request a free API key from the Hiro Platform.
+
+### Working with contracts
+
+List all available contracts in the session:
+
+```clarity
+::get_contracts
+;; +---------------------------------------------------------+----------------------+
+;; | Contract identifier | Public functions |
+;; |---------------------------------------------------------+----------------------|
+;; | ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.counter | (count-up) |
+;; | | (get-count (who ...))|
+;; +---------------------------------------------------------+----------------------+
+
+(contract-call? .counter count-up)
+;; (ok true)
+
+(contract-call? .counter get-count tx-sender)
+;; u1
+```
+
+### Working with different principals
+
+Switch between the provided test wallets to validate multi-user flows:
+
+```clarity
+::get_assets_maps
+;; +-------------------------------------------+-----------------+
+;; | Address | uSTX |
+;; |-------------------------------------------+-----------------|
+;; | ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM | 100000000000000 |
+;; | ST1SJ3DTE5DN7X54YDH5D64R3BCB6A2AG2ZQ8YPD5 | 100000000000000 |
+;; ...
+
+::set_tx_sender ST1SJ3DTE5DN7X54YDH5D64R3BCB6A2AG2ZQ8YPD5
+;; tx-sender switched to ST1SJ3DTE5DN7X54YDH5D64R3BCB6A2AG2ZQ8YPD5
+```
+
+### Working with block heights
+
+Advance the chain to test time-dependent logic:
+
+```clarity
+::get_block_height
+;; Current block height: 4
+
+::advance_chain_tip 100
+;; new burn height: 3
+;; new stacks height: 104
+
+::get_block_height
+;; Current block height: 104
+```
+
+> **Tip: Console reference**
+>
+> For a complete list of console commands, see the [CLI reference](../../reference/clarinet/cli-reference.md).
+
+## Common issues
+
+
+
+Contract not found errors
+
+If you see `use of unresolved contract` errors, the contract may not be deployed or the name might be incorrect:
+
+```clarity
+(contract-call? .missing-contract get-value)
+;; error: use of unresolved contract
+```
+
+Solutions:
+
+* Check for typos in the contract identifier
+* Confirm the contract is deployed in the current session with `::get_contracts`
+* Use the correct prefix (`.` for local contracts)
+
+
+
+
+
+Remote data connection issues
+
+When you enable remote data, rate limits or connectivity problems can occur:
+
+```clarity
+(contract-call? 'SP2C2YFP12AJZB4MABJBAJ55XECVS7E4PMMZ89YZR.arkadiko-token get-name)
+;; error: API rate limit exceeded
+```
+
+**Solutions:**
+
+1. Set your Hiro API key: `export HIRO_API_KEY=your_key_here`
+2. Use a custom API endpoint: `--remote-data-api-url https://your-node.com`
+3. Wait for rate limit to reset (usually 1 minute)
+
+
+
+##
diff --git a/docs/build/clarinet/faq.md b/docs/build/clarinet/faq.md
new file mode 100644
index 0000000000..9828aff908
--- /dev/null
+++ b/docs/build/clarinet/faq.md
@@ -0,0 +1,190 @@
+# FAQ
+
+Common questions and solutions for Clarinet development.
+
+This page addresses common issues encountered when building with Clarinet, based on community feedback and support interactions.
+
+
+
+How do I test with sBTC tokens in my development environment?
+
+To test with sBTC tokens, add the mainnet sBTC contract as a requirement and mint tokens using the deployer address.
+
+* Add sBTC as a requirement:\
+ `clarinet requirements add SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token`
+* Mint sBTC in your tests\
+ // The sBTC multisig address that can mint\
+ `const sbtcDeployer = "SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4";`\
+ // Mint sBTC to your test wallet\
+ `const mintTx = simnet.callPublicFn( "SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token", "mint", [Cl.uint(1000000), Cl.principal(wallet1)], sbtcDeployer);`\
+ \
+ This approach lets you work with sBTC in unit tests without complex Bitcoin transaction simulation.
+
+
+
+
+
+Why am I getting an error when using mainnet addresses during mainnet simulation?
+
+When you run mainnet execution simulation, the target contract may expect mainnet addresses instead of the default testnet wallets. As of Clarinet v3.4.0, you can enable mainnet wallets in simnet with `use_mainnet_wallets = true`:
+
+```toml
+[repl.remote_data]
+enabled = true
+initial_height = 522000
+use_mainnet_wallets = true
+```
+
+If you prefer to manage addresses manually, skip `simnet.getAccounts()` and use the specific mainnet principals you need:
+
+```ts
+// Instead of using simnet.getAccounts()
+const mainnetAddress = "SP3R4F6C1J3JQWWCVZ3S7FRRYPMYG6ZW6RZK31FXY";
+
+// Mint STX to any mainnet address
+simnet.mintSTX(mainnetAddress, 1000000n);
+
+// Call functions with a mainnet address
+const result = simnet.callReadOnlyFn(
+ "SP3R4F6C1J3JQWWCVZ3S7FRRYPMYG6ZW6RZK31FXY.pyth-storage-v3",
+ "get-price",
+ [priceFeed],
+ mainnetAddress
+);
+```
+
+The simnet accepts any valid Stacks address when mainnet simulation is enabled.
+
+
+
+
+
+How do I migrate from expectSTXTransferEvent to the new SDK?
+
+Clarinet v2 relies on standard Vitest matchers instead of the legacy event helpers.
+
+Old approach (Clarinet v1):
+
+```ts
+block.receipts[0].events.expectSTXTransferEvent(
+ amount,
+ sender,
+ recipient
+);
+```
+
+New approach (Clarinet v2):
+
+```ts
+// Check for an exact event match
+expect(events).toContainEqual({
+ event: "stx_transfer_event",
+ data: {
+ amount: "1000000",
+ memo: "",
+ recipient: "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM",
+ sender: "ST1SJ3DTE5DN7X54YDH5D64R3BCB6A2AG2ZQ8YPD5",
+ },
+});
+
+// Or assert specific properties only
+expect(events).toContainEqual({
+ event: "stx_transfer_event",
+ data: expect.objectContaining({
+ sender: address1,
+ recipient: contractAddress,
+ }),
+});
+```
+
+For Clarity value assertions, use the built-in matchers:
+
+```ts
+expect(result).toBeOk(Cl.bool(true));
+expect(result).toBeErr(Cl.uint(500));
+```
+
+
+
+
+
+Why am I getting "bip39 error" when generating deployment plans?
+
+Starting with Clarinet 2.15.0, deployment configurations require 24-word mnemonics. Twelve-word mnemonics are no longer supported.
+
+Update your configuration with a full 24-word phrase:
+
+```toml
+[accounts.deployer]
+
+# Use a 24-word mnemonic
+mnemonic = "twice kind fence tip hidden tilt action fragile skin nothing glory cousin green tomorrow spring wrist shed math olympic multiply hip blue scout claw"
+```
+
+Generate a new 24-word mnemonic using a BIP39 generator if needed. The longer phrase improves security for production deployments.
+
+
+
+
+
+Can I test Bitcoin transaction verification in Clarinet?
+
+Testing contracts that use `clarity-bitcoin-lib` for Bitcoin transaction verification has limitations in simnet and devnet environments.
+
+Current limitations:
+
+* No real Bitcoin blocks or transactions in simnet
+* Mock blocks do not contain verifiable Bitcoin transactions
+* `get-burn-block-info?` returns mock data unsuitable for verification
+
+Workarounds:
+
+* Test Bitcoin verification logic on mainnet or with mainnet execution simulation
+* Write unit tests that mock expected behavior instead of full verification
+* Consider separating Bitcoin verification logic so it can be tested independently
+
+The Clarinet team continues to investigate better support for Bitcoin-focused testing.
+
+
+
+
+
+Why does my devnet freeze at the epoch 3.0 transition?
+
+The epoch 3.0 transition in devnet can be unstable, with success rates between 50–80% depending on your setup.
+
+Temporary workarounds:
+
+* Restart devnet if it freezes around blocks 139–140
+* Try Clarinet 2.14.0, which some users report as more stable
+* Watch for the upcoming feature to start devnet directly in epoch 3.0
+
+You can also monitor the transition manually:
+
+```
+# Watch for the transition around these blocks
+Block 139: Epoch 2.5
+Block 140: Should transition to 3.0
+```
+
+The Clarinet team is working on improving epoch transition stability and plans to allow starting devnet in epoch 3.0.
+
+
+
+
+
+What's the difference between simnet and devnet?
+
+A simnet is a lightweight environment optimized for fast feedback loops, introspection and portability. The scenarios you would use simnet would be during Clarinet console interaction, unit testing, and execution costs reporting.
+
+A devnet refers to a local blockchain development environment in which your smart contracts and front end application can interact with simulated blockchain entities. The scenarios you would use devnet is during your front end development, interaction with web wallets, and creating custom blockchain configurations for testing.
+
+| | Simnet | Devnet |
+| ------------------- | ------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------- |
+| Testing Scope | good for unit/integration tests | good for end to end testing with deployment, real multi-contract interactions with wallets, web interactions, etc |
+| State Persistence | no persistent state, resets with each run | persistent state, can retain data across sessions |
+| Network Behavior | does not simulate real network behavior (ie you control block heights and mining manually) | simulates network behavior automatically like block progress, txs, etc |
+| Consensus Mechanism | not applicable, operates in a simulated context | can implement and test against consensus rules |
+| Transaction Fees | no tx fees or gas | can simulate these in real world scenarios |
+
+
diff --git a/docs/build/clarinet/integrations/README.md b/docs/build/clarinet/integrations/README.md
new file mode 100644
index 0000000000..f996ed9ff2
--- /dev/null
+++ b/docs/build/clarinet/integrations/README.md
@@ -0,0 +1,5 @@
+# Integrations
+
+Explore powerful external tools and resources you can integrate into your Clarity smart contract workflow with Clarinet to level up your development experience.
+
+
diff --git a/docs/build/clarinet/integrations/chainhook.md b/docs/build/clarinet/integrations/chainhook.md
new file mode 100644
index 0000000000..a341bb858c
--- /dev/null
+++ b/docs/build/clarinet/integrations/chainhook.md
@@ -0,0 +1,160 @@
+# Chainhook Integration
+
+Learn how to register Chainhooks on Clarinet devnet so you can monitor smart contract events during local development.
+
+## What you'll learn
+
+* Create Chainhook predicate files for event monitoring
+* Register Chainhooks with Clarinet devnet
+* Monitor contract calls and blockchain events
+* Set up webhooks for real-time notifications
+
+{% hint style="info" %}
+Prerequisites
+
+* Clarinet `2.1.0` or later (`clarinet --version`)
+* Node.js `16` or later (`node --version`)
+{% endhint %}
+
+## Quickstart
+
+{% stepper %}
+{% step %}
+#### Create your Chainhook predicates
+
+Create predicate files in a `chainhooks/` directory alongside your contracts:
+
+* contracts/
+ * counter.clar
+* chainhooks/
+ * increment.json
+ * decrement.json
+* tests/
+ * counter.test.ts
+* Clarinet.toml
+
+Example predicate for monitoring increment events:
+
+{% code title="chainhooks/increment.json" %}
+```json
+{
+ "chain": "stacks",
+ "uuid": "increment-hook",
+ "name": "Increment Counter Hook",
+ "version": 1,
+ "networks": {
+ "devnet": {
+ "if_this": {
+ "scope": "contract_call",
+ "contract_identifier": "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.counter",
+ "method": "increment"
+ },
+ "then_that": {
+ "http_post": {
+ "url": "http://localhost:3000/api/increment",
+ "authorization_header": "Bearer my-secret"
+ }
+ }
+ }
+ }
+}
+```
+{% endcode %}
+{% endstep %}
+
+{% step %}
+#### Start devnet with Chainhooks
+
+From your project root, start devnet. Clarinet registers every predicate automatically:
+
+{% code title="Start devnet" %}
+```bash
+clarinet devnet start
+```
+{% endcode %}
+
+Check the logs for a confirmation message such as:
+
+{% code title="Clarinet log" %}
+```
+INFO Feb 5 15:20:07.233382 2 chainhooks registered
+```
+{% endcode %}
+{% endstep %}
+
+{% step %}
+#### Monitor Chainhook activity
+
+Trigger contract actions and watch for Chainhook alerts:
+
+{% code title="Clarinet log" %}
+```
+INFO Feb 5 15:21:07.233382 1 hooks triggered
+```
+{% endcode %}
+
+Verify the payload based on your `then_that` configuration:
+
+* `http_post` – confirm your endpoint received the POST request
+* `file_append` – ensure the file was created or updated
+{% endstep %}
+{% endstepper %}
+
+## Common patterns
+
+### Contract deployment hook
+
+Monitor when specific contracts are deployed:
+
+{% code title="chainhooks/deploy.json" %}
+```json
+{
+ "chain": "stacks",
+ "uuid": "deploy-hook",
+ "name": "Contract Deploy Monitor",
+ "version": 1,
+ "networks": {
+ "devnet": {
+ "if_this": {
+ "scope": "contract_deployment",
+ "deployer": "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM"
+ },
+ "then_that": {
+ "file_append": {
+ "path": "./deployments.log"
+ }
+ }
+ }
+ }
+}
+```
+{% endcode %}
+
+### STX transfer monitoring
+
+Track STX transfers above a certain threshold:
+
+{% code title="chainhooks/stx-transfer.json" %}
+```json
+{
+ "chain": "stacks",
+ "uuid": "stx-transfer-hook",
+ "name": "Large STX Transfer Monitor",
+ "version": 1,
+ "networks": {
+ "devnet": {
+ "if_this": {
+ "scope": "stx_event",
+ "actions": ["transfer"],
+ "amount_upper_bound": "1000000000000"
+ },
+ "then_that": {
+ "http_post": {
+ "url": "http://localhost:3000/api/large-transfer"
+ }
+ }
+ }
+ }
+}
+```
+{% endcode %}
diff --git a/docs/build/clarinet/integrations/clarity-vscode-extension.md b/docs/build/clarinet/integrations/clarity-vscode-extension.md
new file mode 100644
index 0000000000..006aa8a034
--- /dev/null
+++ b/docs/build/clarinet/integrations/clarity-vscode-extension.md
@@ -0,0 +1,126 @@
+# VSCode Extension
+
+{% hint style="info" %}
+The [VSCode extension](https://marketplace.visualstudio.com/items?itemName=StacksLabs.clarity-stacks) for Clarity is now published under the Stacks Labs organization.
+{% endhint %}
+
+## Features
+
+### Smart auto-completion
+
+The extension provides intelligent code completion that understands Clarity's context. When you start typing any Clarity function, you get instant suggestions with documentation:
+
+```clarity
+;; Type "stx-tr" and get:
+(stx-transfer? amount sender recipient)
+;; ^ ^ ^
+;; Placeholders for easy navigation
+```
+
+Use `Tab` to jump between placeholders and `Escape` to exit placeholder mode.
+
+### Documentation on hover
+
+Access comprehensive documentation without leaving your editor. Hover over any Clarity function or keyword to see:
+
+```clarity
+;; Hover over 'map-set' to see:
+;; - Function signature
+;; - Parameter descriptions
+;; - Return type
+;; - Usage examples
+(map-set my-map {key: "value"} "data")
+```
+
+### Go-to definition
+
+Navigate your codebase efficiently with jump-to-definition features:
+
+* `F12` or `Ctrl+Click` - Go to definition
+* `Alt+F12` - Peek definition without leaving current file
+* Works across contract files and contract calls
+
+### Real-time error checking
+
+The extension validates your code continuously, providing immediate feedback:
+
+* **Red squiggles** - Syntax errors, unknown keywords
+* **Yellow squiggles** - Warnings for potentially unsafe code
+* **Error list** - All issues in the Problems panel (`Ctrl+Shift+M`)
+
+Common errors caught include undefined variables, type mismatches, missing trait implementations, and invalid function signatures.
+
+### Local contract resolution
+
+Auto-completion works across your entire project. Reference functions from other contracts in your workspace:
+
+```clarity
+;; Auto-complete local contract calls
+(contract-call? .my-token transfer amount sender recipient)
+;; ^
+;; Suggests contracts in your project
+```
+
+### Trait support
+
+When implementing traits (like SIP-009 NFTs or SIP-010 tokens), the extension verifies:
+
+* All required functions are implemented
+* Function signatures match trait definitions
+* Return types are correct
+
+```clarity
+;; Extension warns if missing required trait functions
+(impl-trait .sip-010-trait.sip-010-trait)
+
+;; ⚠️ Warning: Missing required function 'get-balance'
+```
+
+### Visual debugging
+
+{% stepper %}
+{% step %}
+**Set breakpoints**
+
+Set breakpoints by clicking line numbers in the editor.
+{% endstep %}
+
+{% step %}
+**Start debugging**
+
+Press `F5` or use Run → Start Debugging to begin a debugging session.
+{% endstep %}
+
+{% step %}
+**Step through code**
+
+Step through code line-by-line to follow execution.
+{% endstep %}
+
+{% step %}
+**Inspect state**
+
+Inspect variables and stack state while paused at breakpoints.
+{% endstep %}
+{% endstepper %}
+
+{% hint style="warning" %}
+Visual debugging requires VS Code Desktop and Clarinet installed locally.
+{% endhint %}
+
+## Comparison table
+
+| Feature | Basic Editor | VS Code Extension |
+| --------------------- | --------------- | ----------------------- |
+| Syntax highlighting | Limited | Full Clarity support |
+| Auto-completion | None | Context-aware with docs |
+| Error checking | On deploy only | Real-time validation |
+| Documentation | External lookup | Inline hover docs |
+| Debugging | Console only | Visual debugger |
+| Cross-file navigation | Manual | Jump to definition |
+
+***
+
+### Additional Resources
+
+* \[[zed.dev](https://zed.dev/extensions?query=clarity)] Zed extension for Clarity
diff --git a/docs/build/clarinet/integrations/sbtc.md b/docs/build/clarinet/integrations/sbtc.md
new file mode 100644
index 0000000000..fe3d163238
--- /dev/null
+++ b/docs/build/clarinet/integrations/sbtc.md
@@ -0,0 +1,225 @@
+# sBTC Integration
+
+source: Hiro blog
+
+Clarinet can automatically wire up the official sBTC contracts so you can build and test SIP-010 flows locally.
+
+## What you'll learn
+
+* Add sBTC smart contracts to your Clarinet project
+* Test contracts with automatic sBTC funding in devnet
+* Work with sBTC as a SIP-010 fungible token
+* Deploy sBTC contracts to testnet and mainnet
+
+## Prerequisites
+
+* Clarinet 2.15.0 or later required for automatic sBTC integration.
+
+## Quickstart
+
+{% stepper %}
+{% step %}
+**Add sBTC to your project**
+
+Add the sBTC contracts to your project requirements:
+
+```bash
+clarinet requirements add SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-deposit
+```
+
+This pulls in:
+
+* `sbtc-token` – SIP-010 fungible token contract
+* `sbtc-registry` – configuration registry
+* `sbtc-deposit` – deposit and withdrawal logic
+
+Clarinet auto-funds devnet wallets with sBTC when these are present.
+{% endstep %}
+
+{% step %}
+**Create an sBTC-enabled contract**
+
+Example NFT marketplace that accepts sBTC payments:
+
+```clarity
+(define-non-fungible-token marketplace-nft uint)
+(define-data-var mint-price uint u100)
+(define-data-var next-id uint u0)
+
+(define-public (mint-with-sbtc)
+ (begin
+ (try! (contract-call? 'SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token transfer
+ (var-get mint-price)
+ tx-sender
+ (as-contract tx-sender)
+ none))
+ (try! (nft-mint? marketplace-nft (var-get next-id) tx-sender))
+ (ok (var-set next-id (+ (var-get next-id) u1)))
+ )
+)
+
+(define-read-only (get-sbtc-balance (owner principal))
+ (contract-call? 'SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token get-balance owner)
+)
+```
+{% endstep %}
+
+{% step %}
+**Test in the Clarinet console**
+
+Launch the console and try the contract using auto-funded wallets:
+
+```bash
+clarinet console
+```
+
+```clarity
+(contract-call? .nft-marketplace get-sbtc-balance tx-sender)
+(contract-call? .nft-marketplace mint-with-sbtc)
+(nft-get-owner? .nft-marketplace marketplace-nft u0)
+```
+{% endstep %}
+
+{% step %}
+**Write unit tests**
+
+Sample Vitest test for sBTC payments:
+
+```ts
+import { describe, expect, it } from 'vitest';
+import { Cl } from '@stacks/transactions';
+
+describe('NFT Marketplace', () => {
+ it('mints NFT with sBTC payment', () => {
+ const accounts = simnet.getAccounts();
+ const wallet1 = accounts.get('wallet_1')!;
+
+ const initial = simnet.callReadOnlyFn(
+ 'nft-marketplace',
+ 'get-sbtc-balance',
+ [Cl.standardPrincipal(wallet1.address)],
+ wallet1.address
+ );
+
+ const mint = simnet.callPublicFn(
+ 'nft-marketplace',
+ 'mint-with-sbtc',
+ [],
+ wallet1
+ );
+
+ expect(mint.result).toBeOk();
+
+ const final = simnet.callReadOnlyFn(
+ 'nft-marketplace',
+ 'get-sbtc-balance',
+ [Cl.standardPrincipal(wallet1.address)],
+ wallet1.address
+ );
+
+ expect(Number(Cl.parse(final.result))).toBeLessThan(
+ Number(Cl.parse(initial.result))
+ );
+ });
+});
+```
+{% endstep %}
+
+{% step %}
+**Deploy to testnet**
+
+Generate a plan to confirm remapped addresses for official sBTC contracts:
+
+```bash
+clarinet deployments generate --testnet
+```
+
+Deploy when ready:
+
+```bash
+clarinet deployments apply --testnet
+```
+{% endstep %}
+{% endstepper %}
+
+## Common patterns
+
+### Working with sBTC addresses
+
+Clarinet handles sBTC contract address mapping across networks:
+
+| Network | sBTC Contract Address |
+| ------------- | ------------------------------------------------------ |
+| Simnet/Devnet | `SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token` |
+| Testnet | `ST1F7QA2MDF17S807EPA36TSS8AMEFY4KA9TVGWXT.sbtc-token` |
+| Mainnet | Contract address remains unchanged |
+
+Your contract code always references the simnet address. Clarinet automatically remaps during deployment.
+
+## Manual sBTC minting in unit tests
+
+While Clarinet 2.15.0+ automatically funds wallets with sBTC in devnet, you may need to manually mint sBTC in unit tests for specific scenarios.
+
+### Minting sBTC using the deployer address
+
+The sBTC token contract allows the deployer (multisig) address to mint tokens. Use this approach in your tests:
+
+```ts
+import { describe, expect, it } from "vitest";
+import { Cl } from "@stacks/transactions";
+
+describe("Manual sBTC minting", () => {
+ it("mints sBTC to custom addresses", () => {
+ // The sBTC multisig address that can mint
+ const sbtcDeployer = "SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4";
+ const customWallet = "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM";
+
+ // Mint 1000 sats to custom wallet
+ const mintResult = simnet.callPublicFn(
+ "SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token",
+ "mint",
+ [
+ Cl.uint(1000), // amount in sats
+ Cl.principal(customWallet) // recipient
+ ],
+ sbtcDeployer // sender must be deployer
+ );
+
+ expect(mintResult.result).toBeOk(Cl.bool(true));
+
+ // Verify balance
+ const balance = simnet.callReadOnlyFn(
+ "SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token",
+ "get-balance",
+ [Cl.principal(customWallet)],
+ customWallet
+ );
+
+ expect(balance.result).toBeOk(Cl.uint(1000));
+ });
+});
+```
+
+### Testing with mainnet execution simulation
+
+When using mainnet execution simulation, you can mint sBTC using the actual mainnet multisig:
+
+```ts
+const mainnetMultisig = "SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4";
+const mainnetWallet = "SP2C2YFP12AJZB4MABJBAJ55XECVS7E4PMMZ89YZR";
+
+// Mint sBTC to any mainnet address
+simnet.callPublicFn(
+ "SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token",
+ "mint",
+ [Cl.uint(100000), Cl.principal(mainnetWallet)],
+ mainnetMultisig
+);
+```
+
+This approach is useful for:
+
+* Testing specific sBTC amounts
+* Simulating different wallet balances
+* Testing edge cases with precise token amounts
+* Integration testing with mainnet contracts
diff --git a/docs/build/clarinet/integrations/stacks.js.md b/docs/build/clarinet/integrations/stacks.js.md
new file mode 100644
index 0000000000..80843af077
--- /dev/null
+++ b/docs/build/clarinet/integrations/stacks.js.md
@@ -0,0 +1,212 @@
+# Stacks.js Integration
+
+Use Stacks.js to interact with your Clarinet devnet from JavaScript applications.
+
+## What you'll learn
+
+* Configure Stacks.js for a local devnet connection
+* Make STX transfers between devnet accounts
+* Call smart contract functions from JavaScript
+* Deploy contracts programmatically
+
+## Quickstart
+
+{% stepper %}
+{% step %}
+#### Install Stacks.js packages
+
+Add the required libraries to your frontend project:
+
+```bash
+npm install @stacks/transactions @stacks/network
+```
+{% endstep %}
+
+{% step %}
+#### Configure for devnet
+
+Create a network helper:
+
+```ts
+import { StacksDevnet } from '@stacks/network';
+
+export const devnet = new StacksDevnet({
+ url: 'http://localhost:3999'
+});
+
+export const accounts = {
+ deployer: {
+ address: 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM',
+ key: 'cb3df38053d132895220b9ce471f6b676db5b9bf0b4adefb55f2118ece2478df01'
+ },
+ wallet1: {
+ address: 'ST1SJ3DTE5DN7X54YDH5D64R3BCB6A2AG2ZQ8YPD5',
+ key: '7287ba251d44a4d3fd9276c88ce34c5c52a038955511cccaf77e61068649c17801'
+ }
+};
+```
+{% endstep %}
+
+{% step %}
+#### Test STX transfers
+
+Send a transfer between devnet accounts:
+
+```ts
+import { makeSTXTokenTransfer, broadcastTransaction, AnchorMode } from '@stacks/transactions';
+import { devnet, accounts } from './devnet-config';
+
+async function transferSTX() {
+ const tx = await makeSTXTokenTransfer({
+ amount: 1_000_000n,
+ recipient: accounts.wallet1.address,
+ senderKey: accounts.deployer.key,
+ network: devnet,
+ anchorMode: AnchorMode.Any,
+ });
+
+ const result = await broadcastTransaction(tx, devnet);
+ console.log('Transaction ID:', result.txid);
+}
+
+transferSTX().catch(console.error);
+```
+
+Run the transfer with `ts-node stx-transfer.ts`.
+{% endstep %}
+
+{% step %}
+#### Call smart contracts
+
+Interact with contracts deployed on devnet:
+
+```ts
+import { makeContractCall, broadcastTransaction, AnchorMode } from '@stacks/transactions';
+import { devnet, accounts } from './devnet-config';
+
+async function callContract() {
+ const tx = await makeContractCall({
+ contractAddress: accounts.deployer.address,
+ contractName: 'counter',
+ functionName: 'increment',
+ functionArgs: [],
+ senderKey: accounts.wallet1.key,
+ network: devnet,
+ anchorMode: AnchorMode.Any,
+ });
+
+ await broadcastTransaction(tx, devnet);
+}
+
+async function readCount() {
+ const response = await fetch(
+ `${devnet.coreApiUrl}/v2/contracts/call-read/${accounts.deployer.address}/counter/get-count`,
+ {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({
+ sender: accounts.wallet1.address,
+ arguments: []
+ })
+ }
+ );
+ const data = await response.json();
+ console.log(data);
+}
+
+callContract().catch(console.error);
+readCount().catch(console.error);
+```
+{% endstep %}
+
+{% step %}
+#### Deploy contracts programmatically
+
+Deploy a contract from your application code:
+
+```ts
+import { makeContractDeploy, broadcastTransaction, AnchorMode } from '@stacks/transactions';
+import { devnet, accounts } from './devnet-config';
+import counterContract from './contracts/counter.clar?raw';
+
+async function deployCounter() {
+ const tx = await makeContractDeploy({
+ contractName: 'counter',
+ codeBody: counterContract,
+ senderKey: accounts.deployer.key,
+ network: devnet,
+ anchorMode: AnchorMode.Any,
+ });
+
+ return broadcastTransaction(tx, devnet);
+}
+
+deployCounter().catch(console.error);
+```
+{% endstep %}
+{% endstepper %}
+
+## Common patterns
+
+### Watching for transaction confirmation
+
+Monitor when transactions are confirmed on devnet:
+
+```ts
+async function waitForTransaction(txid: string) {
+ let attempts = 0;
+ const maxAttempts = 10;
+
+ while (attempts < maxAttempts) {
+ const response = await fetch(
+ `${devnet.coreApiUrl}/extended/v1/tx/${txid}`
+ );
+
+ const tx = await response.json();
+
+ if (tx.tx_status === 'success') {
+ console.log('Transaction confirmed!');
+ return tx;
+ }
+
+ if (tx.tx_status === 'abort_by_response') {
+ throw new Error(`Transaction failed: ${tx.tx_result.repr}`);
+ }
+
+ // Wait for next block
+ await new Promise(resolve => setTimeout(resolve, 5000));
+ attempts++;
+ }
+
+ throw new Error('Transaction timeout');
+}
+```
+
+### Post conditions for safety
+
+Add post conditions to ensure contract calls behave as expected:
+
+```ts
+import { Pc } from '@stacks/transactions';
+
+const postConditions = [
+ // Ensure sender's balance decreases by exactly the amount
+ Pc.principal(accounts.wallet1.address)
+ .willSendEq(1000000n)
+ .ustx(),
+
+ // Ensure recipient receives the amount
+ Pc.principal(accounts.deployer.address)
+ .willReceiveEq(1000000n)
+ .ustx()
+];
+
+const tx = await makeSTXTokenTransfer({
+ amount: 1000000n,
+ recipient: accounts.deployer.address,
+ senderKey: accounts.wallet1.key,
+ network: devnet,
+ postConditions,
+ anchorMode: AnchorMode.Any,
+});
+```
diff --git a/docs/build/clarinet/local-blockchain-development.md b/docs/build/clarinet/local-blockchain-development.md
new file mode 100644
index 0000000000..8d693a5a76
--- /dev/null
+++ b/docs/build/clarinet/local-blockchain-development.md
@@ -0,0 +1,492 @@
+# Local Blockchain Development
+
+Clarinet ships with a complete local blockchain environment so you can build, test, and debug smart contracts without deploying to a public network. This local blockchain environment is what is referred to as a devnet.
+
+
+
+What is a devnet?
+
+* A devnet refers to a local blockchain development environment in which your smart contracts and front end application can interact with simulated blockchain entities.
+* With a devnet, your smart contract application can interact with simulated blockchain entities (miners, nodes, and a stream of mined blocks), all within your local machine.
+* When devnets simulate a blockchain environment, the entities created—the other contracts, transactions, or nodes—resemble the conditions your application will inhabit once in production.
+* Devnets enable you to create different blockchain configurations.
+* You can share a simnet environment with other devs and collaborate with them.
+* You can start a devnet at an arbitrary block height with a specified network upgrade at a later block, and with many simulated users, to see how your application responds.
+
+
+
+## Starting your local blockchain
+
+Launch devnet with all required services:
+
+```bash
+clarinet devnet start
+```
+
+Useful flags:
+
+| Option | Description |
+| -------------------------------- | ------------------------------------------------- |
+| `--manifest-path ` | Use an alternate `Clarinet.toml` |
+| `--no-dashboard` | Stream logs instead of showing the interactive UI |
+| `--deployment-plan-path ` | Apply a specific deployment plan |
+| `--use-on-disk-deployment-plan` | Use an existing plan without recomputing |
+| `--use-computed-deployment-plan` | Recompute and overwrite the plan |
+| `--package ` | Load a packaged devnet configuration |
+
+{% hint style="info" %}
+Prerequisites
+
+Devnet requires Docker. If you see “clarinet was unable to create network,” ensure Docker Desktop is running or the Docker daemon is started.
+{% endhint %}
+
+By default the dashboard displays service health, recent transactions, block production, contract deployments, and resource usage. Use `--no-dashboard` in CI or when you prefer streaming logs.
+
+## Core services and features
+
+Devnet starts these services for you:
+
+| Service | Port | Purpose |
+| ---------------- | ----- | ---------------------------------------- |
+| Stacks node | 20443 | Processes transactions and mines blocks |
+| Bitcoin node | 18443 | Provides block anchoring in regtest mode |
+| Stacks API | 3999 | REST API for blockchain data |
+| Postgres | 5432 | Indexes blockchain data |
+| Stacks Explorer | 8000 | Browse transactions in a web UI |
+| Bitcoin Explorer | 8001 | View the Bitcoin regtest chain |
+
+Devnet includes pre-funded accounts:
+
+```clarity
+::get_assets_maps
+;; +-------------------------------------------+-----------------+
+;; | Address | STX Balance |
+;; |-------------------------------------------+-----------------|
+;; | ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM | 100000000000000 |
+;; | ST1SJ3DTE5DN7X54YDH5D64R3BCB6A2AG2ZQ8YPD5 | 100000000000000 |
+;; | ST2CY5V39NHDPWSXMW9QDT3HC3GD6Q6XX4CFRK9AG | 100000000000000 |
+;; | ST2JHG361ZXG51QTKY2NQCVBPPRRE2KZB1HR05NNC | 100000000000000 |
+;; | ST2NEB84ASENDXKYGJPQW86YXQCEFEX2ZQPG87ND | 100000000000000 |
+;; +-------------------------------------------+-----------------+
+```
+
+When devnet starts it automatically deploys your project contracts so you can interact immediately.
+
+```
+$ clarinet devnet start
+Deploying contracts...
+Deploying counter.clar ✓ ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.counter
+Deploying token.clar ✓ ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.token
+Deploying marketplace.clar ✓ ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.marketplace
+
+All contracts deployed successfully
+```
+
+## Configuration and customization
+
+Devnet behavior is controlled by configuration files in your project.
+
+### Basic configuration
+
+`settings/Devnet.toml` defines network settings:
+
+```toml
+[network]
+name = "devnet"
+
+# Service ports
+stacks_node_rpc_port = 20443
+stacks_api_port = 3999
+stacks_explorer_port = 8000
+bitcoin_node_rpc_port = 18443
+
+[network.devnet]
+bitcoin_controller_block_time = 30_000 # 30 seconds
+
+disable_bitcoin_explorer = false
+disable_stacks_explorer = false
+disable_stacks_api = false
+```
+
+### Port configuration
+
+Avoid local conflicts by customizing ports:
+
+```toml
+stacks_node_rpc_port = 30443
+stacks_api_port = 4999
+postgres_port = 6432
+stacks_explorer_port = 4020
+```
+
+### Mining intervals
+
+Control block production speed:
+
+```toml
+bitcoin_controller_block_time = 1_000 # Fast development (1 second)
+bitcoin_controller_block_time = 30_000 # Standard testing (30 seconds)
+bitcoin_controller_block_time = 120_000 # Realistic timing (2 minutes)
+```
+
+### Custom accounts
+
+Add accounts with specific balances:
+
+```toml
+[accounts.treasury]
+mnemonic = "twice kind fence tip hidden tilt action fragile skin nothing glory cousin"
+balance = 10_000_000_000_000
+
+[accounts.alice]
+mnemonic = "female adjust gallery certain visit token during great side clown fitness like"
+balance = 5_000_000_000_000
+```
+
+## Accessing services
+
+Devnet exposes several ways to interact with the blockchain.
+
+### Stacks Explorer
+
+Visit the explorer to browse transactions, blocks, contract state, and account balances:
+
+```
+http://localhost:8000
+```
+
+### API endpoints
+
+Query blockchain data with the Stacks API:
+
+```bash
+curl http://localhost:3999/v2/info
+```
+
+Common endpoints:
+
+* `/v2/info` – network information
+* `/v2/accounts/{address}` – account details
+* `/v2/contracts/source/{address}/{name}` – contract source code
+* `/extended/v1/tx/{txid}` – transaction details
+
+### Direct RPC
+
+Submit transactions directly to the Stacks node:
+
+```bash
+curl -X POST http://localhost:20443/v2/transactions \
+ -H "Content-Type: application/json" \
+ -d @transaction.json
+```
+
+Useful RPC endpoints:
+
+* `/v2/transactions` – broadcast transactions
+* `/v2/contracts/call-read` – read-only contract calls
+* `/v2/fees/transfer` – fee estimates for STX transfers
+
+## Advanced configuration
+
+### Performance optimization
+
+For faster development cycles:
+
+{% code title="settings/Devnet.toml" %}
+```toml
+[network.devnet]
+bitcoin_controller_block_time = 1_000
+
+disable_bitcoin_explorer = true
+disable_stacks_explorer = true
+disable_stacks_api = false
+```
+{% endcode %}
+
+### Epoch configuration
+
+Test different Stacks versions:
+
+```toml
+[epochs]
+epoch_2_0 = 0 # Stacks 2.0 from genesis
+epoch_2_05 = 0 # Stacks 2.05 from genesis
+epoch_2_1 = 0 # Stacks 2.1 from genesis
+epoch_2_2 = 0 # Pox-2 from genesis
+epoch_2_3 = 0 # Pox-3 from genesis
+epoch_2_4 = 0 # Pox-4 from genesis
+epoch_3_0 = 101 # Nakamoto activation at block 101
+```
+
+### Custom node/signer images
+
+Clarinet runs Devnet with specific tags for each Docker image. For example, Clarinet v3.10.0 uses the following images:
+
+* stacks node: `blockstack/stacks-blockchain:3.3.0.0.1-alpine`
+* stacks signer: `blockstack/stacks-signer:3.3.0.0.1.0-alpine`
+
+We recommend Devnet users let Clarinet handle it and use the default version. This ensures that your Clarinet version can handle and properly configure the images it uses.
+
+In some cases, you may need to use other images. Clarinet lets you do this by configuring it in `settings/Devnet.toml`. For example, if you don't want to run the `alpine` images:
+
+```toml
+# setting/Devnet.toml
+[network]
+name = "devnet"
+deployment_fee_rate = 10
+
+# ...
+
+[devnet]
+stacks_node_image_url = "blockstack/stacks-blockchain:3.3.0.0.1"
+stacks_signer_image_url = "blockstack/stacks-signer:3.3.0.0.1.0"
+```
+
+
+
+Build an image locally and use it
+
+* Clone the stacks-core repository (or a fork) and checkout the desired branch.
+
+```
+git clone git@github.com:stacks-network/stacks-core.git
+cd stacks-core
+git checkout develop
+```
+
+* Build the Docker image `stacks-node:local`:
+
+```
+docker build -t stacks-node:local -f ./Dockerfile ./
+```
+
+* Clarinet needs the image to be available in a registry. You can host a local one and push the image to it.
+
+```
+docker run -d -e REGISTRY_HTTP_ADDR=0.0.0.0:5001 -p 5001:5001 --name registry registry:2
+docker tag stacks-node:local localhost:5001/stacks-node:local
+docker push localhost:5001/stacks-node:local
+```
+
+* Set the image to be used:
+
+```
+# setting/Devnet.toml
+[network]
+name = "devnet"
+deployment_fee_rate = 10
+
+# ...
+
+[devnet]
+stacks_node_image_url = "localhost:5001/stacks-node:local"
+```
+
+* Then start Devnet:
+
+```
+clarinet devnet sta
+```
+
+
+
+### Package deployment
+
+Create reusable devnet configurations:
+
+```bash
+$ clarinet devnet package --name demo-env
+Packaging devnet configuration...
+Created demo-env.json
+```
+
+Use a packaged configuration:
+
+```bash
+$ clarinet devnet start --package demo-env.json
+```
+
+## Common issues
+
+
+
+Docker connection errors — “clarinet was unable to create network”
+
+Follow these steps to fix Docker connection issues:
+
+Ensure Docker Desktop is running (macOS/Windows).Start the Docker daemon (sudo systemctl start docker) on Linux.Confirm permissions with docker ps.Reset Docker to factory defaults if problems persist.
+
+Verify Docker status:
+
+```bash
+docker --version
+docker ps
+```
+
+
+
+
+
+Port already in use — “bind: address already in use”
+
+Find and stop the conflicting process (macOS/Linux):
+
+```bash
+lsof -i :3999
+kill -9 $(lsof -t -i:3999)
+```
+
+Windows equivalent:
+
+```bash
+netstat -ano | findstr :3999
+taskkill /PID /F
+```
+
+Or update ports in `settings/Devnet.toml`:
+
+```toml
+stacks_api_port = 4999
+stacks_explorer_port = 4020
+postgres_port = 6432
+```
+
+
+
+
+
+High resource usage (slow performance, high CPU or memory)
+
+Optimizations:
+
+```toml
+disable_bitcoin_explorer = true
+disable_stacks_explorer = true
+bitcoin_controller_block_time = 60_000
+```
+
+Set Docker resource limits:
+
+```bash
+docker update --memory="2g" --cpus="1"
+```
+
+Clean up old data:
+
+```bash
+clarinet devnet stop
+docker system prune -a
+rm -rf tmp/devnet
+```
+
+
+
+
+
+Network already exists — “network with name `.devnet` already exists”
+
+Remove the orphaned network:
+
+```bash
+docker network rm .devnet
+```
+
+If you're unsure of the name:
+
+```bash
+docker network ls | grep devnet
+docker network rm
+```
+
+Prevent the issue by stopping devnet with `Ctrl+C` and pruning orphaned networks:
+
+```bash
+docker network prune
+```
+
+
+
+
+
+Docker stream error during startup — “Fatal: unable to create image: Docker stream error”
+
+**Error**: "Fatal: unable to create image: Docker stream error"
+
+This error often occurs when Docker images are corrupted or when explorers fail to start properly.
+
+**Solution 1 - Disable explorers**:
+
+If you don't need the web explorers, disable them in `settings/Devnet.toml`:
+
+```
+disable_bitcoin_explorer = true
+disable_stacks_explorer = true
+```
+
+**Solution 2 - Clean Docker environment**:
+
+Remove all containers and images, then restart:
+
+Terminal
+
+```
+docker stop $(docker ps -a -q)
+docker system prune -a
+docker volume prune
+```
+
+**Solution 3 - Full cleanup and restart**:
+
+Terminal
+
+```
+docker stop $(docker ps -a -q)
+docker network rm .devnet
+docker system prune --all --volumes
+clarinet devnet start
+```
+
+This ensures a clean Docker environment for devnet to start fresh.
+
+
+
+
+
+Contract deployment failures
+
+Ensure dependencies deploy first in `Clarinet.toml`:
+
+```toml
+[contracts.sip-010-trait]
+path = "contracts/sip-010-trait.clar"
+
+[contracts.token]
+path = "contracts/token.clar"
+```
+
+Validate contracts before deployment:
+
+```bash
+clarinet check
+```
+
+Check logs:
+
+```bash
+clarinet devnet start --no-dashboard
+```
+
+Deploy manually if needed:
+
+```bash
+clarinet deployments generate --devnet
+clarinet deployments apply --devnet
+```
+
+
+
+***
+
+### Additional Resources
+
+* \[[Hiro Blog](https://www.hiro.so/blog/5-ways-to-interact-with-devnet-in-the-hiro-platform)] 5 Ways to Interact With Devnet in the Hiro Platform
diff --git a/docs/build/clarinet/mainnet-execution-simulation.md b/docs/build/clarinet/mainnet-execution-simulation.md
new file mode 100644
index 0000000000..2f8a402f95
--- /dev/null
+++ b/docs/build/clarinet/mainnet-execution-simulation.md
@@ -0,0 +1,156 @@
+# Mainnet Execution Simulation
+
+Mainnet execution simulation (MXS) lets you test your Clarity contracts against real mainnet data without deploying experimental code. You can reproduce historical state, validate complex integrations, and debug edge cases while keeping the speed of local development.
+
+## What you'll learn
+
+* Set up MXS in a Clarinet project
+* Write tests that interact with mainnet contracts
+* Simulate historical transactions
+* Understand MXS limitations
+
+## What is Mainnet execution simulation?
+
+Testing smart contracts in realistic conditions is essential. Simnet offers an isolated environment but lacks the live Stacks mainnet's complexity and history.
+
+MXS fills this gap by enabling unit tests with the Clarinet JS SDK and Vitest to simulate the Stacks mainnet state at a specific block height. This allows you to:
+
+* **Validate contract logic with real data:** Directly test mainnet contracts or data within your tests.
+* **(Re)simulate transactions:** Analyze mainnet transactions' results, execution, or costs without deploying or using actual STX.
+
+## Enable MXS in your project
+
+Add the following configuration to your `Clarinet.toml` file:
+
+```toml
+[repl.remote_data]
+
+# Enable mainnet execution simulation
+enabled = true
+
+# Specify the Stacks block height to fork from
+initial_height = 522000
+
+# API URL (optional, defaults to https://api.hiro.so)
+api_url = 'https://api.hiro.so'
+```
+
+{% hint style="info" %}
+Pro tip
+
+Set a specific `initial_height` to keep tests reproducible.
+{% endhint %}
+
+## Using mainnet addresses
+
+When testing contracts that check or require mainnet addresses, set `use_mainnet_wallets = true`. This enables your simnet tests to use mainnet addresses (SP/SM) instead of testnet addresses (ST).
+
+```toml
+[repl.remote_data]
+enabled = true
+initial_height = 522000
+use_mainnet_wallets = true # !mark
+```
+
+This is particularly useful when:
+
+* Testing against mainnet-only contracts like DEX protocols
+* Your contract includes [`(is-standard standard-or-contract-principal)`](mainnet-execution-simulation.md) validation
+* Simulating transactions that require mainnet address formats
+
+## Configure API access
+
+While MXS works without an API key, you may encounter rate limits. Set up an API key for reliable access:
+
+```bash
+export HIRO_API_KEY=""
+```
+
+## Write tests with mainnet data
+
+Once MXS is enabled, your tests automatically operate against the mainnet state snapshot. Here's an example testing against the mainnet `pox-4` contract:
+
+```ts
+import { describe, it, expect } from "vitest";
+import { Cl } from "@stacks/transactions";
+
+const accounts = simnet.getAccounts();
+const deployer = accounts.get("deployer")!;
+
+describe("pox-4 mainnet interaction", () => {
+ it("reads current reward cycle from mainnet", () => {
+ // Call the mainnet pox-4 contract
+ const call = simnet.callReadOnlyFn(
+ "SP000000000000000000002Q6VF78.pox-4", // Mainnet contract
+ "current-pox-reward-cycle",
+ [],
+ deployer
+ );
+
+ // Assert the result (adjust based on your initial_height)
+ expect(call.result).toBeUint(109);
+
+ console.log("Current POX reward cycle:", Cl.prettyPrint(call.result));
+ });
+});
+```
+
+The test uses `simnet.callReadOnlyFn` just like in standard unit tests, but because MXS is enabled, it targets the actual `pox-4` contract state at the specified block height.
+
+## Try it out
+
+Run your test to see MXS in action:
+
+```bash
+npm run test
+```
+
+## Common issues
+
+
+
+Rate limit errors
+
+Solution: Set up the `HIRO_API_KEY` environment variable.
+
+```bash
+export HIRO_API_KEY=""
+```
+
+
+
+
+
+Inconsistent results
+
+Solution: Fix `initial_height` in configuration so tests are run against a reproducible block snapshot.
+
+
+
+
+
+Function not found
+
+Solution: Check the contract exists at your block height.
+
+
+
+## Testing in the playground
+
+{% stepper %}
+{% step %}
+**Visit the playground**
+
+Go to: [https://play.hiro.so/?remote\_data=true](https://play.hiro.so/?remote_data=true)
+{% endstep %}
+
+{% step %}
+**Run a mainnet contract call**
+
+Example Clarity call:
+
+```clarity
+> contract-call? 'SP000000000000000000002Q6VF78.pox-4 current-pox-reward-cycle
+```
+{% endstep %}
+{% endstepper %}
diff --git a/docs/build/clarinet/overview.md b/docs/build/clarinet/overview.md
new file mode 100644
index 0000000000..75d05dd246
--- /dev/null
+++ b/docs/build/clarinet/overview.md
@@ -0,0 +1,98 @@
+---
+description: >-
+ Clarinet is everything you need to write, test, and deploy Clarity smart
+ contracts on Stacks.
+---
+
+# Overview
+
+Clarinet is a development framework and Clarity runtime packaged as a command line tool, designed to facilitate smart contract understanding, development, testing and deployment. It contains a suite of tools for building, testing, and deploying Clarity smart contracts for the Stacks blockchain.
+
+Clarinet is the fastest way to build, test, and deploy smart contracts on the Stacks blockchain. It gives you a local devnet, REPL, testing framework, and debugging tools to ship high-quality Clarity code with confidence.
+
+{% hint style="success" %}
+For the latest releases and versions of Clarinet, check out the open-source repo [here](https://github.com/stx-labs/clarinet).
+{% endhint %}
+
+
+
+#### Announcements
+
+{% updates format="full" %}
+{% update date="2025-11-05" %}
+## Clarinet was migrated to Stacks Labs
+
+* The Clarinet repository now belongs to the stx-labs organization.
+* The NPM packages are now published under the `@stacks` organization.
+* The VSCode extension is now published under the Stacks Labs organization.
+* Check out the [announcement](/broken/pages/MJwczGlRXtiBGKy9CNxu) to see how to migrate older projects.
+{% endupdate %}
+{% endupdates %}
+
+## Key features
+
+* [**Leverage a powerful CLI**](https://app.gitbook.com/s/GVj1Z9vMuEOMe7oH7Wnq/clarinet/cli-reference) - Create new projects, manage your smart contracts and their dependencies using clarinet requirements, and interact with your code through the built-in REPL.
+* [**Write unit tests with the SDK**](testing-with-clarinet-sdk.md) - Use the Clarinet SDK to write unit tests in a familiar JS environment and validate contract behavior.
+* [**Run a private blockchain environment**](local-blockchain-development.md) - Spin up a local devnet with nodes, miners, and APIs so you can test and integrate your code.
+* [**VSCode extension**](integrations/clarity-vscode-extension.md) - Linter, step by step debugger, helps writing smart contracts (autocompletion, documentation etc).
+
+## Installation
+
+{% tabs %}
+{% tab title="Homebrew" %}
+```bash
+brew install clarinet
+```
+{% endtab %}
+
+{% tab title="Winget" %}
+```bash
+winget install clarinet
+```
+{% endtab %}
+
+{% tab title="Source" %}
+```bash
+sudo apt install build-essential pkg-config libssl-dev
+git clone https://github.com/stx-labs/clarinet
+cd clarinet
+cargo clarinet-install
+```
+{% endtab %}
+
+{% tab title="Binary" %}
+```bash
+wget -nv https://github.com/stx-labs/clarinet/releases/latest/download/clarinet-linux-x64-glibc.tar.gz -O clarinet-linux-x64.tar.gz
+tar -xf clarinet-linux-x64.tar.gz
+chmod +x ./clarinet
+mv ./clarinet /usr/local/bin
+```
+{% endtab %}
+{% endtabs %}
+
+## Networks
+
+Clarinet supports different network types to cater to various development and testing needs.
+
+| Network | Description | Use case |
+| --------- | --------------------------------------------------------------------------- | ------------------------------------------------------------------ |
+| `simnet` | Optimized for fast feedback loops, introspection, and portability. | Ideal for initial development and unit-testing. |
+| `devnet` | Local Stacks and Bitcoin nodes running on Docker for faster feedback loops. | Use for integration tests or local frontend development. |
+| `testnet` | A pre-production network that offers a realistic environment for testing. | Ideal for final testing before deploying to Mainnet. |
+| `mainnet` | The production network where real transactions occur. | Use when you're ready to deploy your smart contract to production. |
+
+For a deeper understanding of when to use these networks, check out the dedicated blog post by Hiro [here](https://www.hiro.so/blog/devnet-vs-testnet-vs-mainnet-what-do-they-mean-for-web3-developers).
+
+***
+
+### Additional Resources
+
+* \[[Hiro Blog](https://www.hiro.so/blog/clarinet-roadmap-looking-to-the-future)] The Humble Beginning of Clarinet
+
+***
+
+{% hint style="info" %}
+Help: Need help building with Clarinet?
+
+Reach out to us on the **#clarinet** channel on [Discord](https://stacks.chat/) under the Developer Tools section.
+{% endhint %}
diff --git a/docs/build/clarinet/project-development.md b/docs/build/clarinet/project-development.md
new file mode 100644
index 0000000000..6c226defca
--- /dev/null
+++ b/docs/build/clarinet/project-development.md
@@ -0,0 +1,149 @@
+# Project Development
+
+Clarinet streamlines the entire lifecycle of Clarity smart contract development. From project initialization to contract management and code formatting, you'll have the tools needed for professional workflows.
+
+## Creating a new project
+
+The `clarinet new` command creates a complete project structure with all necessary configuration files:
+
+```bash
+$ clarinet new my-defi-app
+```
+
+| Option | Description | Example |
+| --------------------- | ------------------------------- | ----------------------------------------- |
+| `--disable-telemetry` | Opt out of telemetry collection | `clarinet new my-app --disable-telemetry` |
+
+For a deeper look at what Clarinet generates, see the [project structure](project-structure.md) guide.
+
+## Managing contracts
+
+### Creating new contracts
+
+The `clarinet contract new` command generates both a contract file and a matching test file:
+
+```bash
+$ clarinet contract new token
+Created file contracts/token.clar
+Created file tests/token.test.ts
+Updated Clarinet.toml
+```
+
+The generated contract includes a minimal template:
+
+```clarity
+;; token
+;;
+
+;; constants
+;;
+
+;; data vars
+;;
+
+;; data maps
+;;
+
+;; public functions
+;;
+
+;; read only functions
+;;
+
+;; private functions
+;;
+```
+
+### Removing contracts
+
+Clean up unused contracts with the `rm` command:
+
+```bash
+$ clarinet contract rm old-token
+Removed file contracts/old-token.clar
+Removed file tests/old-token.test.ts
+Updated Clarinet.toml
+```
+
+## Checking project contract syntax
+
+Validate your entire project setup:
+
+```bash
+$ clarinet check
+✔ 3 contracts checked
+```
+
+Check specific contracts:
+
+```bash
+$ clarinet check contracts/token.clar
+✔ contracts/token.clar Syntax of contract successfully checked
+```
+
+## Code formatting
+
+Clarinet includes a formatter to maintain consistent style across your project.
+
+Format all contracts in your project:
+
+```bash
+$ clarinet format --in-place
+Formatted 5 contracts
+```
+
+### Formatting options
+
+Customize formatting to match your team's style guide:
+
+| Option | Description | Example |
+| ------------------- | ------------------------------------------------------ | --------------------------------------- |
+| `--dry-run` | Preview changes without modifying files | `clarinet format --dry-run` |
+| `--in-place` | Replace file contents (required for actual formatting) | `clarinet format --in-place` |
+| `--max-line-length` | Set maximum line length | `clarinet format --max-line-length 100` |
+| `--indent` | Set indentation size | `clarinet format --indent 2` |
+| `--tabs` | Use tabs instead of spaces | `clarinet format --tabs` |
+
+### Format single files
+
+```bash
+$ clarinet format contracts/messy-contract.clar --in-place
+```
+
+Format specific contracts with glob patterns:
+
+```bash
+$ clarinet format contracts/token*.clar --in-place
+```
+
+## Project configuration
+
+### Working with requirements
+
+Add mainnet contracts as dependencies:
+
+```bash
+$ clarinet requirements add SP2PABAF9FTAJYNFZH93XENAJ8FVY99RRM50D2JG9.nft-trait
+Added requirement SP2PABAF9FTAJYNFZH93XENAJ8FVY99RRM50D2JG9.nft-trait
+Updated Clarinet.toml
+```
+
+Clarinet adds the dependency to `Clarinet.toml`:
+
+```toml
+[project]
+requirements = [
+ { contract_id = "SP2PABAF9FTAJYNFZH93XENAJ8FVY99RRM50D2JG9.nft-trait" }
+]
+```
+
+You can now implement traits from mainnet contracts:
+
+```clarity
+(impl-trait 'SP2PABAF9FTAJYNFZH93XENAJ8FVY99RRM50D2JG9.nft-trait.nft-trait)
+
+(define-non-fungible-token my-nft uint)
+;; ... implement required functions
+```
+
+##
diff --git a/docs/build/clarinet/project-structure.md b/docs/build/clarinet/project-structure.md
new file mode 100644
index 0000000000..fd80458d04
--- /dev/null
+++ b/docs/build/clarinet/project-structure.md
@@ -0,0 +1,240 @@
+---
+description: Understand the complete structure and configuration of a Clarinet project.
+---
+
+# Project Structure
+
+A Clarinet project follows a carefully designed structure that separates contracts, tests, and configuration. Understanding this structure helps you organize code effectively and configure tools for an efficient development workflow.
+
+## Core project layout
+
+Every Clarinet project contains these essential directories and files:
+
+```
+- my-project/
+ - .vscode/
+ - contracts/
+ - main.clar
+ - trait.clar
+ - deployments/
+ - settings/
+ - Devnet.toml
+ - Mainnet.toml
+ - Testnet.toml
+ - tests/
+ - main.test.ts
+ - .gitignore
+ - Clarinet.toml
+ - package.json
+ - tsconfig.json
+ - vitest.config.js
+```
+
+Each component serves a specific purpose in your development workflow. The sections below explain how they work together to create a complete development environment.
+
+## The project manifest
+
+### Clarinet.toml
+
+The **Clarinet.toml** file is the heart of your project. It defines project metadata and tracks all contracts:
+
+```toml
+[project]
+name = "counter"
+description = "A counter smart contract"
+
+[contracts.traits]
+path = "contracts/traits.clar"
+clarity_version = 4
+epoch = "latest"
+
+[contracts.counter]
+path = "contracts/counter.clar"
+clarity_version = 4
+epoch = "latest"
+```
+
+The manifest handles several critical functions:
+
+* **Contract registration**: Every contract must be listed here
+* **Stacks epoch and Clarity version**: Specifies Clarity version and epoch for each contract
+* **Boot sequence**: Lists contracts to deploy on `clarinet devnet start`
+
+### Epoch configuration
+
+You can specify the epoch in two ways:
+
+```toml
+# Use a specific epoch version
+epoch = 3.1
+```
+
+```toml
+# Use the latest available epoch (default)
+epoch = "latest"
+```
+
+Using `"latest"` ensures your contracts always use the newest Clarity features and optimizations available in your version of Clarinet.
+
+## Testing infrastructure
+
+### Package configuration
+
+The **package.json** defines your testing environment and dependencies:
+
+```json
+{
+ "name": "counter-tests",
+ "version": "1.0.0",
+ "description": "Run unit tests on this project.",
+ "type": "module",
+ "private": true,
+ "scripts": {
+ "test": "vitest run",
+ "test:report": "vitest run -- --coverage --costs",
+ "test:watch": "chokidar \"tests/**/*.ts\" \"contracts/**/*.clar\" -c \"npm run test:report\""
+ },
+ "author": "",
+ "license": "ISC",
+ "dependencies": {
+ "@stacks/clarinet-sdk": "^3.9.1",
+ "@stacks/transactions": "^7.2.0",
+ "@types/node": "^24.4.0",
+ "chokidar-cli": "^3.0.0",
+ "vitest": "^4.0.7",
+ "vitest-environment-clarinet": "^3.0.0"
+ }
+}
+```
+
+| Package | Purpose |
+| ----------------------------- | ------------------------------------------------------- |
+| `@stacks/clarinet-sdk` | WebAssembly-compiled Clarinet for Node.js |
+| `@stacks/transactions` | Clarity value manipulation in TypeScript |
+| `vitest` | Modern testing framework with native TypeScript support |
+| `vitest-environment-clarinet` | Simnet bootstrapping for tests |
+
+### Vitest configuration
+
+The **vitest.config.js** configures the testing framework:
+
+```js
+
+///
+
+import { defineConfig } from "vite";
+import { vitestSetupFilePath, getClarinetVitestsArgv } from "@stacks/clarinet-sdk/vitest";
+
+export default defineConfig({
+ test: {
+ environment: "clarinet", // use vitest-environment-clarinet
+ pool: "forks",
+ poolOptions: {
+ threads: { singleThread: true },
+ forks: { singleFork: true },
+ },
+ setupFiles: [
+ vitestSetupFilePath,
+ // custom setup files can be added here
+ ],
+ environmentOptions: {
+ clarinet: {
+ ...getClarinetVitestsArgv(),
+ // add or override options
+ },
+ },
+ },
+});
+```
+
+This configuration enables:
+
+* **Clarinet environment**: Automatic `simnet` setup for each test
+* **Single fork mode**: Efficient test execution with proper isolation
+* **Coverage tracking**: Generate reports in multiple formats
+* **Custom setup**: Add project-specific test utilities
+
+### TypeScript configuration
+
+The **tsconfig.json** provides TypeScript support:
+
+```json
+{
+ "compilerOptions": {
+ "target": "ESNext",
+ "useDefineForClassFields": true,
+ "module": "ESNext",
+ "lib": ["ESNext"],
+ "skipLibCheck": true,
+
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "noEmit": true,
+
+ "strict": true,
+ "noImplicitAny": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noFallthroughCasesInSwitch": true
+ },
+ "include": [
+ "node_modules/@stacks/clarinet-sdk/vitest-helpers/src",
+ "tests"
+ ]
+}
+```
+
+Properly setting the `include` property ensures TypeScript picks up the helpers defined in the Clarinet SDK package along with your tests.
+
+## Network configurations
+
+### Environment settings
+
+Each network has its own configuration file in the **settings** directory:
+
+```toml
+[network]
+name = "devnet"
+deployment_fee_rate = 10
+
+[accounts.deployer]
+mnemonic = "twice kind fence tip hidden..."
+balance = 100_000_000_000_000
+
+[accounts.wallet_1]
+mnemonic = "sell invite acquire kitten..."
+balance = 10_000_000_000_000
+```
+
+These settings control:
+
+* **Network ports**: API, RPC, and explorer endpoints
+* **Account configuration**: Test wallets with STX balances
+* **Chain parameters**: Network-specific blockchain settings
+
+{% hint style="warning" %}
+Never commit mainnet private keys or mnemonics. Use environment variables for production credentials.
+{% endhint %}
+
+## Common issues
+
+
+
+Imports failing in tests
+
+If you're encountering import errors in your tests, update your TypeScript configuration to use Vite's bundler resolution:
+
+```json
+{
+ "compilerOptions": {
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true
+ }
+}
+```
+
+This configuration ensures TypeScript understands Vite's module resolution strategy and allows importing `.ts` files directly.
+
+
diff --git a/docs/build/clarinet/quickstart.md b/docs/build/clarinet/quickstart.md
new file mode 100644
index 0000000000..7fa0907f30
--- /dev/null
+++ b/docs/build/clarinet/quickstart.md
@@ -0,0 +1,141 @@
+---
+description: >-
+ In this guide, you'll build a simple counter smart contract and interact with
+ it in a local environment.
+---
+
+# Quickstart
+
+## What you'll learn
+
+* Create a Clarity smart contract project
+* Write Clarity code with maps and public functions
+* Test and validate your contracts using Clarinet's console
+
+## Prerequisites
+
+* Clarinet installed on your machine. Follow the [installation guide](overview.md#installation) if needed.
+* A code editor like VS Code for editing Clarity files.
+
+{% stepper %}
+{% step %}
+#### Create your project
+
+Let's start by creating a new Clarinet project. The `clarinet new` command sets up everything you need for smart contract development, including a testing framework, deployment configurations, and a local development environment:
+
+```bash
+clarinet new counter
+```
+
+Clarinet creates a complete project structure for you. Each folder serves a specific purpose in your development workflow:
+
+```
+- counter/
+ - contracts/
+ - settings/
+ - Devnet.toml
+ - Mainnet.toml
+ - Testnet.toml
+ - tests/
+ - Clarinet.toml
+ - package.json
+ - vitest.config.js
+```
+{% endstep %}
+
+{% step %}
+#### Generate your contract
+
+Now that we have our project structure, let's create a smart contract. Navigate into your project directory and use Clarinet's contract generator:
+
+```bash
+$ cd counter
+$ clarinet contract new counter
+Created file contracts/counter.clar
+Created file tests/counter.test.ts
+Updated Clarinet.toml with contract counter
+```
+
+Clarinet automatically creates both your contract file and a corresponding test file. This follows the best practice of writing tests alongside your contract code:
+
+| File | Purpose |
+| ------------------------ | --------------------------- |
+| `contracts/counter.clar` | Your smart contract code |
+| `tests/counter.test.ts` | Test file for your contract |
+
+{% hint style="info" %}
+Notice that Clarinet also updated your `Clarinet.toml` file. This configuration file tracks all contracts in your project and their deployment settings.
+{% endhint %}
+{% endstep %}
+
+{% step %}
+#### Write your contract code
+
+Open `contracts/counter.clar` and replace its contents with our counter implementation. This contract will maintain a separate count for each user who interacts with it:
+
+{% code title="contracts/counter.clar" %}
+```lisp
+;; Define a map to store counts for each user
+(define-map counters principal uint)
+
+;; Increment the count for the caller
+(define-public (count-up)
+ (ok (map-set counters tx-sender (+ (get-count tx-sender) u1)))
+)
+
+;; Get the current count for a user
+(define-read-only (get-count (who principal))
+ (default-to u0 (map-get? counters who))
+)
+```
+{% endcode %}
+
+Let's understand what each part does:
+
+* `define-map` creates a persistent storage map that associates each user (principal) with their count
+* `tx-sender` is a built-in variable that contains the address of whoever calls the function
+* `define-public` declares functions that can modify contract state
+* `define-read-only` declares functions that only read data without modifying it
+{% endstep %}
+
+{% step %}
+#### Validate your contract
+
+Before we can test our contract, let's make sure it's syntactically correct and type-safe. Clarinet's check command analyzes your contract without deploying it:
+
+```bash
+clarinet check
+```
+
+If you see errors instead, here are the most common issues and how to fix them:
+
+| Error | Fix |
+| --------------------- | ----------------------------------------------------------------------------- |
+| `Unknown keyword` | Check spelling of Clarity functions |
+| `Type mismatch` | Ensure you're using correct types (uint, principal, etc.) |
+| `Unresolved contract` | Verify contract name in `Clarinet.toml` matches the contract name in the file |
+{% endstep %}
+
+{% step %}
+#### Test in the console
+
+Now for the exciting part—let's interact with our contract! Clarinet provides an interactive console where you can call functions and see results immediately. Start the console with:
+
+```bash
+clarinet console
+```
+
+Once the console loads, you can call your contract functions directly. Here are a few examples you can try:
+
+```lisp
+$ (contract-call? .counter count-up)
+(ok true)
+$ (contract-call? .counter get-count tx-sender)
+u1
+$ (contract-call? .counter count-up)
+(ok true)
+$ (contract-call? .counter get-count tx-sender)
+u2
+```
+{% endstep %}
+{% endstepper %}
diff --git a/docs/build/clarinet/testing-with-clarinet-sdk.md b/docs/build/clarinet/testing-with-clarinet-sdk.md
new file mode 100644
index 0000000000..a95ea31497
--- /dev/null
+++ b/docs/build/clarinet/testing-with-clarinet-sdk.md
@@ -0,0 +1,448 @@
+---
+description: Practical guide to testing smart contracts with the Clarinet JS SDK.
+---
+
+# Unit Testing
+
+
+
+Unit testing verifies that individual contract functions behave as expected. The Clarinet JS SDK pairs with Vitest to help you catch bugs early in development. The Clarinet JS SDK provides a powerful testing framework for Clarity smart contracts. It integrates with Vitest to let you run comprehensive tests against a simulated blockchain environment. This library will expose many of Clarinet’s features to the JavaScript ecosystem, including “simnet[^1]”.
+
+{% hint style="success" %}
+For the latest releases and versions of `@stacks/clarinet-sdk`, check out its npm page [here](https://www.npmjs.com/package/@stacks/clarinet-sdk).
+
+* For the [SDK](https://app.gitbook.com/s/GVj1Z9vMuEOMe7oH7Wnq/clarinet-js-sdk/sdk-reference) references of all available methods and definitions.
+* For the [Browser SDK](https://app.gitbook.com/s/GVj1Z9vMuEOMe7oH7Wnq/clarinet-js-sdk/browser-sdk-reference) reference, which is a browser build of the Clarinet SDK lets you interact with simnet directly from web experiences.
+{% endhint %}
+
+## What you'll learn
+
+* Set up a Clarinet project for unit testing
+* Write tests for public and read-only functions
+* Handle error conditions and edge cases
+* Run tests and generate coverage reports
+
+{% stepper %}
+{% step %}
+**Set up your project**
+
+Create a new Clarinet project and install dependencies:
+
+```bash
+clarinet new stx-defi
+cd stx-defi
+npm install
+```
+{% endstep %}
+
+{% step %}
+**Create the contract**
+
+Generate a contract stub:
+
+```bash
+clarinet contract new defi
+```
+
+Replace `contracts/defi.clar` with the following implementation:
+
+{% code title="defi.clar" expandable="true" %}
+```clarity
+;; Holds the total amount of deposits in the contract
+(define-data-var total-deposits uint u0)
+
+;; Maps a user's principal address to their deposited amount
+(define-map deposits { owner: principal } { amount: uint })
+
+;; Public function for users to deposit STX into the contract
+(define-public (deposit (amount uint))
+ (let
+ (
+ ;; Fetch the current balance or default to 0 if none exists
+ (current-balance (default-to u0 (get amount (map-get? deposits { owner: tx-sender }))))
+ )
+ ;; Transfer the STX from sender to contract
+ (try! (stx-transfer? amount tx-sender (as-contract tx-sender)))
+ ;; Update the user's deposit amount in the map
+ (map-set deposits { owner: tx-sender } { amount: (+ current-balance amount) })
+ ;; Update the total deposits variable
+ (var-set total-deposits (+ (var-get total-deposits) amount))
+ ;; Return success
+ (ok true)
+ )
+)
+
+;; Read-only function to get the balance by tx-sender
+(define-read-only (get-balance-by-sender)
+ (ok (map-get? deposits { owner: tx-sender }))
+)
+```
+{% endcode %}
+
+Validate the contract:
+
+```bash
+clarinet check
+```
+{% endstep %}
+
+{% step %}
+**Write your unit test**
+
+Create `tests/defi.test.ts` with a basic happy-path test:
+
+{% hint style="warning" %}
+Be sure you're on the latest version of `@stacks/clarinet-sdk`
+{% endhint %}
+
+{% code title="tests/defi.test.ts" expandable="true" %}
+```ts
+import { describe, it, expect } from 'vitest';
+import { Cl } from '@stacks/transactions';
+
+const accounts = simnet.getAccounts();
+const wallet1 = accounts.get('wallet_1')!;
+
+describe('stx-defi', () => {
+ it('allows users to deposit STX', () => {
+ // Define the amount to deposit
+ const amount = 1000;
+
+ // Call the deposit function
+ const deposit = simnet.callPublicFn('defi', 'deposit', [Cl.uint(amount)], wallet1);
+
+ // Assert the deposit was successful
+ expect(deposit.result).toBeOk(Cl.bool(true));
+
+ // Verify the contract's total deposits
+ const totalDeposits = simnet.getDataVar('defi', 'total-deposits');
+ expect(totalDeposits).toBeUint(amount);
+
+ // Check the user's balance
+ const balance = simnet.callReadOnlyFn('defi', 'get-balance-by-sender', [], wallet1);
+ expect(balance.result).toBeOk(
+ Cl.some(
+ Cl.tuple({
+ amount: Cl.uint(amount),
+ })
+ )
+ );
+ });
+});
+```
+{% endcode %}
+
+The `simnet` object is automatically available and exposes a simulated Stacks blockchain.
+
+{% hint style="info" %}
+Key calls:
+
+* `simnet.callPublicFn` – executes public functions
+* `expect(...).toBeOk()` – asserts a Clarity `ok` response
+* `simnet.getDataVar` – reads a contract data variable
+* `Cl.*` helpers – build Clarity values in JavaScript
+{% endhint %}
+{% endstep %}
+
+{% step %}
+**Try it out**
+
+Run the tests:
+
+```bash
+$ npm run test
+ PASS tests/defi.test.ts
+ stx-defi
+ allows users to deposit STX (5 ms)
+
+Test Files 1 passed (1)
+ Tests 1 passed (1)
+```
+{% endstep %}
+
+{% step %}
+**Generate coverage reports**
+
+```bash
+npm run test:report
+```
+
+This command produces:
+
+* `lcov.info` – code coverage data
+* `costs-reports.json` – gas cost analysis
+
+View the HTML report (macOS example):
+
+```bash
+$ brew install lcov
+$ genhtml lcov.info --branch-coverage -o coverage
+$ open coverage/index.html
+```
+{% endstep %}
+{% endstepper %}
+
+## Configuration options
+
+### Clarinet configuration
+
+Define your contracts in `Clarinet.toml`:
+
+```toml
+[project]
+name = "my-project"
+
+[contracts.counter]
+path = "contracts/counter.clar"
+```
+
+### TypeScript setup
+
+Configure TypeScript for the SDK:
+
+```json
+{
+ "compilerOptions": {
+ "target": "ES2020",
+ "module": "ESNext",
+ "moduleResolution": "node",
+ "strict": true,
+ "esModuleInterop": true,
+ "skipLibCheck": true,
+ "types": ["vitest/globals"]
+ },
+ "include": ["tests/**/*.ts"],
+ "exclude": ["node_modules"]
+}
+```
+
+### Vitest configuration
+
+Set up Vitest so the SDK can bootstrap the testing environment:
+
+```js
+import { defineConfig } from "vitest/config";
+import { vitestSetupFilePath } from "@stacks/clarinet-sdk/vitest";
+
+export default defineConfig({
+ test: {
+ environment: "node",
+ globals: true,
+ setupFiles: [vitestSetupFilePath],
+ },
+});
+```
+
+{% hint style="info" %}
+Include `vitestSetupFilePath` in `setupFiles` so the SDK can prepare the `simnet` instance before tests run.
+{% endhint %}
+
+### Package scripts
+
+Add convenient test scripts to `package.json`:
+
+```json
+"scripts": {
+ "test": "vitest run",
+ "test:watch": "vitest",
+ "test:coverage": "vitest run --coverage"
+}
+```
+
+## Common patterns
+
+### Testing read-only functions
+
+Use `callReadOnlyFn` for functions that do not modify state:
+
+```ts
+const getCountCall = simnet.callReadOnlyFn(
+ "counter",
+ "get-count",
+ [Cl.principal(wallet)],
+ wallet
+);
+expect(getCountCall.result).toBeUint(1);
+```
+
+### Testing public functions with parameters
+
+Pass parameters with the appropriate Clarity helpers:
+
+```ts
+const depositCall = simnet.callPublicFn(
+ "defi",
+ "deposit",
+ [Cl.uint(1000)],
+ wallet
+);
+expect(depositCall.result).toBeOk(Cl.bool(true));
+```
+
+### Accessing contract state
+
+Inspect data variables and maps directly:
+
+```ts
+const totalDeposits = simnet.getDataVar("defi", "total-deposits");
+expect(totalDeposits).toBeUint(1000);
+
+const balance = simnet.getMapEntry("defi", "balances", Cl.principal(wallet));
+expect(balance).toBeUint(1000);
+```
+
+## Other Examples
+
+### Testing contract deployment
+
+Ensure the contract was deployed:
+
+```ts
+it("ensures the contract is deployed", () => {
+ const contractSource = simnet.getContractSource("counter");
+ expect(contractSource).toBeDefined();
+});
+```
+
+### Testing error conditions
+
+Verify error handling logic:
+
+```ts
+it("fails when borrowing too much", () => {
+ const borrowCall = simnet.callPublicFn(
+ "defi",
+ "borrow",
+ [Cl.uint(10000)], // Amount exceeds allowed
+ wallet
+ );
+ expect(borrowCall.result).toBeErr(Cl.uint(300)); // err-overborrow
+});
+```
+
+### Testing with multiple accounts
+
+Simulate cross-account interactions:
+
+```ts
+const wallet1 = accounts.get("wallet_1")!;
+const wallet2 = accounts.get("wallet_2")!;
+
+// Wallet 1 deposits
+simnet.callPublicFn("defi", "deposit", [Cl.uint(1000)], wallet1);
+
+// Wallet 2 tries to withdraw wallet 1's funds (should fail)
+const withdrawCall = simnet.callPublicFn(
+ "defi",
+ "withdraw",
+ [Cl.uint(1000)],
+ wallet2
+);
+expect(withdrawCall.result).toBeErr(Cl.uint(401)); // err-unauthorized
+```
+
+## Running tests
+
+Execute the full suite:
+
+```bash
+npm run test
+```
+
+Generate coverage reports:
+
+```bash
+npm run test:report
+```
+
+This command produces:
+
+* `lcov.info` – code coverage data
+* `costs-reports.json` – gas cost analysis
+
+View the HTML report (macOS example):
+
+```bash
+brew install lcov
+genhtml lcov.info --branch-coverage -o coverage
+open coverage/index.html
+```
+
+## Advanced usage
+
+### Using the SDK in existing projects
+
+If your project has a custom structure, keep contracts and tests together and point the SDK to the manifest:
+
+```
+- my-app/
+ - blockchain/
+ - contracts/
+ - token.clar
+ - tests/
+ - token.test.ts
+ - Clarinet.toml
+ - frontend/
+ - App.tsx
+ - package.json
+ - vitest.config.js
+```
+
+Update `vitest.config.js` to reference the correct manifest path:
+
+```js
+export default defineConfig({
+ test: {
+ environment: "node",
+ globals: true,
+ setupFiles: [vitestSetupFilePath],
+ env: {
+ CLARINET_MANIFEST_PATH: "./blockchain/Clarinet.toml"
+ }
+ },
+});
+```
+
+## Advanced testing patterns
+
+Test error conditions:
+
+```ts
+it('fails when depositing zero', () => {
+ const deposit = simnet.callPublicFn('defi', 'deposit', [Cl.uint(0)], wallet1);
+ expect(deposit.result).toBeErr(Cl.uint(100)); // err-invalid-amount
+});
+```
+
+Test with multiple accounts:
+
+```ts
+const wallet2 = accounts.get('wallet_2')!;
+
+it('tracks deposits from multiple users', () => {
+ simnet.callPublicFn('defi', 'deposit', [Cl.uint(1000)], wallet1);
+ simnet.callPublicFn('defi', 'deposit', [Cl.uint(2000)], wallet2);
+
+ const total = simnet.getDataVar('defi', 'total-deposits');
+ expect(total).toBeUint(3000);
+});
+```
+
+## Common issues
+
+| Issue | Solution |
+| ----------------------------- | --------------------------------------------------------------------- |
+| `toBeOk is not a function` | Ensure the Clarinet SDK matchers are loaded via `vitestSetupFilePath` |
+| `Contract not found` | Re-run `clarinet check` to compile and register contracts |
+| Type errors | Use the `Cl` helpers to construct Clarity values |
+| State pollution between tests | Each test runs in isolation - state doesn't carry over |
+| Timing issues | Use `simnet.mineEmptyBlocks()` to advance block height |
+| Complex assertions | Break down into smaller, focused tests |
+
+***
+
+### Additional Resources
+
+* \[[Hiro Blog](https://www.hiro.so/blog/announcing-the-clarinet-sdk-a-javascript-programming-model-for-easy-smart-contract-testing)] Announcing the Clarinet SDK: a JavaScript Programming Model For Easy Smart Contract Testing
+
+[^1]: Simnet allows developers to interact with a virtual and light Stacks network, embedding the same Clarity VM as the one used in production on Stacks mainnet. With this new JavaScript SDK, it is now possible to control the simnet from Node.js in a standard and familiar way.
diff --git a/docs/build/clarinet/validation-and-analysis.md b/docs/build/clarinet/validation-and-analysis.md
new file mode 100644
index 0000000000..2ebd193a59
--- /dev/null
+++ b/docs/build/clarinet/validation-and-analysis.md
@@ -0,0 +1,241 @@
+# Validation and Analysis
+
+Clarinet provides powerful tools for validating, analyzing, and debugging your smart contracts. From static type checking to real-time cost analysis, you can ensure your contracts are correct and efficient before deployment.
+
+Contract validation spans static analysis, runtime debugging, and cost optimization. Each discipline helps you gain confidence in contract behavior.
+
+## Understanding contract validation
+
+**Static analysis vs. runtime debugging**
+
+| Static analysis | Runtime debugging |
+| --------------------------------------- | -------------------------------------- |
+| Catches issues before deployment | Reveals behavior during execution |
+| Flags type mismatches and syntax errors | Shows actual execution costs |
+| Ensures trait compliance | Exposes state changes and side effects |
+| Detects undefined variables | Highlights transaction flow |
+| Validates function signatures | Surfaces performance bottlenecks |
+
+## Static analysis
+
+Run comprehensive validation with `clarinet check`:
+
+```bash
+clarinet check
+```
+
+Successful output resembles:
+
+```
+✔ 3 contracts checked
+```
+
+When validation fails, Clarinet provides detailed diagnostics:
+
+```
+✖ 1 error detected
+
+Error in contracts/token.clar:15:10
+ |
+15| (ok (+ balance amount))
+ | ^^^^^^^
+ |
+ = Type error: expected uint, found (response uint uint)
+```
+
+{% stepper %}
+{% step %}
+#### Run basic checks
+
+Use `clarinet check` to validate your contracts and catch type/syntax errors before deployment.
+
+```bash
+clarinet check
+```
+{% endstep %}
+
+{% step %}
+#### Check a specific contract
+
+Focus validation during development on a single contract file:
+
+```bash
+clarinet check contracts/nft.clar
+```
+{% endstep %}
+
+{% step %}
+#### Integrate into CI
+
+Automate validation in continuous integration pipelines. Example GitHub Actions workflow:
+
+```yaml
+name: Contract Validation
+on: [push, pull_request]
+
+jobs:
+ sanity-checks:
+ runs-on: ubuntu-latest
+ container: ghcr.io/stx-labs/clarinet:latest
+ steps:
+ - uses: actions/checkout@v4
+ - name: Check Clarity contracts check
+ run: clarinet check --use-on-disk-deployment-plan
+ - name: Check Clarity contracts format
+ run: clarinet fmt --check
+```
+{% endstep %}
+{% endstepper %}
+
+**Validation scope**
+
+Clarinet validates multiple aspects of your contracts:
+
+| Validation type | What it checks |
+| ------------------------ | -------------------------------------------------- |
+| **Type safety** | Function parameters, return values, variable types |
+| **Trait compliance** | Implementation matches trait definitions |
+| **Response consistency** | `ok`/`err` branches return the same types |
+| **Variable scope** | Variables defined before use |
+| **Function visibility** | Proper use of public, private, and read-only |
+
+## Runtime analysis
+
+The Clarinet console offers runtime tools that help you inspect behavior during execution.
+
+### Cost analysis with `::toggle_costs`
+
+Enable automatic cost display after every expression:
+
+```clarity
+::toggle_costs
+;; Always show costs: true
+
+(contract-call? .counter count-up)
+;; +----------------------+----------+------------+------------+
+;; | | Consumed | Limit | Percentage |
+;; |----------------------+----------+------------+------------|
+;; | Runtime | 4775 | 5000000000 | 0.00 % |
+;; | Read count | 5 | 15000 | 0.03 % |
+;; | Read length (bytes) | 268 | 100000000 | 0.00 % |
+;; | Write count | 1 | 15000 | 0.01 % |
+;; | Write length (bytes) | 41 | 15000000 | 0.00 % |
+;; +----------------------+----------+------------+------------+
+;; (ok true)
+```
+
+### Execution tracing with `::trace`
+
+Trace function calls to understand execution flow:
+
+```clarity
+::trace (contract-call? .defi-pool swap u100 'token-a 'token-b)
+;; (contract-call? .defi-pool swap u100 'token-a 'token-b)
+;; ( get-pool-balance 'token-a ) defi-pool:15:8
+;; ↳ args: 'token-a
+;; u50000
+;; ( get-pool-balance 'token-b ) defi-pool:16:8
+;; ↳ args: 'token-b
+;; u75000
+;; ( calculate-output u100 u50000 u75000 ) defi-pool:18:12
+;; ↳ args: u100, u50000, u75000
+;; u149
+;; (ok u149)
+```
+
+### Interactive debugging with `::debug`
+
+Set breakpoints and step through execution:
+
+```clarity
+::debug (contract-call? .complex-contract process-batch)
+break validate-input
+;; Breakpoint set at validate-input
+continue
+;; Hit breakpoint at validate-input:23
+```
+
+Common navigation commands:
+
+{% hint style="info" %}
+* `step` or `s` – step into subexpressions
+* `finish` or `f` – complete the current expression
+* `next` or `n` – step over subexpressions
+* `continue` or `c` – resume execution
+{% endhint %}
+
+### Using `::get_costs` for targeted analysis
+
+```clarity
+::get_costs (contract-call? .defi-pool add-liquidity u1000 u1000)
+;; +----------------------+----------+------------+------------+
+;; | | Consumed | Limit | Percentage |
+;; |----------------------+----------+------------+------------|
+;; | Runtime | 12250 | 5000000000 | 0.00 % |
+;; | Read count | 6 | 15000 | 0.04 % |
+;; | Read length (bytes) | 192 | 100000000 | 0.00 % |
+;; | Write count | 3 | 15000 | 0.02 % |
+;; | Write length (bytes) | 96 | 15000000 | 0.00 % |
+;; +----------------------+----------+------------+------------+
+;; (ok {lp-tokens: u1000})
+```
+
+### Spotting costly operations with `::trace`
+
+```clarity
+::trace (contract-call? .complex-algo process-large-dataset)
+```
+
+Review the trace for loops with high iteration counts, nested map/filter operations, repeated contract calls, and large data structure manipulations.
+
+## Debugging workflows
+
+Master interactive debugging to identify issues quickly:
+
+```clarity
+::debug (contract-call? .counter count-up)
+;; ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.counter:9:3
+;; 6
+;; 7 ;; Increment the count for the caller
+;; 8 (define-public (count-up)
+;; ->9 (ok (map-set counters tx-sender (+ (get-count tx-sender) u1)))
+;; ^
+;; 10 )
+```
+
+### Analyzing failed transactions with `::trace`
+
+```clarity
+::trace (contract-call? .marketplace purchase u999)
+;; (contract-call? .marketplace purchase u999)
+;; ( get-listing u999 ) marketplace:45:12
+;; ↳ args: u999
+;; none
+;; (err u404) # Listing not found
+```
+
+### Using `::encode` and `::decode` for inspection
+
+```clarity
+::encode { id: u1, active: true }
+;; 0c0000000206616374697665030269640100000000000000000000000000000001
+
+::decode 0d0000000b48656c6c6f20776f726c64
+;; "Hello world"
+```
+
+### Testing time-dependent logic
+
+```clarity
+::get_block_height
+;; Current block height: 4
+
+::advance_chain_tip 100
+;; new burn height: 3
+;; new stacks height: 104
+
+(contract-call? .vesting claim)
+;; (ok {claimed: u2500, remaining: u7500})
+```
+
+##
diff --git a/docs/build/get-started/build-a-frontend/README.md b/docs/build/get-started/build-a-frontend/README.md
new file mode 100644
index 0000000000..a3aa67410b
--- /dev/null
+++ b/docs/build/get-started/build-a-frontend/README.md
@@ -0,0 +1,25 @@
+---
+description: Interact with your contracts with a proper frontend app
+---
+
+# Build a Frontend
+
+source: Hiro Blog
+
+A major part of building full-stack Stacks applications is creating a well designed UI with a solid UX. One of your primary tools for this is stacks.js, a JavaScript/Typescript library that simplifies working with contracts, wallets, and the Stacks network.
+
+{% hint style="info" %}
+This section assumes you have basic knowledge in front-end development and bootstrapping frontend frameworks.
+{% endhint %}
+
+### Components to your Stacks frontend app
+
+* [Authentication](authentication.md)
+* [Post-Conditions](post-conditions.md)
+* [Sending Transactions](sending-transactions.md)
+
+### Additional Resources
+
+* \[[Hiro Blog](https://www.hiro.so/blog/rich-app-templates-in-the-hiro-platform)] Rich App Templates in the Hiro Platform: Accelerating Web3 Development
+* \[[Hiro Blog](https://www.hiro.so/blog/lean-devops-strategies-for-your-web3-project)] Lean DevOps Strategies for Your Web3 Project
+* \[[Hiro Blog](https://www.hiro.so/blog/introducing-stacks-js-starters-launch-a-frontend-in-just-a-few-clicks)] Introducing Stacks.js Starters: Launch a Frontend in Just a Few Clicks
diff --git a/docs/build/get-started/build-a-frontend/authentication.md b/docs/build/get-started/build-a-frontend/authentication.md
new file mode 100644
index 0000000000..1d82697bf2
--- /dev/null
+++ b/docs/build/get-started/build-a-frontend/authentication.md
@@ -0,0 +1,69 @@
+# Authentication
+
+source: Hiro Blog
+
+Authenticating (connecting wallets) with a Stacks-supported wallet is a common task when building Stacks apps. On a web2 app, authentication usually means sending credentials to a central provider, which then verifies you and controls access. In web3, authentication uses a wallet and cryptographic signatures with libraries like stacks.js, letting users prove identity without a central party holding the keys.
+
+{% hint style="info" %}
+To learn more about how wallets and accounts work with Stacks, check out this [section](https://app.gitbook.com/s/H74xqoobupBWwBsVMJhK/network-fundamentals/accounts) in Learn.
+{% endhint %}
+
+Below is a simple example showing how to set up front-end authentication with `@stacks/connect` and access user data in the UI. The stacks.js monorepo contains several underlying packages specific to different use cases. The package `@stacks/connect` is the main connectivity package used in Stacks.
+
+## Authentication on the frontend
+
+Using `@stacks/connect` on the frontend will allow our frontend app to authenticate wallets, call our contract functions, and interact with the Stacks network.
+
+In the snippet below, you'll notice we have 3 functions setup to handle `connectWallet` , `disconnectWallet`, and for `getBns` . All 3 functions will be integral in how we want to display the 'Connect' and 'Disconnect' button in the UI.
+
+{% hint style="info" %}
+Retrieving a wallet account's associated [BNS](https://app.gitbook.com/s/H74xqoobupBWwBsVMJhK/network-fundamentals/bitcoin-name-system) is a staple of Stacks and for web3 identity. Check out [BNSv2](https://www.bnsv2.com/) for more information and for availably public API endpoints you could use.
+{% endhint %}
+
+import { connect, disconnect } from '@stacks/connect'
+import type { GetAddressesResult } from '@stacks/connect/dist/types/methods'
+import { useState } from 'react'
+
+function App() {
+ let [isConnected, setIsConnected] = useState<boolean>(false)
+ let [walletInfo, setWalletInfo] = useState<any>(null)
+ let [bns, setBns] = useState<string>('')
+
+ async function connectWallet() {
+ let connectionResponse: GetAddressesResult = await connect()
+ let bnsName = await getBns(connectionResponse.addresses[2].address)
+
+ setIsConnected(true)
+ setWalletInfo(connectionResponse)
+ setBns(bnsName)
+ }
+
+ async function disconnectWallet() {
+ disconnect();
+ }
+
+ async function getBns(stxAddress: string) {
+ let response = await fetch(`https://api.bnsv2.com/testnet/names/address/${stxAddress}/valid`)
+ let data = await response.json()
+
+ return data.names[0].full_name
+ }
+
+ return (
+ <>
+ <h3>Stacks Dev Quickstart Message Board</h3>
+ {isConnected ? (
+ <button onClick={disconnectWallet}>{
+ bns ? bns : walletInfo.addresses[2].address
+ }</button>
+ ) : (
+ <button onClick={connectWallet}>connect wallet</button>
+ )}
+ </>
+ )
+}
+
+
+The `connect()` method comes with the ability to configure how you want the wallet selector modal to appear for your app. You can decide which wallets to have only appear as an option or allow any wallet that follows the SIP-030 standard to appear as an available Stacks wallet.
+
+For the complete guides check out the [Stacks Connect](/broken/pages/JLRpUuDHPMxXaInZ9Vll) section.
diff --git a/docs/build/get-started/build-a-frontend/post-conditions.md b/docs/build/get-started/build-a-frontend/post-conditions.md
new file mode 100644
index 0000000000..ea986b6436
--- /dev/null
+++ b/docs/build/get-started/build-a-frontend/post-conditions.md
@@ -0,0 +1,107 @@
+---
+description: A unique security mechanism on Stacks to protect user funds
+---
+
+# Post-Conditions
+
+### What are post-conditions?
+
+Post-conditions are assertions about an on-chain transaction that must be met; otherwise, the transaction will abort during execution. In other words, post-conditions act as a safety net, allowing you to specify what state changes can occur in a transaction. This logic helps limit the amount of damage that can be done to a user and their assets, whether due to a bug or malicious behavior.
+
+Post conditions are an additional safety feature built into the Stacks chain itself that help to protect end users. Rather than being a function of Clarity smart contracts, they are implemented on the client side and meant to be an additional failsafe against malicious contracts.
+
+Put simply, post conditions are a set of conditions that must be met before a user's transaction will execute. The primary goal behind post conditions is to limit the amount of damage that can be done to a user's assets due to a bug, intentional or otherwise.
+
+They are sent as part of the transaction when the user initiates it, meaning we need to implement post-conditions on the frontend. Whenever you are transferring an asset (fungible or non-fungible) from one address to another, you should take advantage of post conditions.
+
+{% hint style="info" %}
+Head to the dedicated section on [post-conditions](/broken/pages/0KPrPPKItMGZZL2u4tiF) for more in-depth information.
+{% endhint %}
+
+We're going to use [stacks.js](https://github.com/stx-labs/stacks.js/tree/master/packages/transactions#post-conditions) to familiarize ourselves with constructing post-conditions on the frontend. And there are several different ways to construct post-conditions based on asset type.
+
+### Simple example
+
+In this example, we are attached a post-condition statement to a contract call transaction to protect the user's assets in the event the contract is malicious.
+
+import { request } from '@stacks/connect'
+import type { TransactionResult } from '@stacks/connect/dist/types/methods'
+import { Pc } from '@stacks/transactions'
+
+let postCond_1 = Pc.principal('ST11V9ZN6E6VG72SHMAVM9GDE30VD3VGW5Q1W9WX3')
+ .willSendEq(1)
+ .ft('ST1F7QA2MDF17S807EPA36TSS8AMEFY4KA9TVGWXT.sbtc-token', 'sbtc-token')
+
+let result: TransactionResult = await request('stx_callContract', {
+ // ...
+ postConditions: [postCond_1],
+ postConditionMode: 'deny',
+ // ...
+})
+
+
+Let's walkthrough the example above line-by-line to see what's happening when you attach a post-condition statement to a transaction.
+
+{% stepper %}
+{% step %}
+#### Declare post-condition statement
+
+```typescript
+let postCond_1 = Pc
+ // Specify who the sender of the expected sBTC transfer will originate from
+ .principal('ST11V9ZN6E6VG72SHMAVM9GDE30VD3VGW5Q1W9WX3')
+ // Specify the equality operator of the amount expected to be sent
+ .willSendEq(1)
+ // Specify the fungible token’s contract principal and asset name
+ .ft('ST1F7QA2MDF17S807EPA36TSS8AMEFY4KA9TVGWXT.sbtc-token', 'sbtc-token')
+```
+
+In this statement, you are declaring that the principal (usually the user that'll call this function) `ST11V9ZN6E6VG72SHMAVM9GDE30VD3VGW5Q1W9WX3` should only expect to send out _exactly_ 1 satoshi of sBTC during the execution of this contract call transaction.
+{% endstep %}
+
+{% step %}
+#### Include post-condition statement to transaction params
+
+let result: TransactionResult = await request('stx_callContract', {
+ // ...
+ postConditions: [postCond_1],
+ // ...
+})
+
+
+The transaction param of `postConditions` accepts an array of different post-condition statements. This means you can declare many post-condition statements of what the user should expect to happen during the execution of the transaction. This include any asset transfers coming from the user or from a contract.
+{% endstep %}
+
+{% step %}
+#### Determine post-condition mode
+
+The other related transaction param of `postConditionMode` is a special setting that is useful when you want to deal with other unexpected/unforeseen asset transfer events that the developer or user may not be aware of.
+
+let result: TransactionResult = await request('stx_callContract', {
+ // ...
+ postConditions: [postCond_1],
+ postConditionMode: 'deny',
+ // ...
+})
+
+
+By setting the `postConditionMode` to `deny` we are stating that if any other asset transfers, besides the ones we've declared, happen during the execution of the transaction, then force the entire transaction to fail.
+{% endstep %}
+{% endstepper %}
+
+### How post-conditions appear to the user
+
+Since post-conditions are declared on your frontend code, they also need to be visually displayed to users. Stacks-supported wallets handle that by displaying post-conditions on the transaction confirmation modals that popup when a user needs to confirm/approve a transaction.
+
+Post-conditions when appeared in a wallet's transaction confirmation modal
+
+After transaction confirmation and broadcasting, users are also able to see what post-conditions were set in their transaction on the transaction page of the Stacks Explorer. This gives users and developers more confidence in analyzing transactions.
+
+Analyze post-conditions set in transactions on the transactions page of the Stacks Explorer
+
+***
+
+### Additional Resources
+
+* \[[Post-Conditions](/broken/pages/0KPrPPKItMGZZL2u4tiF)] Dedicated section on post-conditions in these docs
+* \[[Hiro YT](https://youtu.be/xXgQB8NfdEY?si=eSZp4tlLOCkkqGRS)] ELI5: Post-Conditions on Stacks
diff --git a/docs/build/get-started/build-a-frontend/sending-transactions.md b/docs/build/get-started/build-a-frontend/sending-transactions.md
new file mode 100644
index 0000000000..ff55ffeea3
--- /dev/null
+++ b/docs/build/get-started/build-a-frontend/sending-transactions.md
@@ -0,0 +1,88 @@
+# Sending Transactions
+
+
+
+Any Stacks app is going to require sending transactions at some point, so how do we do that?
+
+{% hint style="warning" %}
+When you send Stacks transactions, don't forget to utilize post-conditions.
+{% endhint %}
+
+### Invoking contract call transactions
+
+In our example below, we're going to be showing how to invoke a contract function from the frontend which will prompt a user's wallet to confirm transaction. For this, we'll setup a `stx_callContract` to invoke the `add-message` public function of our contract taken from the [Developer Quickstart](../developer-quickstart.md). This function will accept a string content to be passed into our contract call.
+
+import { request } from '@stacks/connect'
+import type { TransactionResult } from '@stacks/connect/dist/types/methods'
+import { Cl, Pc } from '@stacks/transactions'
+import { useState } from 'react'
+
+function App() {
+ // ...
+ let [content, setContent] = useState<string>('')
+
+ async function addMessage() {
+ let postCond_1 = Pc.principal('ST11V9ZN6E6VG72SHMAVM9GDE30VD3VGW5Q1W9WX3')
+ .willSendEq(1)
+ .ft('ST1F7QA2MDF17S807EPA36TSS8AMEFY4KA9TVGWXT.sbtc-token', 'sbtc-token')
+
+ let result: TransactionResult = await request('stx_callContract', {
+ contract: 'ST11V9ZN6E6VG72SHMAVM9GDE30VD3VGW5Q1W9WX3.stacks-dev-quickstart-message-board',
+ functionName: 'add-message',
+ functionArgs: [Cl.stringUtf8(content)],
+ network: 'testnet',
+ postConditions: [postCond_1],
+ postConditionMode: 'deny',
+ sponsored: false
+ })
+
+ setContent('')
+ }
+
+ return (
+ <>
+ // ...
+ <span className='input-container'>
+ <button onClick={addMessage}>add-message</button>
+ <input type="text" onChange={e => setContent(e.target.value)}/>
+ </span>
+ </>
+ )
+}
+
+
+Let's breakdown some of the transaction params we specified in our string literal method of `stx_callContract`
+
+* `contract` : this requires the full contract principal of the target contract.
+* `functionName` : the name of the public function in the contract.
+* `functionArgs` : an array of the required function arguments in the same order as coded in the actual function of the Clarity contract. The `Cl` namespace has type converter methods that help with converting your argument into the required Clarity type.
+* `network` : the target network the contract is deployed on.
+* `postConditions` & `postConditionMode` : [Post-Conditions](../../post-conditions/overview.md) for the frontend are declared to protect user assets. The `Pc` helper from `@stacks/transactions` helps us to declare post-condition statements for any type of asset and equality operator.
+* `sponsored` : if the transaction fees will be sponsored or not.
+
+Invoking our `addMessage` function will prompt the user's connected wallet to prompt a transaction confirmation popup. This popup will display all of the relevant information of the transaction as well as the post-condition statements that we've declared.
+
+Invoking a contract function is just one example of sending transactions from the frontend. There is also calling read-only functions, initiating asset transfer transactions, and etc.
+
+### Invoking asset transfer transactions
+
+The `request` object also supports native asset transfers for both STX, fungible tokens, and non-fungible tokens. Here is an example of creating an sBTC transfer transaction on the frontend.
+
+Since sBTC is a SIP-010 fungible token, we'll invoke the `stx_transferSip10Ft` method.
+
+```typescript
+import { request } from '@stacks/connect';
+
+let response = await request('stx_transferSip10Ft', {
+ asset: 'SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token',
+ amount: 1,
+ recipient: 'SP202X1VHZMN5S90T44N7SSQ496PYQD66XCPA7BNK',
+ network: 'mainnet',
+});
+```
+
+***
+
+### Additional Resources
+
+* \[[Learn Stacks.js](/broken/pages/dH5waQhE6Vb7rhcrUG7z)] Head to the Learn Stacks.js section to see more examples
diff --git a/docs/build/get-started/clarity-crash-course.md b/docs/build/get-started/clarity-crash-course.md
new file mode 100644
index 0000000000..a7eb039f3a
--- /dev/null
+++ b/docs/build/get-started/clarity-crash-course.md
@@ -0,0 +1,322 @@
+---
+description: >-
+ The Stacks ecosystem has its own smart contract programming language called
+ Clarity.
+---
+
+# Clarity Crash Course
+
+source: Hiro Blog
+
+### Intro
+
+This is designed for people with some programming experience who are new to Clarity. You don't need prior smart contract development experience, but if you have experience with languages like Solidity, you'll pick this up quickly.
+
+Once you've briefly familiarized yourself with the language, consider the [Clarity Book](https://book.clarity-lang.org/) or the course [Clarity Universe](https://clarity-lang.org/universe) to continue your learning.
+
+{% hint style="info" %}
+Clarity is developed as a joint effort of [Hiro PBC](https://hiro.so/), [Algorand](http://algorand.com/), and various other stakeholders, that originally targets the Stacks blockchain.
+{% endhint %}
+
+### Your First Clarity Smart Contract
+
+We're going to walkthrough a basic Clarity smart contract using the [Clarity Playground](https://play.hiro.so/), an online REPL environment where you can write and run Clarity code in the browser. Visit that link and it will open up a new example contract for you on the left view, with an interactive REPL on the right view.
+
+The example counter contract provided when visiting the Clarity Playground
+
+{% hint style="info" %}
+Clarity Playground is a new tool to write and run Clarity code directly in the browser. With Clarity Playground, developers can test out concepts, try new ideas, or just, well…play around. Learn more [here](https://www.hiro.so/blog/meet-clarity-playground).
+{% endhint %}
+
+The example contract you'll see is a simple counter contract that will store the value of a `count` in a data variable and `increment` the count value by invoking a defined public function.
+
+{% code title="counter.clar" %}
+```clarity
+(define-data-var count uint u0)
+(define-data-var contract-owner principal tx-sender)
+(define-data-var cost uint u10)
+
+(define-read-only (get-count)
+ (var-get count)
+)
+
+(define-public (increment)
+ (begin
+ (print u"incrementing count")
+ (ok (var-set count (+ (var-get count) u1)))
+ )
+)
+```
+{% endcode %}
+
+Clarity's syntax is inspired by LISP: everything is an expression wrapped in parentheses. Function definitions, variable declarations, and parameters are lists inside lists. This makes Clarity concise and readable once you get used to it. Here are some characteristics of Clarity you'll notice:
+
+{% stepper %}
+{% step %}
+#### Everything in parentheses is an expression
+
+Clarity treats everything as expressions inside parentheses. Function definitions are calls to built-in functions; the function body is an expression. This uniformity helps reasoning about programs in Clarity.
+{% endstep %}
+
+{% step %}
+#### Uses LISP-like nesting
+
+Expect nested parentheses and expressions. You’ll often read code as lists inside lists, where each parentheses-enclosed group represents a call or expression.
+{% endstep %}
+{% endstepper %}
+
+{% hint style="info" %}
+In Clarity, there are public, private, and read-only functions:
+
+* public: can modify chain state and be called externally.
+* private: can modify state but only be called within the contract.
+* read-only: will fail if they attempt to modify state.
+{% endhint %}
+
+Let's expand on these ideas by walking through that example counter contract line by line.
+
+#### Defining data variables
+
+The built-in Clarity function of `define-data-var` allows you to define a new persisted variable for the contract. Only modifiable by the contract.
+
+```clarity
+;; defining a `count` variable to store a variable unsigned integer value
+(define-data-var count uint u0)
+
+;; defining a `contract-owner` for a specific `principal` value
+(define-data-var contract-owner principal tx-sender)
+
+;; defining a `cost` variable with an initial unsigned integer value of 10
+(define-data-var cost uint u10)
+```
+
+#### Defining a read-only function to read the current count value
+
+The built-in Clarity function of `define-read-only` defines a public read-only function. Cannot modify data maps or call mutating functions. May return any type.
+
+```clarity
+;; allows anyone to read the current `count` value in the contract
+(define-read-only (get-count)
+ (var-get count)
+)
+```
+
+#### Defining a public function to increment the count value
+
+This function prints a log event saying it's incrementing a counter, then reads the current counter, adds 1, saves it back on-chain, and returns success.
+
+```clarity
+;; Defines a public function named increment that anyone can call
+(define-public (increment)
+ ;; Starts a begin block, which allows multiple expressions to run in order.
+ (begin
+ ;; Logs/prints the text "incrementing count" (as a Unicode string) to
+ ;; the transaction output or event stream.
+ (print u"incrementing count")
+ ;; adds u1 to the current count and wraps the resulting value in a response type
+ (ok (var-set count (+ (var-get count) u1)))
+ )
+)
+```
+
+### Interact With Your Contract
+
+The Clarity Playground allows you to call your functions on the right side view via a REPL console that runs a simnet environment.
+
+
+
+What is Simnet?
+
+Simnet is optimized for providing fast feedback loops at the cost of correctness. Simnet does not provide a full simulated blockchain environment, so there are no concepts of transaction fees, new blocks, or consensus mechanisms.
+
+Instead, simnet focuses on letting you quickly iterate on your code and test the code of the contract locally through unit testing and integration testing. It’s a good preliminary debugging step before introducing the additional variables that come with a fully-fledged blockchain environment.
+
+Simnet is a local environment spun up on your machine and is a private instance—you cannot share a simnet environment with other devs and collaborate with them—and further, simnet has no persistent state. It resets with each run.
+
+
+
+On page load of the Clarity Playground, the example counter contract is automatically deployed to the REPL console on the right side. If you made any changes to the contract in the code editor on the left view, be sure to click on Deploy.
+
+Calling contracts in the console or calling any externally deployed contracts will need to be passed into the built-in Clarity function called `contract-call?` .
+
+Follow the steps below to interact with your counter contract:
+
+{% stepper %}
+{% step %}
+#### Call the read-only \`get-count\` function
+
+In the bottom right Clarity command console, paste in the below command to call your `get-count` function to see the current `count` value.
+
+{% code title="clarity command console" %}
+```clarity
+(contract-call? .contract-0 get-count)
+```
+{% endcode %}
+
+The console should return an initial value of `u0` since we haven't incremented the `count` yet.
+{% endstep %}
+
+{% step %}
+#### Call the public \`increment\` function
+
+Now let's finally increment our count value. In the bottom right Clarity command console, paste in the below command to call your `increment` function, which will increment the `count` value by 1.
+
+The console should return a value of `(ok true)` . This means the public function executed successfully and the count should have incremented.
+
+{% code title="clarity command console" %}
+```clarity
+(contract-call? .contract-0 increment)
+```
+{% endcode %}
+{% endstep %}
+
+{% step %}
+#### Call our \`get-count\` function again
+
+To see if our count value was really incremented, let's call our read-only `get-count` function once again.
+
+{% code title="clarity command console" %}
+```clarity
+(contract-call? .contract-0 get-count)
+```
+{% endcode %}
+
+The console should now returns a value of `u1` which is exactly what we'd expect.
+
+
+{% endstep %}
+{% endstepper %}
+
+Great! You just interacted with your first Clarity smart contract. Hopefully this gives you a good introduction to how the Clarity smart contract language looks and feels.
+
+***
+
+### Read Access into Bitcoin
+
+Clarity smart contracts on the Stacks layer can also read Bitcoin state and can be triggered by standard Bitcoin transactions. This is because Stacks nodes also run Bitcoin nodes as part of consensus, and they read and index Bitcoin state.
+
+Reading Bitcoin state in Clarity is made by possible by the built-in function: `get-burn-block-info?` and the keyword `burn-block-height` .
+
+* `burn-block-height` : This keyword returns the current block height of the underlying burnchain: Bitcoin. Check out the example snippet below:
+
+```clarity
+(> burn-block-height u1000)
+;; returns true if the current height of the underlying burn blockchain has passed 1000 blocks.
+```
+
+* `get-burn-block-info?` : This function fetches block data of the burnchain: Bitcoin. Check out the example snippet below:
+
+```clarity
+(get-burn-block-info? header-hash u677050)
+;; Returns (some 0xe671...)
+```
+
+
+
+Verifying bitcoin transactions in Clarity
+
+One of the most popular Clarity contracts that leverages read access into Bitcoin is the `clarity-bitcoin-lib` contract, maintained by Friedger. This contract intakes data of a bitcoin transaction and will verify that it was indeed mined in a Bitcoin block.
+
+For more info: [https://github.com/friedger/clarity-bitcoin](https://github.com/friedger/clarity-bitcoin)
+
+
+
+***
+
+### Flexible and secure modularization
+
+Many DAOs of the major Stacks apps implement a familiar contract design and architecture. This familiarity is inspired by the [ExecutorDAO](https://github.com/MarvinJanssen/executor-dao) framework, written by Marvin Janssen. This ExecutorDAO framework leverages the flexibility of having modularization in your smart contracts by compartmentalizing duties.
+
+The core tenets of the ExecutorDAO framework that make this possible are:
+
+1. Proposals are smart contracts.
+2. The core executes, the extensions give form.
+3. Ownership control happens via sending context.
+
+{% tabs %}
+{% tab title="Main DAO contract" %}
+The main DAO contract acts as the core contract where its sole purpose is to execute proposals and to keep a list of authorised extensions.
+
+{% code title="dao.clar" expandable="true" %}
+```clarity
+(use-trait proposal-trait .proposal-trait.proposal-trait)
+(use-trait extension-trait .extension-trait.extension-trait)
+
+;; ...
+
+;; --- Authorisation check
+(define-private (is-self-or-extension)
+ (ok (asserts! (or (is-eq tx-sender (as-contract tx-sender)) (is-extension contract-caller)) err-unauthorised))
+)
+
+;; ...
+
+;; --- Admin function to execute proposals
+(define-public (execute (proposal ) (sender principal))
+ (begin
+ (try! (is-self-or-extension))
+ (asserts! (map-insert executed-proposals (contract-of proposal) block-height) err-already-executed)
+ (print {event: "execute", proposal: proposal})
+ (as-contract (contract-call? proposal execute sender))
+ )
+)
+```
+{% endcode %}
+{% endtab %}
+
+{% tab title="A proposal extension contract" %}
+This proposal contract updates the whitelist of an example `.nft-escrow` contract that is owned by the main DAO contract. This proposal contract implements the `proposal-trait` and is passed into the main DAO contract's `execute` function for final approved execution.
+
+{% code title="proposal.clar" %}
+```clarity
+(impl-trait .proposal-trait.proposal-trait)
+
+(define-public (execute (sender principal))
+ (contract-call? .nft-escrow set-whitelisted .some-nft true)
+)
+```
+{% endcode %}
+{% endtab %}
+{% endtabs %}
+
+***
+
+### Testing Clarity Smart Contracts
+
+Once you get to writing more advanced smart contracts, properly testing them is paramount to protecting anyone who interacts with your contract.
+
+{% hint style="danger" %}
+Smart contracts are immutable once deployed. Bugs are permanent. Test them thoroughly.
+{% endhint %}
+
+* [Rendezvous Fuzz Testing](../rendezvous/overview.md): Use Rendezvous to hammer your contract with random inputs. It helps expose edge cases and vulnerabilities.
+* [Unit Testing in Clarinet](/broken/pages/xKpkZWiNCO3dwHoA9AeB): Unit testing verifies that individual contract functions behave as expected.
+
+***
+
+### Auditing Clarity Smart Contracts
+
+Auditors provide an independent, expert review of your smart contracts to identify vulnerabilities, logic flaws, edge cases, or design risks that might be missed during development. Here are a few Clarity smart contract auditors that are part of the Stacks community.
+
+* [Clarity Alliance](https://x.com/ClarAllianceSec)
+* [SetDev](https://x.com/setdevbtc)
+
+***
+
+### Additional Resources
+
+This brief overview should get your feet wet with Clarity. For deeper learning, we recommend:
+
+* [Clarity Book](https://book.clarity-lang.org/title-page.html)
+* [Clarity Universe](https://clarity-lang.org/universe)
+* [Clarity Playground](https://play.hiro.so/)
+* [Clarity Camp](https://learn.stacks.org/course/clarity-camp)
+* \[[StacksGov](https://github.com/stacksgov/sips/blob/main/sips/sip-002/sip-002-smart-contract-language.md)] SIP-002 The Clarity Smart Contract Language
+* \[[Hiro Blog](https://www.hiro.so/blog/web3-programming-languages-clarity-vs-solidity)] Web3 Programming Languages: Clarity vs. Solidity
+* \[[Stacks YT](https://youtu.be/hFqH1bJEvnw?si=yQADCvRNNjotuAga)] How Stacks' Language Clarity Enables Next Gen Smart Contracts
+* \[[StacksDevs YT](https://www.youtube.com/watch?v=WZe1DgJ1w-E)] How Stacks’ Smart Contract Language Prevents Exploitation
+* \[[Chainlink YT](https://youtu.be/OAVwd6SNJVU?si=UgfjmisBRbIYv27U)] Marvin Janssen: Clarity Smart Contracts for Stacks
+* [100+ Days of Clarity video series by Setzeus](https://youtube.com/playlist?list=PLFHm9eE6H5uhNQ4cUXRE-4HkXF1ekS0ZG\&si=q0NmD-e9_QBomK3a)
+* \[[waits.dev](https://waits.dev/writing/clarity-vs-solidity)] Clarity vs Solidity
+
+If you prefer jumping into Clarity's reference materials for definitions on all its types, functions, and keywords, head to [Clarity's Reference section](https://app.gitbook.com/s/GVj1Z9vMuEOMe7oH7Wnq/clarity/functions) of the docs.
diff --git a/docs/build/get-started/create-a-token/README.md b/docs/build/get-started/create-a-token/README.md
new file mode 100644
index 0000000000..c5f2922c5b
--- /dev/null
+++ b/docs/build/get-started/create-a-token/README.md
@@ -0,0 +1,23 @@
+# Create a Token
+
+Many Stacks projects need tokens to establish membership or as an incentive for building a thriving Web3 community. When building a project, you need to not only think about whether your project needs a token (and if so, what type), but also what other Stacks tokens your app will need to interact with.
+
+Rather than needing to work with external libraries, Clarity has built-in functions that make working with fungible and non-fungible tokens a breeze. Below are the 3 different types of tokens available on Stacks. Click into any one of them to learn what they are and the different ways to have them launched for your project.
+
+### Fungible Tokens
+
+Fungible tokens on Stacks are digital assets that are interchangeable and identical in value, much like traditional currencies such as the dollar or bitcoin. They are typically used for utilities like payments, rewards, and participation rights within decentralized applications on the Stacks blockchain.
+
+[**Launch a fungible token**](fungible-tokens.md)
+
+### Non-Fungible Tokens
+
+Non-fungible tokens (NFTs) on Stacks are unique digital assets that cannot be exchanged on a one-to-one basis, as each token holds distinct information and value. They are often used for representing ownership of digital art, collectibles, and other unique items within decentralized applications on the Stacks network. NFTs provide a way to authenticate and trade the unique characteristics of digital goods securely.
+
+[**Launch a non-fungible token**](non-fungible-tokens.md)
+
+### Semi-Fungible Tokens
+
+Semi-fungible tokens (SFTs) are a type of digital asset that possess qualities of both fungible and non-fungible tokens. Initially, SFTs can be exchanged on a one-to-one basis like fungible tokens because they represent identical assets or goods, often in specific series or batches. However, once redeemed or utilized, they transform into non-fungible tokens, acquiring unique attributes or identification. This makes SFTs versatile for applications such as event tickets, vouchers, or gaming items where controlled fungibility is beneficial.
+
+[**Launch a semi-fungible token**](semi-fungible-tokens.md)
diff --git a/docs/build/get-started/create-a-token/fungible-tokens.md b/docs/build/get-started/create-a-token/fungible-tokens.md
new file mode 100644
index 0000000000..cc61c10812
--- /dev/null
+++ b/docs/build/get-started/create-a-token/fungible-tokens.md
@@ -0,0 +1,260 @@
+---
+description: A guide to help you create your own fungible tokens
+---
+
+# Fungible Tokens
+
+source: Hiro blog
+
+Creating a fungible token on Stacks can happen a few different ways — using no-code launchpads or writing your own Clarity smart contract. This guide helps you pick the best path for your goals and gives you the implementation details to ship confidently, whether you’re deploying with clicks or code.
+
+### Custom Development
+
+For developers who want full control over their token implementation, here’s how to create a custom SIP-010 token on Stacks using Clarity. But before you deploy the token contract, you must have your token contract conform to the SIP-010 trait standard.
+
+{% stepper %}
+{% step %}
+#### Define SIP-010 fungible token trait
+
+
+
+What is SIP-010?
+
+[SIP-010](https://github.com/stacksgov/sips/blob/main/sips/sip-010/sip-010-fungible-token-standard.md) is the standard for defining fungible tokens on Stacks. Defining a common interface (known in Clarity as a "trait") allows different smart contracts, apps, and wallets to interoperate with fungible token contracts in a reusable way.
+
+
+
+Below is an implementation of the SIP-010 trait standard for fungible tokens. You can use the existing minimal standard SIP-010 trait or extend it by adding in your own custom traits. But the requirements of the SIP-010 traits are necessary to have at the minimum.
+
+{% code title="SIP-010 trait implementation" expandable="true" %}
+```clarity
+(define-trait sip-010-trait
+ (
+ ;; Transfer from the caller to a new principal
+ (transfer (uint principal principal (optional (buff 34))) (response bool uint))
+
+ ;; the human readable name of the token
+ (get-name () (response (string-ascii 32) uint))
+
+ ;; the ticker symbol, or empty if none
+ (get-symbol () (response (string-ascii 32) uint))
+
+ ;; the number of decimals used, e.g. 6 would mean 1_000_000 represents 1 token
+ (get-decimals () (response uint uint))
+
+ ;; the balance of the passed principal
+ (get-balance (principal) (response uint uint))
+
+ ;; the current total supply (which does not need to be a constant)
+ (get-total-supply () (response uint uint))
+
+ ;; an optional URI that represents metadata of this token
+ (get-token-uri () (response (optional (string-utf8 256)) uint))
+ )
+)
+```
+{% endcode %}
+
+All we are doing here is defining the function signatures for functions we'll need to implement in our token contract, which we can see a simple version of below.
+{% endstep %}
+
+{% step %}
+#### Implement SIP-010 trait in token contract
+
+Any token contract that wants to conform to the SIP-010 fungible token standard for Stacks needs to have this trait "implemented" in their token contract. See the below minimal token contract example of how this is done.
+
+{% code title="token-contract-clar" expandable="true" %}
+```clarity
+;; This contract implements the SIP-010 community-standard Fungible Token trait.
+(impl-trait 'SP3FBR2AGK5H9QBDH3EEN6DF8EK8JY7RX8QJ5SVTE.sip-010-trait-ft-standard.sip-010-trait)
+
+;; Define the FT, with no maximum supply
+(define-fungible-token clarity-coin)
+
+;; Define errors
+(define-constant ERR_OWNER_ONLY (err u100))
+(define-constant ERR_NOT_TOKEN_OWNER (err u101))
+
+;; Define constants for contract
+(define-constant CONTRACT_OWNER tx-sender)
+(define-constant TOKEN_NAME "Clarity Coin")
+(define-constant TOKEN_SYMBOL "CC")
+(define-constant TOKEN_DECIMALS u6) ;; 6 units displayed past decimal, e.g. 1.000_000 = 1 token
+
+(define-data-var token_uri (string-utf8 256) u"https://hiro.so") ;; utf-8 string with token metadata host
+
+;; SIP-010 function: Get the token balance of a specified principal
+(define-read-only (get-balance (who principal))
+ (ok (ft-get-balance clarity-coin who))
+)
+
+;; SIP-010 function: Returns the total supply of fungible token
+(define-read-only (get-total-supply)
+ (ok (ft-get-supply clarity-coin))
+)
+
+;; SIP-010 function: Returns the human-readable token name
+(define-read-only (get-name)
+ (ok TOKEN_NAME)
+)
+
+;; SIP-010 function: Returns the symbol or "ticker" for this token
+(define-read-only (get-symbol)
+ (ok TOKEN_SYMBOL)
+)
+
+;; SIP-010 function: Returns number of decimals to display
+(define-read-only (get-decimals)
+ (ok TOKEN_DECIMALS)
+)
+
+;; SIP-010 function: Returns the URI containing token metadata
+(define-read-only (get-token-uri)
+ (ok (some (var-get token_uri)))
+)
+
+;; Properly updates token URI by emitting a SIP-019 token metadata update notification
+(define-public (set-token-uri (value (string-utf8 256)))
+ (begin
+ (asserts! (is-eq tx-sender CONTRACT_OWNER) ERR_OWNER_ONLY)
+ (var-set token-uri value)
+ (ok (print {
+ notification: "token-metadata-update",
+ payload: {
+ contract-id: current-contract,
+ token-class: "ft"
+ }
+ })
+ )
+ )
+)
+
+;; Mint new tokens and send them to a recipient.
+;; Only the contract deployer can perform this operation.
+(define-public (mint (amount uint) (recipient principal))
+ (begin
+ (asserts! (is-eq tx-sender CONTRACT_OWNER) ERR_OWNER_ONLY)
+ (ft-mint? clarity-coin amount recipient)
+ )
+)
+
+;; SIP-010 function: Transfers tokens to a recipient
+;; Sender must be the same as the caller to prevent principals from transferring tokens they do not own.
+(define-public (transfer
+ (amount uint)
+ (sender principal)
+ (recipient principal)
+ (memo (optional (buff 34)))
+)
+ (begin
+ ;; #[filter(amount, recipient)]
+ (asserts! (or (is-eq tx-sender sender) (is-eq contract-caller sender)) ERR_NOT_TOKEN_OWNER)
+ (try! (ft-transfer? clarity-coin amount sender recipient))
+ (match memo to-print (print to-print) 0x)
+ (ok true)
+ )
+)
+```
+{% endcode %}
+
+This is the Clarity code we need in order to create an fungible token, with one additional function, `mint` that allows us to actually create a new fungible tokens. This `mint` function is not needed to adhere to the trait.
+
+The token contract example above is passing in an already deployed trait on mainnet into the `impl-trait` function. You can use this same deployed trait for your own token contract as well.
+
+{% hint style="success" %}
+Deployed SIP-010 trait contracts you can directly implement in your custom token contract:
+
+* \[mainnet] [SP3FBR2AGK5H9QBDH3EEN6DF8EK8JY7RX8QJ5SVTE.sip-010-trait-ft-standard.sip-010-trait](https://explorer.hiro.so/txid/SP3FBR2AGK5H9QBDH3EEN6DF8EK8JY7RX8QJ5SVTE.sip-010-trait-ft-standard?chain=mainnet)
+* \[testnet] [ST1NXBK3K5YYMD6FD41MVNP3JS1GABZ8TRVX023PT.sip-010-trait-ft-standard.sip-010-trait](https://explorer.hiro.so/txid/ST1NXBK3K5YYMD6FD41MVNP3JS1GABZ8TRVX023PT.sip-010-trait-ft-standard?chain=testnet)
+
+Reminder: when implementing these deployed traits in your contract, be sure to also add them as a contract requirement in Clarinet.
+{% endhint %}
+{% endstep %}
+{% endstepper %}
+
+### No-code Platforms
+
+Use community built no-code platforms that can quickly help you deploy tokens.
+
+
+
+STX.City
+
+[STX.CITY](https://stx.city/) is a one-click platform for launching tokens on Stacks. The platform is a comprehensive toolkit for memecoin creators, enabling them to grow their communities through features like AMM listing support (such as on [Alex](https://alexgo.io/), [Velar](https://velar.com/), and [Stackswap](https://app.stackswap.org/)), airdrops, token donations, and burn mechanisms.
+
+Check out [this](https://www.hiro.so/blog/building-stx-city-as-a-solo-dev-on-stacks) blog post by the founder of STX.City for more information.
+
+
+
+### Best Practices
+
+Here are some things to consider when creating your token and after your token is launched.
+
+
+
+How to format the token metadata?
+
+Example token metadata taken from the sBTC token:
+
+```json
+// https://ipfs.io/ipfs/bafkreibqnozdui4ntgoh3oo437lvhg7qrsccmbzhgumwwjf2smb3eegyqu
+
+{
+ "sip": 16,
+ "name": "sBTC",
+ "description": "BTC is a 1:1 Bitcoin-backed asset on the Stacks Bitcoin L2 that will allow developers to leverage the security, network effects, and .5T in latent capital of the Bitcoin network.",
+ "image": "https://ipfs.io/ipfs/bafkreiffe46h5voimvulxm2s4ddszdm4uli4rwcvx34cgzz3xkfcc2hiwi",
+ "properties": {
+ "decimals": 8,
+ "external_url": "https://sbtc.tech"
+ }
+}
+```
+
+Check out the [SIP-016](https://github.com/stacksgov/sips/blob/main/sips/sip-016/sip-016-token-metadata.md) standard for how you should define the schema of your metadata.
+
+
+
+
+
+How would I properly update my token metadata?
+
+If you plan on updating your token's metadata in the future, you should definitely implement a [SIP-019](https://github.com/stacksgov/sips/blob/main/sips/sip-019/sip-019-token-metadata-update-notifications.md) compliant token metadata update notification. Take a look at the example token contract above and you'll notice the `set-token-uri` function emits a SIP-019 compliant print event.
+
+```clarity
+;; ...
+(define-public (set-token-uri (value (string-utf8 256)))
+ (begin
+ (asserts! (is-eq tx-sender CONTRACT_OWNER) ERR_OWNER_ONLY)
+ (var-set token-uri value)
+ (ok (print {
+ notification: "token-metadata-update",
+ payload: {
+ contract-id: current-contract,
+ token-class: "ft"
+ }
+ })
+ )
+ )
+)
+;; ...
+```
+
+Hiro’s [Token Metadata API](https://www.hiro.so/token-metadata-api) watches for that specific print event (specifically the notification of "token-metadata-update") on the network and auto-updates the API’s database to reflect a change in the existing token’s metadata.
+
+If your token contract did not implement this print event, you could use the helper contract below to invoke a function that'll emit the same print event notification. Just invoke the `ft-metadata-update-notify` function of this contract below:
+
+[SP1H6HY2ZPSFPZF6HBNADAYKQ2FJN75GHVV95YZQ.token-metadata-update-notify](https://explorer.hiro.so/txid/SP1H6HY2ZPSFPZF6HBNADAYKQ2FJN75GHVV95YZQ.token-metadata-update-notify?chain=mainnet)
+
+
+
+### Additional Resources
+
+* \[[dev.to](https://dev.to/kamalthedev/ethereum-vs-bitcoin-a-deep-dive-into-token-standards-erc-20-vs-sip-10-vs-brc20-vs-stx20-12na)] A Deep Dive into Token Standards: ERC-20 vs. SIP-10 vs. BRC20 vs. STX20
+* \[[StacksGov](https://github.com/stacksgov/sips/blob/main/sips/sip-010/sip-010-fungible-token-standard.md)] SIP-010 Standard Trait Definition for Fungible Tokens
+* \[[StacksGov](https://github.com/stacksgov/sips/blob/main/sips/sip-016/sip-016-token-metadata.md)] SIP-016 Schema Definition for Metadata for Digital Assets
+* \[[StacksGov](https://github.com/stacksgov/sips/blob/main/sips/sip-019/sip-019-token-metadata-update-notifications.md)] SIP-019 Notifications for Token Metadata Updates
+* \[[contract](https://explorer.hiro.so/txid/SP1H6HY2ZPSFPZF6HBNADAYKQ2FJN75GHVV95YZQ.token-metadata-update-notify?chain=mainnet)] SP1H6HY2ZPSFPZF6HBNADAYKQ2FJN75GHVV95YZQ.token-metadata-update-notify
+* \[[StacksDevs YT](https://youtu.be/v0_Mexz3KJ8?si=iGMyxQX2lSktOTWp)] Fungible Token Standard (SIP-10) Tutorial For Bitcoin L2 Stacks
+* \[[LearnWeb3](https://learnweb3.io/lessons/sip-010-fungible-tokens-and-traits/)] SIP-010 Fungible Tokens & Traits
+* \[[Medium @n.campos.rojas](https://medium.com/@n.campos.rojas/learn-how-to-create-fungible-tokens-on-stacks-versus-on-ethereum-a6dae4986863)] Learn how to create fungible tokens on Stacks (versus on Ethereum)
diff --git a/docs/build/get-started/create-a-token/non-fungible-tokens.md b/docs/build/get-started/create-a-token/non-fungible-tokens.md
new file mode 100644
index 0000000000..306b4535e9
--- /dev/null
+++ b/docs/build/get-started/create-a-token/non-fungible-tokens.md
@@ -0,0 +1,209 @@
+---
+description: A guide to help you create your own non-fungible tokens
+---
+
+# Non-Fungible Tokens
+
+source: Hiro blog
+
+Create an NFT with Stacks because it builds **on Bitcoin** — inheriting the security and permanence of the most durable chain via Proof-of-Transfer. Clarity smart contracts make logic easy to audit, reducing the guessing and attack surface common in NFT projects. Plus, Stacks NFTs tap into a Bitcoin-aligned community that values ownership, longevity, and real on-chain utility.
+
+### Custom Development
+
+For developers who want full control over their token implementation, here’s how to create a custom SIP-009 NFT on Stacks using Clarity. But before you deploy the NFT contract, you must have your NFT contract conform to the SIP-009 trait standard.
+
+{% stepper %}
+{% step %}
+#### Define SIP-009 non-fungible token trait
+
+
+
+What is SIP-009?
+
+[SIP-009](https://github.com/stacksgov/sips/blob/main/sips/sip-009/sip-009-nft-standard.md) is the standard for defining fungible tokens on Stacks. Defining a common interface (known in Clarity as a "trait") allows different smart contracts, apps, and wallets to interoperate with non-fungible token contracts in a reusable way. Its primary purpose is to ensure that NFTs are composable and different tools know how to interact with them.
+
+
+
+Below is an implementation of the SIP-009 trait standard for non-fungible tokens. You can use the existing minimal standard SIP-009 trait or extend it by adding in your own custom traits. But the requirements of the SIP-009 traits are necessary to have at the minimum.
+
+{% code title="NFT trait standard" expandable="true" %}
+```clarity
+(define-trait nft-trait
+ (
+ ;; Last token ID, limited to uint range
+ (get-last-token-id () (response uint uint))
+
+ ;; URI for metadata associated with the token
+ (get-token-uri (uint) (response (optional (string-ascii 256)) uint))
+
+ ;; Owner of a given token identifier
+ (get-owner (uint) (response (optional principal) uint))
+
+ ;; Transfer from the sender to a new principal
+ (transfer (uint principal principal) (response bool uint))
+ )
+)
+```
+{% endcode %}
+
+All we are doing here is defining the function signatures for functions we'll need to implement in our NFT contract, which we can see a simple version of below.
+{% endstep %}
+
+{% step %}
+#### Implement SIP-009 trait in NFT contract
+
+Any NFT contract that wants to conform to the SIP-009 non-fungible token standard for Stacks needs to have this trait "implemented" in their NFT contract. See the below minimal NFT contract example of how this is done.
+
+{% code title="non-fungible-token.clar" expandable="true" %}
+```clarity
+;; This contract implements the SIP-009 community-standard Non-Fungible Token trait
+(impl-trait 'SP2PABAF9FTAJYNFZH93XENAJ8FVY99RRM50D2JG9.nft-trait.nft-trait)
+
+;; Define the NFT's name
+(define-non-fungible-token Your-NFT-Name uint)
+
+;; Keep track of the last minted token ID
+(define-data-var last-token-id uint u0)
+
+;; Define constants
+(define-constant CONTRACT_OWNER tx-sender)
+(define-constant COLLECTION_LIMIT u1000) ;; Limit to series of 1000
+
+(define-constant ERR_OWNER_ONLY (err u100))
+(define-constant ERR_NOT_TOKEN_OWNER (err u101))
+(define-constant ERR_SOLD_OUT (err u300))
+
+(define-data-var base-uri (string-ascii 256) "https://your.api.com/path/to/collection/{id}")
+
+;; SIP-009 function: Get the last minted token ID.
+(define-read-only (get-last-token-id)
+ (ok (var-get last-token-id))
+)
+
+;; SIP-009 function: Get link where token metadata is hosted
+(define-read-only (get-base-uri (token-id uint))
+ (ok (some (var-get base-uri)))
+)
+
+;; SIP-009 function: Get the owner of a given token
+(define-read-only (get-owner (token-id uint))
+ (ok (nft-get-owner? Your-NFT-Name token-id))
+)
+
+;; SIP-019 compliant token metadata update notification
+(define-public (set-base-uri (value (string-ascii 256)))
+ (begin
+ (asserts! (is-eq tx-sender CONTRACT_OWNER) ERR_OWNER_ONLY)
+ (var-set base-uri value)
+ (ok (print {
+ notification: "token-metadata-update",
+ payload: {
+ token-class: "nft",
+ contract-id: current-contract,
+ }
+ })
+ )
+ )
+)
+
+;; SIP-009 function: Transfer NFT token to another owner.
+(define-public (transfer (token-id uint) (sender principal) (recipient principal))
+ (begin
+ ;; #[filter(sender)]
+ (asserts! (is-eq tx-sender sender) ERR_NOT_TOKEN_OWNER)
+ (nft-transfer? Your-NFT-Name token-id sender recipient)
+ )
+)
+
+;; Mint a new NFT.
+(define-public (mint (recipient principal))
+ ;; Create the new token ID by incrementing the last minted ID.
+ (let ((token-id (+ (var-get last-token-id) u1)))
+ ;; Ensure the collection stays within the limit.
+ (asserts! (< (var-get last-token-id) COLLECTION_LIMIT) ERR_SOLD_OUT)
+ ;; Only the contract owner can mint.
+ (asserts! (is-eq tx-sender CONTRACT_OWNER) ERR_OWNER_ONLY)
+ ;; Mint the NFT and send it to the given recipient.
+ (try! (nft-mint? Your-NFT-Name token-id recipient))
+
+ ;; Update the last minted token ID.
+ (var-set last-token-id token-id)
+ ;; Return a success status and the newly minted NFT ID.
+ (ok token-id)
+ )
+)
+```
+{% endcode %}
+
+This is the Clarity code we need in order to create an NFT, with one additional function, `mint` that allows us to actually create a new NFT. This `mint` function is not needed to adhere to the trait.
+
+The token contract example above is passing in an already deployed trait on mainnet into the `impl-trait` function. You can use this same deployed trait for your own NFT contract as well.
+
+{% hint style="success" %}
+Deployed SIP-010 trait contracts you can directly implement in your custom token contract:
+
+* \[mainnet] SP2PABAF9FTAJYNFZH93XENAJ8FVY99RRM50D2JG9.nft-trait
+* \[testnet] ST1NXBK3K5YYMD6FD41MVNP3JS1GABZ8TRVX023PT.nft-trait
+
+Reminder: when implementing these deployed traits in your contract, be sure to also add them as a contract requirement in Clarinet.
+{% endhint %}
+{% endstep %}
+{% endstepper %}
+
+### Best Practices
+
+Here are some things to consider when creating your NFT and after your NFT is launched.
+
+
+
+How to format the NFT metadata?
+
+Check out the [SIP-016](https://github.com/stacksgov/sips/blob/main/sips/sip-016/sip-016-token-metadata.md) standard for how you should define the schema of your metadata.
+
+
+
+
+
+How would I properly update my NFT metadata?
+
+If you plan on updating your NFT's metadata in the future, you should definitely implement a function that emits a [SIP-019](https://github.com/stacksgov/sips/blob/main/sips/sip-019/sip-019-token-metadata-update-notifications.md) compliant token metadata update notification. Take a look at the example NFT contract above and you'll notice the `set-base-uri` function emits a SIP-019 compliant print event.
+
+;; ...
+(define-public (set-base-uri (value (string-ascii 256)))
+ (begin
+ (asserts! (is-eq tx-sender CONTRACT_OWNER) ERR_OWNER_ONLY)
+ (var-set base-uri value)
+ (ok (print {
+ notification: "token-metadata-update",
+ payload: {
+ token-class: "nft",
+ contract-id: current-contract,
+ }
+ })
+ )
+ )
+)
+;; ...
+
+
+Hiro’s [Token Metadata API](https://www.hiro.so/token-metadata-api) watches for that specific print event (specifically the notification of "token-metadata-update") on the network and auto-updates the API’s database to reflect a change in the existing NFT’s metadata.
+
+If your NFT contract did not implement this print event, you could use the helper contract below to invoke a function that'll emit the same print event notification. Just invoke the `nft-metadata-update-notify` function of this contract below:
+
+[SP1H6HY2ZPSFPZF6HBNADAYKQ2FJN75GHVV95YZQ.token-metadata-update-notify](https://explorer.hiro.so/txid/SP1H6HY2ZPSFPZF6HBNADAYKQ2FJN75GHVV95YZQ.token-metadata-update-notify?chain=mainnet)
+
+
+
+### Additional Resources
+
+* \[[Stacks](https://www.stacks.co/explore/nfts)] Explore NFTs on Stacks
+* \[[Clarity Book](https://book.clarity-lang.org/ch10-01-sip009-nft-standard.html)] SIP009: the NFT standard
+* \[[StacksGov](https://github.com/stacksgov/sips/blob/main/sips/sip-010/sip-010-fungible-token-standard.md)] SIP-009 Standard Trait Definition for Non-Fungible Tokens
+* \[[StacksGov](https://github.com/stacksgov/sips/blob/main/sips/sip-016/sip-016-token-metadata.md)] SIP-016 Schema Definition for Metadata for Digital Assets
+* \[[StacksGov](https://github.com/stacksgov/sips/blob/main/sips/sip-019/sip-019-token-metadata-update-notifications.md)] SIP-019 Notifications for Token Metadata Updates
+* \[[contract](https://explorer.hiro.so/txid/SP1H6HY2ZPSFPZF6HBNADAYKQ2FJN75GHVV95YZQ.token-metadata-update-notify?chain=mainnet)] SP1H6HY2ZPSFPZF6HBNADAYKQ2FJN75GHVV95YZQ.token-metadata-update-notify
+* \[[Hiro YT](https://youtu.be/Hejsz-pivM4?si=SrOlgC9KK6YQvEy7)] How to Display NFTs in a Wallet Using the Token Metadata API
+* \[[Hiro YT](https://youtu.be/xwbXNgSvMkk?si=Dl8KEL2KsmPy1kON)] A Beginner's Overview of the Megapont Ape NFT Clarity Smart Contract
+* \[[Hiro YT](https://youtu.be/Ajuq6j2NXM8?si=Gj-Z5sxJ28FRyPmN)] Stacker Chat with Muneeb Ali: Diving Deeper into Bitcoin NFTs
+* \[[Hiro Blog](https://www.hiro.so/blog/breaking-down-nft-code-snippets-in-clarity)] Breaking Down NFT Code Snippets in Clarity
+* \[[Hiro Blog](https://www.hiro.so/blog/how-sigle-built-nft-gated-features-in-their-app)] How Sigle Built NFT-Gated Features in Their App
diff --git a/docs/build/get-started/create-a-token/semi-fungible-tokens.md b/docs/build/get-started/create-a-token/semi-fungible-tokens.md
new file mode 100644
index 0000000000..9d5673471c
--- /dev/null
+++ b/docs/build/get-started/create-a-token/semi-fungible-tokens.md
@@ -0,0 +1,230 @@
+---
+description: A guide to help you create your own semi-fungible tokens
+---
+
+# Semi-Fungible Tokens
+
+Semi-fungible tokens (SFTs) are a hybrid token structure that embraces parts of both FTs (fungible tokens) and NFTs. SFTs are interchangeable (like FTs) and can be traded between users like cash—1 SFT has the same value as another SFT in the same collection. But each SFT also has a unique identifier (like NFTs).
+
+SFTs are also particularly well suited for Web3 gaming and applications that need to issue lots of different tokens because SFTs enable different asset classes to be managed by a single smart contract (which as a developer is easier to manage and as a user results in cheaper transaction fees).
+
+### Custom Development
+
+For developers who want full control over their SFT implementation, here’s how to create a custom SIP-013 SFT on Stacks using Clarity. But before you deploy the SFT contract, you must have your SFT contract conform to the SIP-013 trait standard.
+
+{% stepper %}
+{% step %}
+#### Define SIP-013 semi-fungible token trait
+
+
+
+What is SIP-013?
+
+[SIP-013](https://github.com/stacksgov/sips/blob/main/sips/sip-013/sip-013-semi-fungible-token-standard.md) is the standard for defining semi-fungible tokens on Stacks. Defining a common interface (known in Clarity as a "trait") allows different smart contracts, apps, and wallets to interoperate with semi-fungible token contracts in a reusable, standard way.
+
+
+
+Below is an implementation of the SIP-013 trait standard for semi-fungible tokens. You can use the existing minimal standard SIP-013 trait or extend it by adding in your own custom traits. But the requirements of the SIP-013 traits are necessary to have at the minimum.
+
+{% code title="SFT trait standard" expandable="true" %}
+```clarity
+(define-trait sip013-semi-fungible-token-trait
+ (
+ ;; Get a token type balance of the passed principal.
+ (get-balance (uint principal) (response uint uint))
+
+ ;; Get the total SFT balance of the passed principal.
+ (get-overall-balance (principal) (response uint uint))
+
+ ;; Get the current total supply of a token type.
+ (get-total-supply (uint) (response uint uint))
+
+ ;; Get the overall SFT supply.
+ (get-overall-supply () (response uint uint))
+
+ ;; Get the number of decimal places of a token type.
+ (get-decimals (uint) (response uint uint))
+
+ ;; Get an optional token URI that represents metadata for a specific token.
+ (get-token-uri (uint) (response (optional (string-ascii 256)) uint))
+
+ ;; Transfer from one principal to another.
+ (transfer (uint uint principal principal) (response bool uint))
+
+ ;; Transfer from one principal to another with a memo.
+ (transfer-memo (uint uint principal principal (buff 34)) (response bool uint))
+ )
+)
+
+```
+{% endcode %}
+
+All we are doing here is defining the function signatures for functions we'll need to implement in our SFT contract, which we can see a simple version of below.
+
+**\[optional] transfer-many specification**\
+SIP013 Semi-fungible tokens can also optionally implement the trait `sip013-transfer-many-trait` to offer a built-in "transfer-many" features for bulk token transfers.
+
+{% code title="SFT transfer many trait" %}
+```clarity
+(define-trait sip013-transfer-many-trait
+ (
+ ;; Transfer many tokens at once.
+ (transfer-many ((list 200 {token-id: uint, amount: uint, sender: principal, recipient: principal})) (response bool uint))
+
+ ;; Transfer many tokens at once with memos.
+ (transfer-many-memo ((list 200 {token-id: uint, amount: uint, sender: principal, recipient: principal, memo: (buff 34)})) (response bool uint))
+ )
+)
+```
+{% endcode %}
+{% endstep %}
+
+{% step %}
+#### Implement SIP-013 trait in SFT contract
+
+Any SFT contract that wants to conform to the SIP-013 semi-fungible token standard for Stacks needs to have this trait "implemented" in their SFT contract. See the below minimal SFT contract example of how this is done.
+
+{% code title="semi-fungible-token.clar" expandable="true" %}
+```clarity
+(impl-trait 'SPDBEG5X8XD50SPM1JJH0E5CTXGDV5NJTKAKKR5V.sip013-semi-fungible-token-trait.sip013-semi-fungible-token-trait)
+(impl-trait 'SPDBEG5X8XD50SPM1JJH0E5CTXGDV5NJTKAKKR5V.sip013-transfer-many-trait.sip013-transfer-many-trait)
+
+(define-fungible-token semi-fungible-token)
+(define-non-fungible-token semi-fungible-token-id {token-id: uint, owner: principal})
+(define-map token-balances {token-id: uint, owner: principal} uint)
+(define-map token-supplies uint uint)
+
+(define-constant contract-owner tx-sender)
+
+(define-constant err-owner-only (err u100))
+(define-constant err-insufficient-balance (err u1))
+(define-constant err-invalid-sender (err u4))
+
+(define-private (set-balance (token-id uint) (balance uint) (owner principal))
+ (map-set token-balances {token-id: token-id, owner: owner} balance)
+)
+
+(define-private (get-balance-uint (token-id uint) (who principal))
+ (default-to u0 (map-get? token-balances {token-id: token-id, owner: who}))
+)
+
+(define-read-only (get-balance (token-id uint) (who principal))
+ (ok (get-balance-uint token-id who))
+)
+
+(define-read-only (get-overall-balance (who principal))
+ (ok (ft-get-balance semi-fungible-token who))
+)
+
+(define-read-only (get-total-supply (token-id uint))
+ (ok (default-to u0 (map-get? token-supplies token-id)))
+)
+
+(define-read-only (get-overall-supply)
+ (ok (ft-get-supply semi-fungible-token))
+)
+
+(define-read-only (get-decimals (token-id uint))
+ (ok u0)
+)
+
+(define-read-only (get-token-uri (token-id uint))
+ (ok none)
+)
+
+;; #[allow(unchecked_params)]
+(define-public (transfer (token-id uint) (amount uint) (sender principal) (recipient principal))
+ (let
+ (
+ (sender-balance (get-balance-uint token-id sender))
+ )
+ (asserts! (or (is-eq sender tx-sender) (is-eq sender contract-caller)) err-invalid-sender)
+ (asserts! (<= amount sender-balance) err-insufficient-balance)
+ (try! (ft-transfer? semi-fungible-token amount sender recipient))
+ (try! (tag-nft-token-id {token-id: token-id, owner: sender}))
+ (try! (tag-nft-token-id {token-id: token-id, owner: recipient}))
+ (set-balance token-id (- sender-balance amount) sender)
+ (set-balance token-id (+ (get-balance-uint token-id recipient) amount) recipient)
+ (print {type: "sft_transfer", token-id: token-id, amount: amount, sender: sender, recipient: recipient})
+ (ok true)
+ )
+)
+
+(define-public (transfer-memo (token-id uint) (amount uint) (sender principal) (recipient principal) (memo (buff 34)))
+ (begin
+ (try! (transfer token-id amount sender recipient))
+ (print memo)
+ (ok true)
+ )
+)
+
+(define-private (transfer-many-iter (item {token-id: uint, amount: uint, sender: principal, recipient: principal}) (previous-response (response bool uint)))
+ (match previous-response prev-ok (transfer (get token-id item) (get amount item) (get sender item) (get recipient item)) prev-err previous-response)
+)
+
+(define-public (transfer-many (transfers (list 200 {token-id: uint, amount: uint, sender: principal, recipient: principal})))
+ (fold transfer-many-iter transfers (ok true))
+)
+
+(define-private (transfer-many-memo-iter (item {token-id: uint, amount: uint, sender: principal, recipient: principal, memo: (buff 34)}) (previous-response (response bool uint)))
+ (match previous-response prev-ok (transfer-memo (get token-id item) (get amount item) (get sender item) (get recipient item) (get memo item)) prev-err previous-response)
+)
+
+(define-public (transfer-many-memo (transfers (list 200 {token-id: uint, amount: uint, sender: principal, recipient: principal, memo: (buff 34)})))
+ (fold transfer-many-memo-iter transfers (ok true))
+)
+
+(define-public (mint (token-id uint) (amount uint) (recipient principal))
+ (begin
+ (asserts! (is-eq tx-sender contract-owner) err-owner-only)
+ (try! (ft-mint? semi-fungible-token amount recipient))
+ (try! (tag-nft-token-id {token-id: token-id, owner: recipient}))
+ (set-balance token-id (+ (get-balance-uint token-id recipient) amount) recipient)
+ (map-set token-supplies token-id (+ (unwrap-panic (get-total-supply token-id)) amount))
+ (print {type: "sft_mint", token-id: token-id, amount: amount, recipient: recipient})
+ (ok true)
+ )
+)
+
+(define-private (tag-nft-token-id (nft-token-id {token-id: uint, owner: principal}))
+ (begin
+ (and
+ (is-some (nft-get-owner? semi-fungible-token-id nft-token-id))
+ (try! (nft-burn? semi-fungible-token-id nft-token-id (get owner nft-token-id)))
+ )
+ (nft-mint? semi-fungible-token-id nft-token-id (get owner nft-token-id))
+ )
+)
+```
+{% endcode %}
+
+This is the Clarity code we need in order to create a SFT, with an additional function, `mint` that allows us to actually create a new SFT. This `mint` function is not needed to adhere to the trait.
+
+The token contract example above is passing in already deployed traits on mainnet into the `impl-trait` function. You can use these same deployed traits for your own SFT contract as well.
+
+{% hint style="success" %}
+Deployed SIP-013 trait contracts you can directly implement in your custom token contract:
+
+* \[mainnet] SPDBEG5X8XD50SPM1JJH0E5CTXGDV5NJTKAKKR5V.sip013-semi-fungible-token-trait
+* \[mainnet] SPDBEG5X8XD50SPM1JJH0E5CTXGDV5NJTKAKKR5V.sip013-transfer-many-trait
+
+Reminder: when implementing these deployed traits in your contract, be sure to also add them as contract requirements in Clarinet.
+{% endhint %}
+{% endstep %}
+{% endstepper %}
+
+### Best Practices
+
+
+
+How to deal with post-conditions on SFTs?
+
+Check out the SIP-013 standard for more info on dealing with post-conditions for SFTs.
+
+
+
+### Additional Resources
+
+* \[[StacksGov](https://github.com/stacksgov/sips/blob/main/sips/sip-013/sip-013-semi-fungible-token-standard.md)] SIP-013 Standard Trait Definition for Semi-Fungible Tokens
+* \[[Hiro YT](https://youtu.be/a7c8aBiIkD4?si=k4cUS5DHrUsnm7Q9)] A Walkthrough of a SIP013 Implementation of SFTs on Stacks
+* \[[DegenLab](https://docs.degenlab.io/gamefistacks/sfts/general-idea-and-base-sfts-static-deployments)] Example of SFT implementation with DegenLab
diff --git a/docs/build/get-started/developer-quickstart.md b/docs/build/get-started/developer-quickstart.md
new file mode 100644
index 0000000000..b75921d6a4
--- /dev/null
+++ b/docs/build/get-started/developer-quickstart.md
@@ -0,0 +1,853 @@
+---
+description: Your 0→1 guide for building a Clarity contract and app on Stacks.
+---
+
+# Developer Quickstart
+
+
+
+**Welcome to the Stacks Developer Quickstart Guide!**\
+This is your fast-track path for understanding what you'll need to become a Stacks developer. In this guide, you’ll build a real Clarity smart contract, wire up a functioning Stacks app, and pick up about 75% of the practical knowledge every Stacks builder needs. Whether you’re shipping your first project or leveling up your skills, this guide takes you from zero to deployed—quickly and confidently.
+
+### What you'll achieve
+
+By the end of this quickstart, you’ll have built an onchain app by:
+
+* Building a Clarity smart contract with Clarinet
+* Utilize the 1:1 Bitcoin backed token, sBTC
+* Deploying your smart contract to Stacks' testnet
+* Interacting with your deployed contract from a frontend app
+
+{% hint style="success" %}
+**Why Stacks?**
+
+Stacks is a fast, low-cost, builder-friendly layer 2 network on Bitcoin. It’s built on Bitcoin, inheriting Bitcoin’s battle-tested security. By jumping into this guide, you’re joining the Stacks community that’s bringing a global onchain economy to Bitcoin.
+{% endhint %}
+
+### What You'll Build
+
+The app you'll build will be a message board contract. Users can add a new message to store on-chain for a fee of 1 satoshi in sBTC. Other functionality to read data from the contract will also be handled. Besides sBTC, there will be other things that'll be introduced to you such as post-conditions, Bitcoin read access, unit testing, wallet connectivity, BNS, Hiro, and more. Hopefully all this will give you a good flavor of what you can expect in the Stacks builder ecosystem.
+
+Let's start building on Bitcoin! :orange\_square:
+
+{% hint style="info" %}
+**Prerequisites**
+
+* Basic familiarity with web development
+* Basic familiarity with web3 concepts
+* A modern web browser
+* Node.js
+* Visual Studio Code or any other popular IDE
+{% endhint %}
+
+### Set Up Your Developer Environment
+
+{% stepper %}
+{% step %}
+**Install Clarinet**
+
+Clarinet is the popular CLI tool to build, test, and deploy smart contracts on the Stacks blockchain.
+
+Below are a few different ways to install Clarinet on your machine using your terminal. Refer to the dedicated [installation](../clarinet/overview.md) guide in the 'Learn Clarinet' section for more information.
+
+{% tabs %}
+{% tab title="Homebrew" %}
+```bash
+brew install clarinet
+```
+{% endtab %}
+
+{% tab title="Winget" %}
+```bash
+winget install clarinet
+```
+{% endtab %}
+
+{% tab title="Source" %}
+```bash
+sudo apt install build-essential pkg-config libssl-dev
+git clone https://github.com/stx-labs/clarinet
+cd clarinet
+cargo clarinet-install
+```
+{% endtab %}
+
+{% tab title="Binary" %}
+```bash
+wget -nv https://github.com/stx-labs/clarinet/releases/latest/download/clarinet-linux-x64-glibc.tar.gz -O clarinet-linux-x64.tar.gz
+tar -xf clarinet-linux-x64.tar.gz
+chmod +x ./clarinet
+mv ./clarinet /usr/local/bin
+```
+{% endtab %}
+{% endtabs %}
+{% endstep %}
+
+{% step %}
+**Install Clarity Extension**
+
+You'll also want to install the Clarity Extension for your code editor. The official one is '[Clarity - Stacks Labs](https://marketplace.visualstudio.com/items?itemName=StacksLabs.clarity-stacks)' which is maintained by [Stacks Labs](https://stackslabs.com/).
+
+
+
+What is Clarity?
+
+Clarity is Stacks' smart contract language, designed for safety and predictability.
+
+Clarity is inspired by LISP and uses a functional programming approach. Everything in Clarity is an expression wrapped in parentheses. This can be a bit overwhelming at first if you are used to languages like JavaScript or Solidity, but the learning curve is short and Clarity is a simple language to understand once you dive in and start using it.
+
+Check out the [Clarity Crash Course](clarity-crash-course.md) for a quick primer.
+
+
+
+The 'Clarity - Stacks Labs' extension as it appears in Visual Studio Code.
+{% endstep %}
+
+{% step %}
+**Install a Stacks wallet**
+
+There are many Stacks supported wallets in the market. For this guide, we'll be using the [Leather](https://leather.io/) wallet. Leather supports Stacks, Bitcoin, and other Bitcoin related meta-protocols. Download and install its browser extension so you can interact with your smart contract later on in this guide. Make sure to switch to the **Testnet** network in your wallet settings. Later on, we'll show you how to get testnet STX and sBTC tokens that you'll use for contract interaction.
+{% endstep %}
+{% endstepper %}
+
+### Create a Clarity smart contract
+
+{% stepper %}
+{% step %}
+**Create a new Clarinet project**
+
+Let's start by creating a new Clarinet project which will house our smart contract. The `clarinet new` command sets up everything you need for smart contract development, including a testing framework, deployment configurations, and a local development environment.
+
+{% code title="terminal" %}
+```
+clarinet new my-stacks-contracts
+```
+{% endcode %}
+
+A Clarinet project will be scaffolded with the below:
+
+{% code title="terminal" expandable="true" %}
+```
+Created directory my-stacks-contracts
+Created directory contracts
+Created directory settings
+Created directory tests
+Created file Clarinet.toml
+Created file settings/Mainnet.toml
+Created file settings/Testnet.toml
+Created file settings/Devnet.toml
+Created directory .vscode
+Created file .vscode/settings.json
+Created file .vscode/tasks.json
+Created file .gitignore
+Created file .gitattributes
+Created file package.json
+Created file tsconfig.json
+Created file vitest.config.ts
+
+----------------------------
+Hint: what's next?
+Switch to the newly created directory with:
+
+ $ cd my-stacks-contracts
+
+Once you are ready to write your contracts, run the following commands:
+
+ $ clarinet contract new
+ Create new contract scaffolding, including test files.
+
+ $ clarinet check
+ Check contract syntax for all files in ./contracts.
+```
+{% endcode %}
+{% endstep %}
+
+{% step %}
+**Generate your contract**
+
+Now that we have our project structure, let's create a smart contract. Navigate into your project directory and use Clarinet's contract generator:
+
+```sh
+$ cd my-stacks-contracts
+$ clarinet contract new message-board
+Created file contracts/message-board.clar
+Created file tests/message-board.test.ts
+Updated Clarinet.toml with contract message-board
+```
+
+Clarinet automatically creates both your contract file and a corresponding test file.
+{% endstep %}
+{% endstepper %}
+
+### Write your Clarity smart contract
+
+{% stepper %}
+{% step %}
+**Define constants**
+
+Open `contracts/message-board.clar` and remove its existing content. This is where we'll start writing our own Clarity smart contract.
+
+Let's first define some constants:
+
+* contract owner to establish control access
+* custom error codes to handle errors in functions
+
+;; Simple Message Board Contract
+;; This contract allows users to read and post messages for a fee in sBTC.
+
+;; Define contract owner
+(define-constant CONTRACT_OWNER tx-sender)
+
+;; Define error codes
+(define-constant ERR_NOT_ENOUGH_SBTC (err u1004))
+ (define-constant ERR_NOT_CONTRACT_OWNER (err u1005))
+ (define-constant ERR_BLOCK_NOT_FOUND (err u1003))
+
+
+You'll notice in the `CONTRACT_OWNER` constant that `tx-sender` is set in place as the value. When this contract is deployed, the Clarity VM will determine who the `tx-sender` is based on who deployed the contract. This allows the hardcoded `tx-sender` to always point to the principal that deployed the contract.
+{% endstep %}
+
+{% step %}
+**Define data storage**
+
+We'll then need to define some data storage:
+
+* A map to store key-value pairs of the message id and it's related metadata
+* A data variable to count the total number of messages added
+
+;; Define a map to store messages
+;; Each message has an ID, content, author, and Bitcoin block height timestamp
+(define-map messages
+ uint
+ {
+ message: (string-utf8 280),
+ author: principal,
+ time: uint,
+ }
+)
+
+;; Counter for total messages
+(define-data-var message-count uint u0)
+
+{% endstep %}
+
+{% step %}
+**Define an add message function**
+
+Next up is our main function of the contract. This function allows users to add a new message to the contract for a fee of 1 satoshi in sBTC. Invoking this function will change the state of our contract and update the data storage pieces we setup before.
+
+;; Public function to add a new message for 1 satoshi of sBTC
+;; @format-ignore
+(define-public (add-message (content (string-utf8 280)))
+ (let ((id (+ (var-get message-count) u1)))
+ (try! (restrict-assets? contract-caller
+ ((with-ft 'SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token "sbtc-token" u1))
+ (unwrap!
+ ;; Charge 1 satoshi of sBTC from the caller
+ (contract-call? 'SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token
+ transfer u1 contract-caller current-contract none
+ )
+ ERR_NOT_ENOUGH_SBTC
+ )
+ ))
+ ;; Store the message with current Bitcoin block height
+ (map-set messages id {
+ message: content,
+ author: contract-caller,
+ time: burn-block-height,
+ })
+ ;; Update message count
+ (var-set message-count id)
+ ;; Emit event for the new message
+ (print {
+ event: "[Stacks Dev Quickstart] New Message",
+ message: content,
+ id: id,
+ author: contract-caller,
+ time: burn-block-height,
+ })
+ ;; Return the message ID
+ (ok id)
+ )
+)
+
+
+There's quite a lot going on in this function above that covers in-contract post-conditions, calling the official sBTC token contract, reading Bitcoin state, emitting events, and etc. We'll break it down for you:
+
+
+
+Define public function and params
+
+```clarity
+(define-public (add-message (content (string-utf8 280)))
+ ;; function body
+)
+```
+
+By using the `define-public` function, we can literally create a public function where anyone can invoke.
+
+* `(add-message ... )` : the custom name of the public function
+* `(content (string-utf8 280))` : the custom paramater name and type
+
+
+
+
+
+Create let variable binding for next message id
+
+```clarity
+(let ((id (+ (var-get message-count) u1)))
+ ;; body expressions
+)
+```
+
+Creates a "local" variable that can be used inside the function body only. This `id` variable will be used to represent the new message id being added.
+
+
+
+
+
+Transfer 1 satoshi of sBTC from user to the contract
+
+(try! (restrict-assets? contract-caller
+ ((with-ft 'SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token "sbtc-token" u1))
+ (unwrap!
+ ;; Charge 1 satoshi of sBTC from the caller
+ (contract-call? 'SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token
+ transfer u1 contract-caller current-contract none
+ )
+ ERR_NOT_ENOUGH_SBTC
+ )
+))
+
+
+This snippet calls the external .`sbtc-token` contract to transfer sBTC.
+
+The `restrict-assets?` acts as an in-contract post-condition to protect user and contract funds when calling external contracts to transfer assets.
+
+
+
+
+
+Store message data in mapping
+
+```clarity
+(map-set messages id {
+ message: content,
+ author: contract-caller,
+ time: burn-block-height,
+})
+```
+
+The function `map-set` will allow the existing mapping of `messages` to add a new key-value pair consiting of the metadata of the new message.
+
+We'll be using the current Bitcoin block height (via `burn-block-height`) as a way to capture the time of when this new message was added. Through `burn-block-height` , Clarity allows us to have read access into the Bitcoin state at anytime.
+
+
+
+
+
+Update the message-count variable
+
+```clarity
+(var-set message-count id)
+```
+
+Increments the existing data variable of `message-count` with the `let` id variable.
+
+
+
+
+
+Emit an event to the network
+
+```clarity
+(print {
+ event: "[Stacks Dev Quickstart] New Message",
+ message: content,
+ id: id,
+ author: contract-caller,
+ time: burn-block-height,
+})
+```
+
+The `print` function will allow us to emit a custom event to the Stacks network.
+
+Emitting events on Stacks serves several critical purposes:
+
+1. **Transparency**: Events provide an on-chain record of actions and transactions, ensuring transparency.
+2. **Notification**: They serve as a signal mechanism for users and external applications, notifying them of specific occurrences on Stacks.
+3. **State Tracking**: Developers can use events to track changes in the state of smart contracts without querying the chain continuously.
+4. **Efficient Data Handling**: By emitting events, webhook services, such as Hiro's [Chainhooks](https://docs.hiro.so/en/tools/chainhooks), can filter and handle relevant data efficiently, reducing the on-chain computation load.
+
+
+
+
+
+Return final response
+
+;; Return the message ID
+(ok id)
+
+
+Public functions _must_ return a ResponseType (using either `ok` or `err`). In this case, we'll return a response type with an inner value of the new message id.
+
+
+{% endstep %}
+
+{% step %}
+**Add sBTC contract requirements**
+
+Since we're working with sBTC in our local developer environment, we'll need to make sure Clarinet can recognize this. Clarinet can automatically wire up the official sBTC contracts so you can build and test sBTC flows locally.
+
+In our case, all we'll need to do is add the [`.sbtc-deposit`](https://explorer.hiro.so/txid/SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-deposit?chain=mainnet) contract as a project requirement.
+
+{% code title="terminal" %}
+```
+clarinet requirements add SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-deposit
+```
+{% endcode %}
+
+You'll notice in the `add-message` public function, we're making an external contract call to the [`.sbtc-token`](https://explorer.hiro.so/txid/0xead2080826685a98886891cbd9b288d367ae19b357353c71fff4a3330da582c8?chain=mainnet) contract. This is the official sBTC token contract that contains the [SIP-010](https://github.com/stacksgov/sips/blob/main/sips/sip-010/sip-010-fungible-token-standard.md) standard `transfer` function that we are invoking.
+
+Check out the dedicated [sBTC integration](../clarinet/integrations/sbtc.md) page to learn more.
+{% endstep %}
+
+{% step %}
+**Allow contract owner to withdraw funds**
+
+In the beginning of our contract, we defined a constant to store the Stacks principal of the contract owner. Having a contract owner allows for specific access control of the contract that is entitled to the owner. Let's allow the owner to be able to withdraw the accumulated sBTC fees that were sent by anyone who created a new message in the contract.
+
+;; Withdraw function for contract owner to withdraw accumulated sBTC
+(define-public (withdraw-funds)
+ (begin
+ (asserts! (is-eq tx-sender CONTRACT_OWNER) (err u1005))
+ (let ((balance (unwrap-panic (contract-call? 'SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token
+ get-balance current-contract
+ ))))
+ (if (> balance u0)
+ (contract-call? 'SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token
+ transfer balance current-contract CONTRACT_OWNER none
+ )
+ (ok false)
+ )
+ )
+ )
+)
+
+
+You'll notice in the highlighted line that the function performs an `asserts!` check to confirm that the `tx-sender` calling the contract is in fact the `CONTRACT_OWNER` . If it is in fact the owner of the contract, the function body proceeds with transferring the balance of sBTC to the owner or else it'll throw an error that we defined earlier.
+
+{% hint style="info" %}
+The usage of `tx-sender` versus another Clarity keyword, `contract-caller` , is always a tricky concept because it determines who actually initiated the transaction versus who invoked the current function. Both of them can have certain implications on security based on the context of your code. Check out the dedicated [blog](https://www.setzeus.com/public-blog-post/clarity-carefully-tx-sender), written by community dev Setzeus, to learn when you should use either or.
+{% endhint %}
+{% endstep %}
+
+{% step %}
+**Implement read only functions**
+
+We'll round out our contract with important read only functions that will return us needed data from the contract.
+
+;; Read-only function to get a message by ID
+(define-read-only (get-message (id uint))
+ (map-get? messages id)
+)
+
+;; Read-only function to get message author
+(define-read-only (get-message-author (id uint))
+ (get author (map-get? messages id))
+)
+
+;; Read-only function to get message count at a specific Stacks block height
+(define-read-only (get-message-count-at-block (block uint))
+ (ok (at-block
+ (unwrap! (get-stacks-block-info? id-header-hash block) ERR_BLOCK_NOT_FOUND)
+ (var-get message-count)
+ ))
+)
+
+
+You'll notice the usage of a `at-block` function in the highlighted line of code. The `at-block` function evaluates the inner expression _as if_ it were evaluated at the end of a specific Stacks block.
+{% endstep %}
+
+{% step %}
+**Test your contract**
+
+Now with the actual writing of your contract complete, we now need to test its functionality. There's a few different ways we can go about iterating and testing the functionality of your contract.
+
+* Contract interaction in the [Clarinet REPL](../clarinet/contract-interaction.md)
+* Running your contract in a [local blockchain environment](../clarinet/local-blockchain-development.md)
+* Fuzz testing with [Rendezvous](https://stacks-network.github.io/rendezvous/)
+* Writing unit tests with the [Clarinet JS SDK](../clarinet/testing-with-clarinet-sdk.md)
+
+We'll go with unit testing for now. In your `tests` folder, open up the related `message-board.test.ts` file and let's use the unit test written below.
+
+import { Cl, ClarityType } from "@stacks/transactions";
+import { describe, expect, it } from "vitest";
+
+const accounts = simnet.getAccounts();
+const deployer = accounts.get("deployer")!;
+const address1 = accounts.get("wallet_1")!;
+
+describe("example tests", () => {
+ let content = "Hello Stacks Devs!"
+
+ it("allows user to add a new message", () => {
+ let currentBurnBlockHeight = simnet.burnBlockHeight;
+
+ let confirmation = simnet.callPublicFn(
+ "stacks-dev-quickstart-message-board",
+ "add-message",
+ [Cl.stringUtf8(content)],
+ address1
+ )
+
+ const messageCount = simnet.getDataVar("stacks-dev-quickstart-message-board", "message-count");
+
+ expect(confirmation.result).toHaveClarityType(ClarityType.ResponseOk);
+ expect(confirmation.result).toBeOk(messageCount);
+ expect(confirmation.events[1].data.value).toBeTuple({
+ author: Cl.standardPrincipal(address1),
+ event: Cl.stringAscii("[Stacks Dev Quickstart] New Message"),
+ id: messageCount,
+ message: Cl.stringUtf8(content),
+ time: Cl.uint(currentBurnBlockHeight),
+ });
+ });
+
+ it("allows contract owner to withdraw funds", () => {
+ simnet.callPublicFn(
+ "stacks-dev-quickstart-message-board",
+ "add-message",
+ [Cl.stringUtf8(content)],
+ address1
+ )
+
+ simnet.mineEmptyBurnBlocks(2);
+
+ let confirmation = simnet.callPublicFn(
+ "stacks-dev-quickstart-message-board",
+ "withdraw-funds",
+ [],
+ deployer
+ )
+
+ expect(confirmation.result).toBeOk(Cl.bool(true));
+ expect(confirmation.events[0].event).toBe("ft_transfer_event")
+ expect(confirmation.events[0].data).toMatchObject({
+ amount: '1',
+ asset_identifier: 'SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token::sbtc-token',
+ recipient: deployer,
+ sender: `${deployer}${".stacks-dev-quickstart-message-board"}`,
+ })
+ })
+});
+
+
+
+You'll notice we have two `it` blocks setup to test out 2 different scenarios:
+
+1. Allows user to add a new message
+2. Allows owner to withdraw sBTC funds
+
+Run the test via `npm run test` to confirm that the two scenarios are functioning as intended.
+
+{% code title="terminal" %}
+```bash
+$ npm run test
+
+ ✓ tests/message-board.test.ts (2 tests) 46ms
+ ✓ message board tests (2)
+ ✓ allows user to add a new message 26ms
+ ✓ allows contract owner to withdraw funds 19ms
+
+ Test Files 1 passed (1)
+ Tests 2 passed (2)
+ Start at 14:05:07
+ Duration 886ms (transform 40ms, setup 42ms, collect 8ms, tests 46ms, environment 699ms, prepare 4ms)
+```
+{% endcode %}
+
+Great! Now that your contract is working as intended, let's deploy the contract to testnet.
+{% endstep %}
+{% endstepper %}
+
+### Get testnet faucet tokens
+
+{% stepper %}
+{% step %}
+**Navigate to the Hiro Platform faucet**
+
+[Hiro](https://www.hiro.so/platform) is a platform to build and scale Bitcoin apps, including custom data streams, onchain alerts, API key management, and more. Create an account and navigate to the top tab of 'Faucet'. On the Faucet page, you can request testnet STX and/or sBTC. We'll be needing both so fund your Leather wallet account with both.
+
+
+
+Grab the testnet Stacks address from your Leather wallet and paste it in the recipient field.
+
+{% hint style="warning" %}
+**Important**: Switch to the **Testnet** network in your wallet settings
+{% endhint %}
+{% endstep %}
+
+{% step %}
+**Confirm testnet tokens in your wallet**
+
+Open up your Leather extension to confirm that you've received testnet STX and sBTC. You might need to enable the viewing of the sBTC token in your wallet under 'Manage tokens'.
+
+
+
+With both testnet STX and sBTC, you're ready to deploy your contract and interact with it from a front-end client.
+{% endstep %}
+{% endstepper %}
+
+### Deploy your Clarity smart contract
+
+{% stepper %}
+{% step %}
+**Generate testnet deployment plan**
+
+You'll first want to input a mnemonic seed phrase in the `settings/Testnet.toml` file and specify the account derivation path that you want to use for deploying the contract. The account should be the same one you used to request testnet STX to. This will be the account that actually deploys the contract and becomes the contract owner.
+
+[network]
+name = "testnet"
+stacks_node_rpc_address = "https://api.testnet.hiro.so"
+deployment_fee_rate = 10
+
+[accounts.deployer]
+mnemonic = "<YOUR TESTNET MNEMONIC>"
+ derivation = "m/44'/5757'/0'/0/0"
+
+
+Then generate a deployment plan for the testnet network. Deployment plans are YAML files that describe how contracts are published or called.
+
+{% hint style="warning" %}
+For more information on configuring deployment plans, check out the specific guide [here](../clarinet/contract-deployment.md).
+{% endhint %}
+
+{% code title="terminal" %}
+```bash
+$ clarinet deployments generate --testnet --medium-cost
+Analyzing contracts...
+Calculating deployment costs...
+Generating deployment plan
+Created file deployments/default.testnet-plan.yaml
+```
+{% endcode %}
+{% endstep %}
+
+{% step %}
+**Deploy contract to testnet**
+
+Once your deployment plan is generated and configured properly, go ahead and deploy the contract to testnet.
+
+{% code title="terminal" %}
+```bash
+clarinet deployments apply --testnet
+```
+{% endcode %}
+
+If the contract was successfully deployed, you should see the below confirmation:
+
+```
+Broadcasting transactions to https://api.testnet.hiro.so
+Publish ST11V9ZN6E6VG72SHMAVM9GDE30VD3VGW5Q1W9WX3.message-board Transaction confirmed
+```
+
+{% hint style="info" %}
+A sample of the contract we just created above is already deployed to testnet [here](https://explorer.hiro.so/txid/ST11V9ZN6E6VG72SHMAVM9GDE30VD3VGW5Q1W9WX3.stacks-dev-quickstart-message-board?chain=testnet). Check out its contract page on the Stacks Explorer and directly interact with its functions.
+{% endhint %}
+{% endstep %}
+{% endstepper %}
+
+### Use stacks.js on the frontend
+
+{% stepper %}
+{% step %}
+**Connect wallet**
+
+Using [stacks.js](../stacks.js/overview.md) packages on the frontend will allow our frontend app to authenticate wallets, call our contract functions, and interact with the Stacks network.
+
+We'll first want to connect and authenticate our Leather wallet extension with our frontend app. The stacks.js monorepo contains several underlying packages specific to different use cases. The package `@stacks/connect` is the main connectivity package used in Stacks.
+
+In the snippet below, you'll notice we have 3 functions setup to handle `connectWallet` , `disconnectWallet`, and for `getBns` . All 3 functions will be integral in how we want to display the 'Connect' and 'Disconnect' button in the UI.
+
+{% hint style="info" %}
+Retrieving a wallet account's associated [BNS](https://app.gitbook.com/s/H74xqoobupBWwBsVMJhK/network-fundamentals/bitcoin-name-system) is a staple of Stacks and for web3 identity. Check out [BNSv2](https://www.bnsv2.com/) for more information and for availably public API endpoints you could use.
+{% endhint %}
+
+import { connect, disconnect } from '@stacks/connect'
+import type { GetAddressesResult } from '@stacks/connect/dist/types/methods'
+import { useState } from 'react'
+
+function App() {
+ let [isConnected, setIsConnected] = useState<boolean>(false)
+ let [walletInfo, setWalletInfo] = useState<any>(null)
+ let [bns, setBns] = useState<string>('')
+
+ async function connectWallet() {
+ let connectionResponse: GetAddressesResult = await connect()
+ let bnsName = await getBns(connectionResponse.addresses[2].address)
+
+ setIsConnected(true)
+ setWalletInfo(connectionResponse)
+ setBns(bnsName)
+ }
+
+ async function disconnectWallet() {
+ disconnect();
+ }
+
+ async function getBns(stxAddress: string) {
+ let response = await fetch(`https://api.bnsv2.com/testnet/names/address/${stxAddress}/valid`)
+ let data = await response.json()
+
+ return data.names[0].full_name
+ }
+
+ return (
+ <>
+ <h3>Stacks Dev Quickstart Message Board</h3>
+ {isConnected ? (
+ <button onClick={disconnectWallet}>{
+ bns ? bns : walletInfo.addresses[2].address
+ }</button>
+ ) : (
+ <button onClick={connectWallet}>connect wallet</button>
+ )}
+ </>
+ )
+}
+
+
+The `connect()` method comes with ability to configure how you want the wallet selector modal to appear for your app. You can decide which wallets to have only appear as an option or allow any wallet that follows the SIP-030 standard to appear as an available Stacks wallet.
+
+The Stacks Connect wallet selector modal
+{% endstep %}
+
+{% step %}
+**Call \`add-message\` public function**
+
+Next, we'll setup a `stx_callContract` to invoke the `add-message` public function of our contract. This function will accept a string content to be passed into our contract call.
+
+import { request } from '@stacks/connect'
+import type { TransactionResult } from '@stacks/connect/dist/types/methods'
+import { Cl, Pc } from '@stacks/transactions'
+import { useState } from 'react'
+
+function App() {
+ // ...
+ let [content, setContent] = useState<string>('')
+
+ async function addMessage() {
+ let postCond_1 = Pc.principal('ST11V9ZN6E6VG72SHMAVM9GDE30VD3VGW5Q1W9WX3')
+ .willSendEq(1)
+ .ft('ST1F7QA2MDF17S807EPA36TSS8AMEFY4KA9TVGWXT.sbtc-token', 'sbtc-token')
+
+ let result: TransactionResult = await request('stx_callContract', {
+ contract: 'ST11V9ZN6E6VG72SHMAVM9GDE30VD3VGW5Q1W9WX3.stacks-dev-quickstart-message-board',
+ functionName: 'add-message',
+ functionArgs: [Cl.stringUtf8(content)],
+ network: 'testnet',
+ postConditions: [postCond_1],
+ postConditionMode: 'deny',
+ sponsored: false
+ })
+
+ setContent('')
+ }
+
+ return (
+ <>
+ // ...
+ <span className='input-container'>
+ <button onClick={addMessage}>add-message</button>
+ <input type="text" onChange={e => setContent(e.target.value)}/>
+ </span>
+ </>
+ )
+}
+
+
+You'll notice in the transaction data object that we pass into our string literal method of `stx_callContract`, that we're setting up post-conditions. [Post-Conditions](../post-conditions/overview.md) for the frontend are declared to protect user assets. The `Pc` helper from `@stacks/transactions` helps us to declare post-condition statements for any type of asset and equality operator.
+
+Invoking our `addMessage` function will prompt the user's connected wallet to prompt a transaction confirmation popup. This popup will display all of the relevant information of the transaction as well as the post-condition statements that we've declared.
+
+
+{% endstep %}
+
+{% step %}
+**Call read-only function**
+
+As how we've created a few read-only functions in our contract, we'll also want to call these from the frontend to retrieve certain contract data.
+
+Let's setup a `fetchCallReadOnlyFunction` to invoke our contract's `get-message-count-at-block` read-only function. For this, we'll fetch the current Stacks block height from the Hiro API endpoint and pass that returned value into our read-only function.
+
+// ...
+import type { ClarityValue } from '@stacks/connect/dist/types/methods'
+import { Cl, fetchCallReadOnlyFunction } from '@stacks/transactions'
+
+function App() {
+ // ...
+ async function getMessageCountAtBlock() {
+ let response = await fetch('https://api.testnet.hiro.so/v2/info', {
+ headers: {
+ "x-api-key": "<HIRO_API_KEY>"
+ }
+ })
+ let data = await response.json()
+ let stacksBlockHeight = data.stacks_tip_height
+
+ let result: ClarityValue = await fetchCallReadOnlyFunction({
+ contractAddress: 'ST11V9ZN6E6VG72SHMAVM9GDE30VD3VGW5Q1W9WX3',
+ contractName: 'stacks-dev-quickstart-message-board',
+ functionName: 'get-message-count-at-block',
+ functionArgs: [Cl.uint(stacksBlockHeight)],
+ network: 'testnet',
+ senderAddress: 'ST11V9ZN6E6VG72SHMAVM9GDE30VD3VGW5Q1W9WX3',
+ })
+ }
+
+ // ...
+
+
+{% hint style="info" %}
+For the complete set of available API endpoints for the Stacks network, check out the [Hiro docs](https://docs.hiro.so/). But first create an API key from the [Hiro Platform](https://platform.hiro.so/) to determine your API rate plan.
+{% endhint %}
+{% endstep %}
+{% endstepper %}
+
+And that's it, you've successfully created an sBTC powered Clarity smart contract which can be interacted with from a frontend app. There's obviously much more you can do to complete this but you've got some of the basics down pat now. Go ahead and finish creating the frontend functions to call on the other contract functions we have.
+
+***
+
+### Further Improvements
+
+This is just the beginning. There are many ways we can improve upon this app. Here are some suggestions for you to extend the functionality of this app:
+
+* Deploy to mainnet and share your project with the community
+* Use [Chainhooks](https://docs.hiro.so/en/tools/chainhooks) to index emitted events from the contract
+* Integrate the [`sbtc`](../more-guides/sbtc/bridging-bitcoin/) library so users can directly bridge their BTC to sBTC in-app
+* Utilize SIP-009 NFTs to uniquely identify each message for each author
+
+***
+
+### Next Steps
+
+Now that you have the basics down, here are some ways to continue your Stacks development journey:
+
+**Learn More About Clarity**
+
+* [**Clarity Crash Course**](https://docs.stacks.co/docs/clarity-crash-course): Quick introduction to Clarity concepts
+* [**Clarity Book**](https://book.clarity-lang.org/): Comprehensive guide to Clarity development
+* [**Clarity Reference**](https://docs.stacks.co/docs/clarity): Complete documentation of Clarity functions
+
+**Development Tools**
+
+* [**Clarinet**](https://github.com/stx-labs/clarinet): Local development environment for Clarity
+* [**Hiro Platform**](https://platform.hiro.so/): Hosted development environment
+* [**Stacks Explorer**](https://explorer.stacks.co/): View transactions and contracts
+
+**Community Resources**
+
+* [**Stacks Discord**](https://discord.gg/stacks): Connect with other developers
+* [**Stacks Forum**](https://forum.stacks.org/): Ask questions and share projects
diff --git a/docs/build/get-started/introduction/why-build-with-stacks.md b/docs/build/get-started/introduction/why-build-with-stacks.md
new file mode 100644
index 0000000000..2da229f98b
--- /dev/null
+++ b/docs/build/get-started/introduction/why-build-with-stacks.md
@@ -0,0 +1,67 @@
+---
+description: Diving into the question of why we're all here
+---
+
+# Why Build with Stacks
+
+{% embed url="https://youtu.be/eqFFX4Sx9mY?si=XcH6Bo3nTQusW0Tp" %}
+
+### Why build with Stacks
+
+Build on Bitcoin with Stacks because builders don’t need a new base layer — they need a better app layer. Stacks anchors to Bitcoin finality while enabling clear, auditable contracts and expressive logic, making BTC useful beyond holding. With production-ready tooling and one of the most active Bitcoin L2 developer communities, you get momentum, collaboration, and Bitcoin-aligned product-market fit from day one. If you want Bitcoin capital with real applications, Stacks is the path of least resistance and greatest leverage.
+
+### What does it mean to build with Stacks
+
+Building with Stacks means creating applications and smart contracts that _**extend**_ the power of Bitcoin without altering Bitcoin itself. It’s about inheriting Bitcoin’s security, finality, and economic gravity, while gaining the expressiveness needed for decentralized apps, ownership-first systems, and programmable digital assets.
+
+Developers use easy, LISP-like contracts written in the Clarity language, interact with the chain using familiar tooling like Stacks.js, automate on-chain responsiveness with Chainhooks, enable Bitcoin programmability via sBTC, and tap into indexed on-chain data through reliable APIs.
+
+Ultimately, **building with Stacks is a mindset**: leverage Bitcoin as the base layer, but experiment boldly at the application layer—where users keep custody of their bitcoin via sBTC, transactions enforce intent, and decentralized systems become useful enough for everyday life.
+
+### Benefits of building with Stacks
+
+
+
+🌐 Global Community
+
+_**Diverse and Vibrant:**_ Stacks has a massive global builder community where collaboration happens at internet speed, not conference speed. You plug into shared momentum, talent, diversity, and distribution across a network anchored by Bitcoin.
+
+* \[[Hiro YT](https://youtu.be/jjSbIKRb8Z8?si=JRzdbiBWq9mLKVaz)] Meeting Rockstar Web3 Builders at the EasyA x Stacks Hackathon
+* \[[StacksDevs](https://x.com/StacksDevs/status/1991506865394774371)] Photos from the Stacks Hacker House in Buenos Aires
+* \[[Stacks YT](https://youtu.be/UB6pkG58wYo?si=ITiW7xhz8odfa59T)] How Stacks Took Over Miami
+
+
+
+
+
+🎨 Creator Tools
+
+_**The Bitcoin-Backed Creator Economy:**_ From artists to influencers, creators are seeking smarter ways to capture value. With Stacks, you can push the boundaries of monetization, powered by Bitcoin capital and programmable Clarity contracts.
+
+* \[[Hiro Blog](https://www.hiro.so/blog/what-is-bitcoin-culture-see-it-through-bitcoin-nfts)] What is “Bitcoin Culture?” See it through Bitcoin NFTs
+* \[[Hiro Blog](https://www.hiro.so/blog/building-an-accelerator-for-african-creators-with-osinachi-africas-foremost-nft-artist)] Building an Accelerator for African Creators With Osinachi, Africa’s Foremost NFT Artist
+* \[[Hiro Blog](https://www.hiro.so/blog/a-look-inside-gammas-create-portal-and-how-it-empowers-nft-creators)] A Look Inside Gamma’s Create Portal and How It Empowers NFT Creators
+
+
+
+
+
+🛠️ Developer Experience
+
+_**Built for Builders:**_ Stacks offers everything you need — tooling, infra, and hands-on support. Backed by one of the largest on-chain dev communities, it’s a place to collaborate, level up, and build the future together.
+
+* \[[Hiro YT](https://youtu.be/gPG6ZFGpYo0?si=hMxIxGJjuoggfD8Q)] Exploring Web3 Developer Tooling With the Clarinet Team
+* \[[Bitcoin Builders YT](https://youtu.be/RCHbqfaUbHQ?si=j5BLw6lCIYAq52RI)] What is the Dev Experience for Bitcoin Layers?
+
+
+
+
+
+🏗️ Builder Programs
+
+_**Support at Every Step:**_ Stacks runs specialized builder programs that give you capital, feedback, and community validation, not just swag and tweets. You get structured support that compounds long after demo day.
+
+* \[[Stacks Ascent](https://stacks.org/ascent)] From Code to Company
+* \[[Stacks Foundation](https://stacks.org/grants)] Grants & Bounty Programs
+
+
diff --git a/docs/build/get-started/use-cases/README.md b/docs/build/get-started/use-cases/README.md
new file mode 100644
index 0000000000..86b69b58bf
--- /dev/null
+++ b/docs/build/get-started/use-cases/README.md
@@ -0,0 +1,12 @@
+---
+description: Exploring different use cases for building with Stacks, on Bitcoin.
+---
+
+# Use Cases
+
+
+
+Stacks extends Bitcoin's functionality, enabling a variety of decentralized applications. Here are some use cases for you to explore and incite new ideas.
+
+DeFi Enable smart contracts for lending, borrowing, and trading of digital assets. defi.md Art Facilitate the artistic creation and trading of digital art as NFTs. art.md Payments Enable fast, Bitcoin-settled transactions using assets like sBTC and STX, with developer tooling support and easy wallet integrations. payments.md Gaming Support on-chain economies, verifiable in-game assets as NFTs, and player rewards programs. gaming.md AI AI agents can hold sBTC, sign transactions, manage digital assets, and automate workflows while being bound by Clarity-level constraints ai.md
+
diff --git a/docs/build/get-started/use-cases/ai.md b/docs/build/get-started/use-cases/ai.md
new file mode 100644
index 0000000000..c0304e5327
--- /dev/null
+++ b/docs/build/get-started/use-cases/ai.md
@@ -0,0 +1,75 @@
+---
+description: Use cases of AI on Stacks
+---
+
+# AI
+
+AI on **Stacks** enables verifiable, Bitcoin-secured AI applications. Developers can build decentralized AI marketplaces, create AI agents that safely manage sBTC under smart-contract rules, and generate verifiable inference receipts for trust and compliance. By combining Bitcoin security with Clarity and sBTC, Stacks provides a powerful foundation for trusted, permissionless, AI-powered apps.
+
+Here are some powerful examples of how **Stacks is unlocking on-chain AI experiences secured by Bitcoin:**
+
+### **x402-Stacks**
+
+x402 enables **automatic HTTP-level payments** for APIs, AI agents, and digital services using STX or sBTC tokens on Stacks. Pay only for what you use, right when you use it. No subscriptions, no API keys, no intermediaries.
+
+**Implementation highlight:**\
+The `x402-Stacks` library is a TypeScript library for implementing the x402 payment protocol on Stacks blockchain. This system supports multiple ways to handle paid API access: clients can pay automatically using an axios interceptor, or they can sign requests while a facilitator service reliably settles the payment on their behalf. Developers can also protect any Express.js endpoint with plug-and-play middleware. Pricing is fully flexible, supporting fixed, tiered, or dynamic fee models.
+
+{% code title="x402-stacks" expandable="true" %}
+```typescript
+import axios from 'axios';
+import { withPaymentInterceptor, privateKeyToAccount } from 'x402-stacks';
+
+// Create account from private key
+const account = privateKeyToAccount(process.env.PRIVATE_KEY!, 'testnet');
+
+// Wrap axios with automatic payment handling
+const api = withPaymentInterceptor(
+ axios.create({ baseURL: 'https://api.example.com' }),
+ account
+);
+
+// Use normally - 402 payments are handled automatically!
+const response = await api.get('/api/premium-data');
+console.log(response.data);
+```
+{% endcode %}
+
+
+
+Check out more from x402-Stacks
+
+* \[[npm package](https://www.npmjs.com/package/x402-stacks)] x402-Stacks
+* \[[Github](https://github.com/tony1908/x402Stacks)] Open-source repo for x402-Stacks
+* \[[Twitter](https://x.com/toony1908/status/1996417973842858238)] Demo video of using x402-Stacks SDK
+
+
+
+***
+
+### AIBTC
+
+The AI + BTC coordination network. AIBTC provides AI powered agents with Bitcoin and Stacks tooling.
+
+**Implementation highlight:**\
+The `aibtcdev-backend` bridges AI capabilities with Stacks blockchain technology to create intelligent DAO management experiences. The system provides real-time communication with AI agents that can autonomously interact with DAOs, create and evaluate proposals, execute trades, and manage blockchain accounts.
+
+{% code title="WebSocket Chat usage example" %}
+```typescript
+const ws = new WebSocket('ws://localhost:8000/chat/ws?token=your_token');
+ws.send(JSON.stringify({
+ type: 'message',
+ thread_id: 'thread-uuid',
+ content: 'Hello, AI agent!'
+}));
+```
+{% endcode %}
+
+
+
+Check out more from AIBTC
+
+* \[[Official](https://aibtc.com/)] Official website of AIBTC
+* \[[Github](https://github.com/aibtcdev)] Open-source repo for backend, frontend, and agent tooling support
+
+
diff --git a/docs/build/get-started/use-cases/art.md b/docs/build/get-started/use-cases/art.md
new file mode 100644
index 0000000000..7ae3a6176c
--- /dev/null
+++ b/docs/build/get-started/use-cases/art.md
@@ -0,0 +1,122 @@
+---
+description: Use cases of art on Stacks
+---
+
+# Art
+
+Unlock expressive, Bitcoin-secured digital art with NFT assets — all backed by fast, low-cost execution on Stacks. The Stacks ecosystem brings programmability, provenance, and creative tooling to Bitcoin, giving artists and collectors the speed, flexibility, and cultural richness they’ve always wanted _without leaving Bitcoin_. Stacks expands what Bitcoin culture can be: native digital ownership, programmable collectibles, onchain storytelling, and communities that form directly around Bitcoin-secured art.
+
+Here are the creative use cases artists are exploring today:
+
+### **Megapont Ape Club**
+
+Megapont Ape Club is a pixel-art NFT collection built on Stacks. The “universe” behind Megapont is a fictional, stylized world — a retro-inspired pixel-art universe where mutated species evolved, with chimpanzees (apes) playing a central role. Beyond just apes, Megapont supports other NFT lines (e.g. Robot Factory, other “species / world” NFTs) and cross-chain / cross-platform assets.
+
+**Implementation highlight:**\
+The below code snippet is taken from the Megapont Ape's NFT contracts. This snippet shows two **internal minting functions** used. They are not public entrypoints—only callable from inside the contract. One handles _mintpass_-based presale minting, the other handles _public sale_ minting.
+
+* **Presale minting** has stricter access rules (mintpasses, whitelists, limits).
+* **Public sale minting** is open to anyone once activated.
+* The actual NFT lives in a separate contract (`.megapont-ape-club-nft`), keeping logic modular.
+
+{% code title=".megapont-ape-club-mint" fullWidth="false" expandable="true" %}
+```clarity
+;; ...
+
+;; Internal - Mint NFT using Mintpass mechanism
+(define-private (mintpass-mint (new-owner principal))
+ (let ((presale-balance (get-presale-balance new-owner)))
+ (asserts! (> presale-balance u0) ERR-NO-MINTPASS-REMAINING)
+ (map-set presale-count
+ new-owner
+ (- presale-balance u1))
+ (contract-call? .megapont-ape-club-nft mint new-owner)))
+
+;; Internal - Mint public sale NFT
+(define-private (public-mint (new-owner principal))
+ (begin
+ (asserts! (var-get sale-active) ERR-SALE-NOT-ACTIVE)
+ (contract-call? .megapont-ape-club-nft mint new-owner)))
+
+;; ...
+```
+{% endcode %}
+
+
+
+Check out more from Megapont
+
+* \[[Official](https://www.megapont.com/)] Official website of Megapont
+* \[[Gamma](https://stacks.gamma.io/collections/megapont-ape-club)] NFT listing page on the Gamma marketplace
+* \[[Hiro YT](https://youtu.be/mz1irJUpq0I?t=843)] Muneeb joining the Megapont Ape community
+* \[[Hiro YT](https://youtu.be/xwbXNgSvMkk?si=jeHwWQ4oLlj9_ucr)] A Beginner's Overview of the Megapont Ape NFT Clarity Smart Contract
+* \[[contract](https://explorer.hiro.so/txid/SP3D6PV2ACBPEKYJTCMH7HEN02KP87QSP8KTEH335.megapont-ape-club-nft?chain=mainnet)] .megapont-ape-club-nft
+* \[[contract](https://explorer.hiro.so/txid/SP3D6PV2ACBPEKYJTCMH7HEN02KP87QSP8KTEH335.megapont-ape-club-mint?chain=mainnet\&tab=overview)] .megapont-ape-club-mint
+
+
+
+***
+
+### Satoshibles
+
+Satoshibles is an early, pixel-art NFT collection that originally launched on Ethereum in 2021 and later bridged to Stacks, becoming one of the first established NFT communities to move onto the Bitcoin ecosystem.
+
+The project consists of 5000 algorithmically generated crypto collectible NFTs that have been hand illustrated. Each one unique, and each representing a fun, retro interpretation of “Satoshi-like” personas—quirky, expressive, and distinctly Bitcoin-themed.
+
+**Implementation highlights:**\
+This code snippet below enables a flexible, secure commission system by letting each NFT listing specify a commission contract, enforcing its use during purchase, and delegating fee payout logic to that external contract via the commission trait. By accepting a contract implementing `commission-trait`, it creates a _plug-and-play commission system_ where:
+
+* marketplaces decide their fee logic,
+* creators can define custom royalty structures,
+* different listings can use different commission rules.
+
+The marketplace contract enforces that the same commission contract passed at listing must also be used at purchase time.
+
+{% code title="SP6P4EJF0VG8V0RB3TQQKJBHDQKEF6NVRD1KZE3C.satoshibles" expandable="true" %}
+```clarity
+;; ...
+
+(use-trait commission-trait .commission-trait.commission)
+
+;; ...
+
+(define-public (list-in-ustx (id uint) (price uint) (comm ))
+ (let ((listing {price: price, commission: (contract-of comm)}))
+ (asserts! (is-sender-owner id) ERR-NOT-AUTHORIZED)
+ (map-set market id listing)
+ (print (merge listing {a: "list-in-ustx", id: id}))
+ (ok true)))
+
+(define-public (unlist-in-ustx (id uint))
+ (begin
+ (asserts! (is-sender-owner id) ERR-NOT-AUTHORIZED)
+ (map-delete market id)
+ (print {action: "unlist-in-ustx", id: id})
+ (ok true)))
+
+(define-public (buy-in-ustx (id uint) (comm ))
+ (let ((owner (unwrap! (nft-get-owner? Satoshibles id) ERR-NOT-FOUND))
+ (listing (unwrap! (map-get? market id) ERR-LISTING))
+ (price (get price listing)))
+ (asserts! (is-eq (contract-of comm) (get commission listing)) ERR-WRONG-COMMISSION)
+ (try! (stx-transfer? price tx-sender owner))
+ (try! (contract-call? comm pay id price))
+ (try! (trnsfr id owner tx-sender))
+ (map-delete market id)
+ (print {action: "buy-in-ustx", id: id})
+ (ok true)))
+
+;; ...
+```
+{% endcode %}
+
+
+
+Check out more from Satoshibles
+
+* \[[Official](https://satoshibles.com/)] Official website of Satoshibles
+* \[[contract](https://explorer.hiro.so/txid/SP6P4EJF0VG8V0RB3TQQKJBHDQKEF6NVRD1KZE3C.satoshibles?tab=overview)] SP6P4EJF0VG8V0RB3TQQKJBHDQKEF6NVRD1KZE3C.satoshibles
+* \[[Gamma](https://gamma.io/stacks/collections/satoshibles/items)] Satoshibles' listing page on Gamma marketplace
+* \[[YT](https://www.youtube.com/watch?v=gZw4EvV6qig)] BRIDGE from ETH to Stacks | Satoshibles
+
+
diff --git a/docs/build/get-started/use-cases/defi.md b/docs/build/get-started/use-cases/defi.md
new file mode 100644
index 0000000000..3516e98281
--- /dev/null
+++ b/docs/build/get-started/use-cases/defi.md
@@ -0,0 +1,122 @@
+---
+description: Use cases of DeFi on Stacks
+---
+
+# DeFi
+
+Stacks enables users to put their BTC to work in trust-minimized ways: borrowing against it, providing liquidity, earning yield, or participating in programmable financial products that settle on Bitcoin. This ecosystem gives builders the foundation to extend Bitcoin from a passive store of value into an active financial layer.
+
+Here are some powerful demonstrations of unlocking DeFi for Bitcoin:
+
+### Hermetica
+
+Hermetica is a DeFi protocol built on Stacks whose mission is to bring fully Bitcoin-native stablecoins and yield products to the Bitcoin ecosystem. Their flagship asset is USDh — a Bitcoin-backed, yield-bearing synthetic dollar.
+
+**Implementation highlight:**\
+The code snippet below highlights the **migration lock**, **manager assignment**, and **token deprecation logic** all in one tight block. It captures the “power unlock” of the contract without pulling in the entire file:
+
+* Safely upgrade USDh by freezing old token operations once migration starts.
+* Assigns a migration manager to burn and migrate balances securely.
+* Ensures consistent supply and a trust-minimized transition to the new token.
+
+{% code title="SPN5AKG35QZSK2M8GAMR4AFX45659RJHDW353HSG.usdh-token-v1" expandable="true" %}
+```clarity
+;; Prevents all token activity once migration has begun
+(define-read-only (is-not-migrated)
+ (ok (asserts! (is-eq u0 (var-get migration-start-height)) ERR_DEPRECATED_TOKEN))
+)
+
+;; Begins the migration process and hands control to a migration manager contract
+(define-public (start-migration (manager ))
+ (begin
+ (try! (is-not-migrated))
+ (try! (contract-call? .hq-v1 check-is-owner contract-caller))
+ (var-set migration-start-height burn-block-height)
+ (var-set migration-manager (some (contract-of manager)))
+ (contract-call? manager start-migration burn-block-height (ft-get-supply usdh))
+ )
+)
+
+;; Allows the designated migration manager to burn a user’s balance and extract it for migration
+(define-public (migrate-balance (who principal))
+ (let ((balance (ft-get-balance usdh who)))
+ (asserts! (is-eq (var-get migration-manager) (some contract-caller)) ERR_NOT_MIGRATION_MANAGER)
+ (asserts! (> balance u0) (ok u0))
+ (try! (ft-burn? usdh balance who))
+ (ok balance)
+ )
+)
+
+```
+{% endcode %}
+
+
+
+Check out more from Hermetica
+
+* \[[Official](https://hermetica.fi/)] Official website of Hermetica
+* \[[Stacks YT](https://youtu.be/Xb54LJrLicY?si=3wMTBwOskphdsn4S)] Earn up to 25% with Your BTC as Collateral with Jakob Schillinger
+* \[[Hiro YT](https://www.youtube.com/watch?v=R6f4jR8S45M)] Lessons From Building Bitcoin DeFi
+* \[[Hiro Blog](https://www.hiro.so/blog/how-hermetica-uses-chainhook-to-track-bitcoin-deposits)] How Hermetica Uses Chainhook to Track Bitcoin Deposits
+* \[[contract](https://explorer.stacks.co/token/SPN5AKG35QZSK2M8GAMR4AFX45659RJHDW353HSG.usdh-token-v1?chain=mainnet)] SPN5AKG35QZSK2M8GAMR4AFX45659RJHDW353HSG.usdh-token-v1
+
+
+
+***
+
+### StackingDAO
+
+StackingDAO is the hub for liquid stacking on Stacks. One of their liquid stacking services **stSTXbtc**, is a liquid stacking token (LST) backed 1-to-1 with STX, and holders receive sBTC rewards daily that can be claimed at any moment.
+
+**Implementation highlight:**\
+This function **initiates a withdrawal of stSTXbtc**, locks the underlying STX for withdrawal, burns the derivative token, and mints an NFT that represents the user’s withdrawal claim. It effectively transforms a liquid derivative token into a time-locked withdrawal right.
+
+* Enforces protocol-level safety checks
+* Determines the unlock Bitcoin (burn) height
+* Links the withdrawal to an NFT “claim ticket”
+* Coordinates state changes across multiple protocol contracts
+
+{% code title="SP4SZE494VC2YC5JYG7AYFQ44F5Q4PYV7DVMDPBG.stacking-dao-core-btc-v2" fullWidth="true" expandable="true" %}
+```clarity
+;; --snip--
+
+(define-public (init-withdraw
+ (reserve )
+ (direct-helpers )
+ (ststxbtc-amount uint)
+)
+ (let (
+ (sender tx-sender)
+ (unlock-burn-height (unwrap-panic (contract-call? .stacking-dao-core-v4 get-withdraw-unlock-burn-height)))
+
+ (nft-id (unwrap-panic (contract-call? .ststxbtc-withdraw-nft get-last-token-id)))
+ )
+ (try! (contract-call? .dao check-is-enabled))
+ (try! (contract-call? .dao check-is-protocol (contract-of reserve)))
+ (try! (contract-call? .dao check-is-protocol (contract-of direct-helpers)))
+ (asserts! (not (get-shutdown-init-withdraw)) (err ERR_SHUTDOWN))
+
+ (try! (contract-call? .data-core-v2 set-ststxbtc-withdrawals-by-nft nft-id ststxbtc-amount unlock-burn-height))
+
+ (try! (contract-call? direct-helpers subtract-direct-stacking tx-sender ststxbtc-amount))
+
+ ;; Burn stSTXbtc tokens
+ (try! (as-contract (contract-call? reserve lock-stx-for-withdrawal ststxbtc-amount)))
+ (try! (contract-call? .ststxbtc-token-v2 burn-for-protocol ststxbtc-amount sender))
+ (try! (as-contract (contract-call? .ststxbtc-withdraw-nft mint-for-protocol sender)))
+
+ (print { action: "init-withdraw", data: { stacker: tx-sender, nft-id: nft-id, ststxbtc-amount: ststxbtc-amount, unlock-burn-height: unlock-burn-height, block-height: block-height } })
+ (ok nft-id)
+ )
+)
+```
+{% endcode %}
+
+
+
+Check out more from StackingDAO
+
+* \[[Hiro YT](https://youtu.be/1hWYeqS5r-k?si=GRWag60DUmm08TG_)] Going Under the Hood of stSTXbtc with Philip De Smedt from StackingDAO
+* \[[Hiro YT](https://youtu.be/ujpatSY9DhM?si=cr823veqbmcfYr7y)] A Simple Breakdown of the StackingDAO Clarity Contracts on Stacks
+
+
diff --git a/docs/build/get-started/use-cases/gaming.md b/docs/build/get-started/use-cases/gaming.md
new file mode 100644
index 0000000000..2673225ccc
--- /dev/null
+++ b/docs/build/get-started/use-cases/gaming.md
@@ -0,0 +1,91 @@
+---
+description: Use cases of gaming on Stacks
+---
+
+# Gaming
+
+Gaming is one of the most powerful entry points for bringing millions of new users into the Bitcoin ecosystem, and Stacks unlocks this opportunity with onchain logic secured by Bitcoin itself. By enabling fast, low-cost transactions, expressive smart contracts, and asset ownership through NFTs and fungible tokens, Stacks gives game developers the tools to build richer in-game economies, verifiable digital ownership, and player-driven marketplaces—all anchored to Bitcoin’s security. This combination lets games move beyond simple collectibles and into fully programmable, decentralized worlds where players truly own their assets and developers can design deeper incentives, interoperable items, and sustainable onchain economies.
+
+Here are some powerful examples of how Stacks is unlocking on-chain gaming for Bitcoin:
+
+### Skullcoin
+
+Skullcoin is a Web3 gaming project building a new genre called Find2Earn — treasure hunt games powered by Encrypted NFTs and real on-chain rewards. An Encrypted NFT is a new type of digital asset with two layers of information: a public layer visible to everyone, and a private encrypted layer that can only be revealed by the owner of NFT.
+
+**Implementation highlight:**\
+Here's a high-level breakdown of Skullcoin's Encrypted NFTs:
+
+* **What happens on-chain**: standard SIP-009 NFTs + commitments (hashes / indexes / events) that define what’s “locked” and who has the right to unlock it;
+* **What happens off-chain**: the actual encrypted payload (image / text / coords) lives in storage and is only served after the on-chain proof/conditions are satisfied.
+
+{% code title="skullcoin-competitive-seed-phase2.clar" %}
+```clarity
+;; --snip--
+
+(define-private (is-sender-owner (id uint))
+ (let ((owner (unwrap! (nft-get-owner? skullcoin_competitive_seed_p2 id) false)))
+ (or (is-eq tx-sender owner) (is-eq contract-caller owner))))
+
+;; --snip--
+```
+{% endcode %}
+
+
+
+Check out more from Skullcoin
+
+* \[[Official](https://skullco.in/)] Official website of Skullcoin
+* \[[Whitepaper](https://docs.skullco.in/)] Skullcoin whitepaper/docs
+* \[[contracts](https://github.com/proofofgame/find_to_earn)] Github repo for Skullcoin's Find2Earn contracts
+
+
+
+***
+
+### Cryptonauts
+
+Cryptonauts is a multiplayer GameFi Experience built on Unreal Engine 5 and powered by **Stacks**, a Bitcoin-anchored smart contract layer. Cryptonauts integrates Stacks wallet authentication, NFT verification, and on-chain asset logic directly into Unreal Engine, enabling features such as player skin ownership validation, Codex Component loadouts (NFT-based abilities), and signed game session data for Web3 interoperability.
+
+**Implementation highlight:**\
+Cryptonauts leverages BNS for player identification.
+
+* **Human-readable identities for players** — instead of using cryptographic addresses, BNS lets players show names like `cryptodude.btc`. This makes in-game identities more memorable, personality-driven, and social.
+* **Persistent identity + on-chain history** — BNS allows binding off-chain state to names and linking with on-chain state. That means a player’s actions, assets, and progress can be tied to a stable identity — even if they change wallets.
+
+{% code title="https://api.bnsv2.com/names/address/SP3WAR3N1XRR139DXCGPR1ATPK2VN63PGRXTD537N/valid" expandable="true" %}
+```json
+{
+ "total": 2,
+ "current_burn_block": 921664,
+ "limit": 50,
+ "offset": 0,
+ "names": [
+ {
+ "full_name": "cryptodude.btc",
+ "name_string": "cryptodude",
+ "namespace_string": "btc",
+ "owner": "SP3WAR3N1XRR139DXCGPR1ATPK2VN63PGRXTD537N",
+ "registered_at": "28369",
+ "renewal_height": "1125897",
+ "stx_burn": "2000000",
+ "revoked": false
+ }
+ ]
+}
+```
+{% endcode %}
+
+
+
+Check out more from Cryptonauts
+
+* \[[docs](https://cryptonauts.gitbook.io/cryptonauts-docs)] Cryptonauts docs
+
+
+
+***
+
+### Additional Resources
+
+* \[[Hiro Blog](https://www.hiro.so/blog/its-time-to-stake-your-claim-on-the-future-of-web3-gaming)] It’s Time to Stake Your Claim on the Future of Web3 Gaming
+* \[[Hiro Blog](https://www.hiro.so/blog/what-are-gaming-nfts-and-how-can-they-drive-bitcoin-adoption)] What Are Gaming NFTs and How Can They Drive Bitcoin Adoption?
diff --git a/docs/build/get-started/use-cases/payments.md b/docs/build/get-started/use-cases/payments.md
new file mode 100644
index 0000000000..7c6da75286
--- /dev/null
+++ b/docs/build/get-started/use-cases/payments.md
@@ -0,0 +1,133 @@
+---
+description: Use cases of payments on Stacks
+---
+
+# Payments
+
+Enable fast, Bitcoin-settled transactions using assets like sBTC and STX, with developer tooling support and easy wallet integrations. Stacks brings the liquidity, speed, and logic of modern payments to Bitcoin — fast digital transfers, smarter payment rules, and the UX digital payments deserve.
+
+Here are the payment use cases developers are building with today:
+
+### sBTC Pay
+
+sBTC Pay provides a payment gateway with APIs and webhooks for developers to instantly integrate a simple sBTC payment system in their app. A complete _**"Stripe for sBTC"**_ payment gateway that enables businesses to easily accept Bitcoin payments via sBTC on Stacks blockchain.
+
+**Implementation highlight:**\
+sBTC Pay comes with a few integration methods developers can start using right away. The React component from its `@sbtc-gateway/react` library provides UI components for readily usable sBTC payments.
+
+{% code title="@sbtc-gateway/react" %}
+```typescript
+import { SBTCProvider, PaymentButton } from '@sbtc-gateway/react';
+
+function App() {
+ return (
+
+ console.log('Success!', paymentIntent)}
+ />
+
+ );
+}
+```
+{% endcode %}
+
+
+
+Check out more from sBTC Pay
+
+* [Official website](https://sbtcpay.org/)
+* [Demo video](https://x.com/kai_builder/status/1962151430535700891)
+* [Winner of the Stacks Builder Competition](https://x.com/kai_builder/status/1967806436387459388)
+* [Github repo](https://github.com/STX-CITY/sbtc-pay)
+
+
+
+***
+
+### Bolt Wallet
+
+Bolt wallet not only enables sBTC as transaction fees, but also boasts lightning bolt speed for payments on Stacks while guaranteeing transaction confirmation. This is made possible by Stacks' sponsor transaction feature and optimistic confirmations.
+
+**Implementation highlight:**\
+The code snippet below demonstrates how to transfer sBTC between Stacks wallets while paying the fee in sBTC instead of STX using Bolt Protocol's sponsorship feature.
+
+{% code title="https://github.com/ronoel/bolt-protocol/blob/main/cookbook/transfer-stacks-to-stacks.md" expandable="true" %}
+```typescript
+import { STACKS_TESTNET } from "@stacks/network";
+import { bytesToHex } from "@stacks/common";
+import {
+ Cl,
+ FungiblePostCondition,
+ makeContractCall,
+ PostConditionMode,
+ SignedContractCallOptions,
+} from "@stacks/transactions";
+
+async function transferStacksToStacks() {
+ // Amount and fee in satoshis
+ const amount = 100000000; // 1 sBTC
+ const fee = 10; // 10 satoshis minimum fee
+
+ // Post condition to ensure exact amount+fee is spent
+ const ftPostCondition: FungiblePostCondition = {
+ type: 'ft-postcondition',
+ address: "", // Replace with actual sender address
+ condition: 'eq',
+ amount: amount + fee,
+ asset: 'SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token::sbtc-token'
+ };
+
+ // Transaction options
+ const txOptions: SignedContractCallOptions = {
+ sponsored: true, // Enable sponsorship
+ senderKey: "", // Replace with sender's private key
+ network: STACKS_TESTNET,
+ contractAddress: "SP3QZNX3CGT6V7PE1PBK17FCRK1TP1AT02ZHQCMVJ",
+ contractName: "boltproto-sbtc-v1",
+ functionName: "transfer-stacks-to-stacks",
+ functionArgs: [
+ Cl.uint(amount),
+ Cl.principal(""), // Replace with recipient address
+ Cl.none(), // No memo
+ Cl.uint(fee)
+ ],
+ postConditionMode: PostConditionMode.Deny,
+ postConditions: [ftPostCondition],
+ };
+
+ // Create and serialize the transaction
+ const transaction = await makeContractCall(txOptions);
+ const serializedTx = bytesToHex(transaction.serializeBytes());
+
+ // Submit to Bolt Protocol API
+ const response = await fetch('https://boltproto.org/api/v1/transaction/sbtc-token', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify({ serializedTx })
+ });
+
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`);
+ }
+
+ const data = await response.json();
+ console.log('Transaction submitted:', data.txid);
+ return data;
+}
+```
+{% endcode %}
+
+
+
+Check out more from Bolt wallet
+
+* [Official website for Bolt](https://boltproto.org/)
+* [Hiro Dev N' Tell with Ronoel.btc showcasing Bolt wallet in action](https://youtu.be/iuNQ88VoRiU?si=xR7hf5N0VJQlz1rm)
+* [Bolt Protocol](https://x.com/boltprotobtc)
+* [Github repo](https://github.com/ronoel/bolt-protocol)
+
+
diff --git a/docs/build/more-guides/c32check.md b/docs/build/more-guides/c32check.md
new file mode 100644
index 0000000000..d9a6926725
--- /dev/null
+++ b/docs/build/more-guides/c32check.md
@@ -0,0 +1,115 @@
+---
+description: Generating and decoding addresses on the Stacks blockchain.
+---
+
+# c32check
+
+
+
+{% hint style="info" %}
+For the c32check open-source repo: [https://github.com/stacks-network/c32check](https://github.com/stacks-network/c32check)
+{% endhint %}
+
+The Stacks blockchain uses c32-encoded public key hashes as addresses. Specifically, a **c32check address** is a c32check-encoded ripemd160 hash. This library is meant for generating and decoding addresses on the Stacks blockchain.
+
+### How it works
+
+Each c32check string encodes a 1-byte version and a 4-byte checksum. When decoded as a hex string, the wire format looks like this:
+
+```
+0 1 n+1 n+5
+|------|-----------------------------|---------------|
+version n-byte hex payload 4-byte hash
+```
+
+If `version` is the version byte (a 1-byte `number`) and `payload` is the raw bytes (e.g. as a `string`), then the `checksum` is calculated as follows:
+
+```
+checksum = sha256(sha256(version + payload)).substring(0,4)
+```
+
+In other words, the checksum is the first four bytes of the double-sha256 of the bytestring concatenation of the `version` and `payload`. This is similar to base58check encoding, for example.
+
+### Examples
+
+**Installation**
+
+{% code title="terminal" %}
+```shellscript
+npm install c32check
+```
+{% endcode %}
+
+```typescript
+> c32 = require('c32check')
+{ c32encode: [Function: c32encode],
+ c32decode: [Function: c32decode],
+ c32checkEncode: [Function: c32checkEncode],
+ c32checkDecode: [Function: c32checkDecode],
+ c32address: [Function: c32address],
+ c32addressDecode: [Function: c32addressDecode],
+ versions:
+ { mainnet: { p2pkh: 22, p2sh: 20 },
+ testnet: { p2pkh: 26, p2sh: 21 } },
+ c32ToB58: [Function: c32ToB58],
+ b58ToC32: [Function: b58ToC32] }
+```
+
+#### c32encode, c32decode
+
+```typescript
+> c32check.c32encode(Buffer.from('hello world').toString('hex'))
+'38CNP6RVS0EXQQ4V34'
+> c32check.c32decode('38CNP6RVS0EXQQ4V34')
+'68656c6c6f20776f726c64'
+> Buffer.from('68656c6c6f20776f726c64', 'hex').toString()
+'hello world'
+```
+
+#### c32checkEncode, c32checkDecode
+
+```typescript
+> version = 12
+> c32check.c32checkEncode(version, Buffer.from('hello world').toString('hex'))
+'CD1JPRV3F41VPYWKCCGRMASC8'
+> c32check.c32checkDecode('CD1JPRV3F41VPYWKCCGRMASC8')
+[ 12, '68656c6c6f20776f726c64' ]
+> Buffer.from('68656c6c6f20776f726c64', 'hex').toString()
+'hello world'
+```
+
+#### c32address, c32addressDecode
+
+> **Note**: These methods only work on ripemd160 hashes
+
+```typescript
+> hash160 = 'a46ff88886c2ef9762d970b4d2c63678835bd39d'
+> version = c32check.versions.mainnet.p2pkh
+22
+> c32check.c32address(version, hash160)
+'SP2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKNRV9EJ7'
+> c32check.c32addressDecode('SP2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKNRV9EJ7')
+[ 22, 'a46ff88886c2ef9762d970b4d2c63678835bd39d' ]
+```
+
+#### c32ToB58, b58ToC32
+
+Convert a Stacks address to its corresponding Bitcoin address, or vice versa.
+
+> **Note**: Common address versions are converted between c32check and base58check seamlessly, in order to accommodate Stacks addresses.
+
+```typescript
+> b58addr = '16EMaNw3pkn3v6f2BgnSSs53zAKH4Q8YJg'
+> c32check.b58ToC32(b58addr)
+'SPWNYDJ3STG7XH7ERWXMV6MQ7Q6EATWVY5Q1QMP8'
+> c32check.c32ToB58('SPWNYDJ3STG7XH7ERWXMV6MQ7Q6EATWVY5Q1QMP8')
+'16EMaNw3pkn3v6f2BgnSSs53zAKH4Q8YJg'
+```
+
+```typescript
+> b58addr = '3D2oetdNuZUqQHPJmcMDDHYoqkyNVsFk9r'
+> c32check.b58ToC32(b58addr)
+'SM1Y6EXF21RZ9739DFTEQKB1H044BMM0XVCM4A4NY'
+> c32check.c32ToB58('SM1Y6EXF21RZ9739DFTEQKB1H044BMM0XVCM4A4NY')
+'3D2oetdNuZUqQHPJmcMDDHYoqkyNVsFk9r'
+```
diff --git a/docs/build/more-guides/community-tutorials.md b/docs/build/more-guides/community-tutorials.md
new file mode 100644
index 0000000000..54448e5058
--- /dev/null
+++ b/docs/build/more-guides/community-tutorials.md
@@ -0,0 +1,27 @@
+# Community Tutorials
+
+source: EasyA x Stacks hackathon at Harvard University [2024]
+
+These tutorials have been created by various developers of the Stacks community. Have a tutorial to suggest? View the [contribution guide](http://localhost:3000/docs/contribute/docs) to submit a PR with a new tutorial added.
+
+### Written Tutorials
+
+* [Create a server-side rendered Stacks app with Remix](https://micro-stacks.dev/guides/with-remix)
+* [Build a Stacks app with Next.js](https://micro-stacks.dev/guides/with-nextjs)
+* [Creating a Voting Contract](https://www.clearness.dev/01-voting-clarity-smart-contract/01-getting-started)
+* [Building an NFT with Stacks and Clarity](https://blog.developerdao.com/building-an-nft-with-stacks-and-clarity)
+* [Minting NFTs with QuickNode](https://www.quicknode.com/guides/web3-sdks/how-to-mint-nfts-on-the-stacks-blockchain)
+* [Order Book Contract Walkthrough](https://byzantion.hiro.so/)
+* [Build a DEX on Stacks](https://www.pointer.gg/tutorials/build-a-dex-with-stacks/56abb3a4-05c1-4608-b096-f82189e9f759)
+* [NFT Tutorial](https://docs.hiro.so/tutorials/clarity-nft)
+* [Billboard Tutorial](https://docs.hiro.so/tutorials/clarity-billboard)
+* [Integrating NFTs Into a Game](https://gamefi-stacks.gitbook.io/gamefistacks/tutorials/integrate-nfts-into-game)
+* [Building on Stacks](https://github.com/amoweolubusayo/stacks-clarinet-tutorial)
+
+### Video Tutorials
+
+* [Web3 for Bitcoin](https://www.crowdcast.io/e/web3-for-bitcoin/)
+
+### Other Resources
+
+There are also a great amount of both tutorials and developer tools in the [Awesome Stacks repo](https://github.com/friedger/awesome-stacks-chain#clarity-resources).
diff --git a/docs/build/more-guides/onboarding/README.md b/docs/build/more-guides/onboarding/README.md
new file mode 100644
index 0000000000..6c36225277
--- /dev/null
+++ b/docs/build/more-guides/onboarding/README.md
@@ -0,0 +1,14 @@
+---
+description: Guides to assist the onboarding experience of your app
+---
+
+# Onboarding
+
+
+
+A smooth onboarding process is crucial for applications because it directly affects user retention and engagement. Here are a few reasons why it is important:
+
+* **User Retention**: A seamless onboarding experience helps in retaining new users by reducing friction and making it easier for them to get started with the app.
+* **First Impressions**: The onboarding process shapes the first impressions of the application. A positive experience can lead to increased trust and credibility.
+
+By prioritizing a well-designed onboarding process, developers can enhance user experience and promote wider adoption of Bitcoin/Stacks applications.
diff --git a/docs/build/more-guides/onboarding/signing-with-turnkey.md b/docs/build/more-guides/onboarding/signing-with-turnkey.md
new file mode 100644
index 0000000000..1d6ca61b3c
--- /dev/null
+++ b/docs/build/more-guides/onboarding/signing-with-turnkey.md
@@ -0,0 +1,181 @@
+---
+description: Leverage Stacks.js with Turnkey's embedded wallet solutions
+---
+
+# Signing with Turnkey
+
+[Turnkey’s embedded wallet](https://docs.turnkey.com/embedded-wallets/overview) makes STX & sBTC transactions seamless, secure, and user-friendly, letting your users experience Bitcoin-native apps without friction. Using external embedded wallet/signing solutions with Stacks comes down to properly passing in a hashed transaction payload to a provided signing method. We'll show you how to derive that hashed transaction payload in this guide.
+
+{% hint style="info" %}
+Currently, Turnkey does not natively support Stacks, but can be simply integrated together using the example below. Work is in progress for native Stacks support in Turnkey.
+{% endhint %}
+
+### Address derivation
+
+Turnkey supports Stacks address derivation with `ADDRESS_FORMAT_COMPRESSED` and `ADDRESS_FORMAT_UNCOMPRESSED` address formats. Stacks addresses are derived from the secp256k1 curve, which Turnkey fully supports.
+
+{% hint style="info" %}
+Use a secp256k1 generated public key to derive Stacks addresses and sign Stacks transactions. In most cases with Turnkey, using an Ethereum account's public key would satisfy this.
+{% endhint %}
+
+```typescript
+import { publicKeyToAddress } from "@stacks/transactions"
+
+const stxAddress = publicKeyToAddress(matchingAccount?.publicKey!)
+
+// STX address: SP1Z6MYME47PW04D1J15K368XZE02VWQ2A5SRC4HV
+// publicKey: 03169b8f8bbad2cc6435893c5f255cd5201d272befa8556c82136bf9b36aa0d778
+```
+
+### Transaction construction and signing
+
+A sample script that demonstrates how to sign a Stacks transaction with Turnkey. Stacks uses the secp256k1 cryptographic curve for transaction signing, but there some specific data formatting that takes place for the signing process.
+
+Simplified step-by-step process of what this example script is showing:
+
+1. Generate `sigHash` from unsigned transaction
+2. Generate `preSignSigHash`
+3. ECDSA sign `preSignSigHash` with a Turnkey private key
+4. Concatenate outputted raw signature (from step 3) components in the order of V + R + S
+5. The resulting signature of step 4 will be the `nextSig`
+6. Reassign `spendingCondition.signature` with the value of `nextSig`
+
+**Note:** The hashFunction `HASH_FUNCTION_NO_OP` should be set this way because the payload has already been hashed.
+
+{% hint style="info" %}
+Signing Stacks transactions works with either Turnkey's Server or React SDKs
+{% endhint %}
+
+```typescript
+import { Turnkey as TurnkeyServerSDK } from "@turnkey/sdk-server";
+import {
+ broadcastTransaction,
+ createMessageSignature,
+ makeUnsignedSTXTokenTransfer,
+ sigHashPreSign,
+ SingleSigSpendingCondition,
+ TransactionSigner,
+ publicKeyToAddress,
+ type StacksTransactionWire,
+} from "@stacks/transactions";
+import * as path from "path";
+import * as dotenv from "dotenv";
+
+// Load environment variables from `.env.local`
+dotenv.config({ path: path.resolve(process.cwd(), ".env.local") });
+
+// Define the Turnkey API client
+const client = new TurnkeyServerSDK({
+ apiBaseUrl: process.env.TURNKEY_BASE_URL!,
+ apiPrivateKey: process.env.TURNKEY_API_PRIVATE_KEY!,
+ apiPublicKey: process.env.TURNKEY_API_PUBLIC_KEY!,
+ defaultOrganizationId: process.env.TURNKEY_ORGANIZATION_ID!,
+});
+
+// Construct an unsigned Stacks transaction
+const constructStacksTx = async (pubKey: string) => {
+ const recipient = process.env.STACKS_RECIPIENT_ADDRESS!;
+
+ let transaction = await makeUnsignedSTXTokenTransfer({
+ recipient,
+ amount: 300,
+ publicKey: pubKey,
+ numSignatures: 1,
+ network: "mainnet",
+ });
+
+ return { stacksTransaction: transaction, sighash: transaction.signBegin() };
+};
+
+// The resulting preSignSigHash is what ultimately gets signed by a private key using ECDSA over the secp256k1 curve.
+const generatePreSignSigHash = (
+ transaction: StacksTransactionWire,
+ sighash: string
+) => {
+ let preSignSigHash = sigHashPreSign(
+ sigHash,
+ transaction.auth.authType,
+ transaction.auth.spendingCondition.fee,
+ transaction.auth.spendingCondition.nonce,
+ );
+
+ return preSignSigHash;
+};
+
+const signStacksTx = async () => {
+ try {
+ // Grab the public key associated with the user's Turnkey Ethereum account as a proxy
+ // Ethereum's public key generation and signing curve matches that of Stacks
+ // Use `publicKeyToAddress` to convert public key to Stacks address for display purposes
+ const stacksPublicKey = process.env.TURNKEY_SIGNER_PUBLIC_KEY!;
+
+ let { stacksTransaction, stacksTxSigner } = await constructStacksTx(
+ stacksPublicKey!,
+ );
+ let preSignSigHash = generatePreSignSigHash(
+ stacksTransaction,
+ stacksTxSigner,
+ );
+
+ const payload = `0x${preSignSigHash}`;
+
+ const signature = await client?.apiClient().signRawPayload({
+ payload,
+ // either passing in pubkey or account address
+ signWith: stacksPublicKey,
+ encoding: "PAYLOAD_ENCODING_HEXADECIMAL",
+ hashFunction: "HASH_FUNCTION_NO_OP",
+ });
+
+ // r and s values returned are in hex format, may need to padStart r and s values
+ // v should be "00" for Stacks but the returned "01" also works
+ const nextSig = `${signature!.v}${signature!.r.padStart(64, "0")}${signature!.s.padStart(64, "0")}`;
+
+ // Reassign signature field in transaction with `nextSig`
+ let spendingCondition = stacksTransaction.auth.spendingCondition as SingleSigSpendingCondition;
+ spendingCondition.signature = createMessageSignature(nextSig);
+
+ return stacksTransaction;
+ } catch (err) {
+ console.error("Signing failed:", err);
+ return undefined;
+ }
+};
+
+const handleBroadcastTx = async () => {
+ let tx = await signStacksTx();
+
+ let result = await broadcastTransaction({
+ transaction: tx!,
+ network: "mainnet",
+ });
+
+ console.log("Broadcast Result:", result);
+};
+
+(async () => {
+ await handleBroadcastTx();
+})();
+```
+
+### **Components of a ECDSA signature**
+
+* **r (32 bytes)**: The x-coordinate of a point on the elliptic curve, derived during the signing process.
+* **s (32 bytes)**: A scalar derived from the message hash, private key, and the nonce k.
+* **v (1 byte)**: Indicates which of the two possible public keys was used to generate the signature.
+
+### **Why Use Turnkey Embedded Wallets for Stacks Apps**
+
+* **Seamless onboarding** – Users can start interacting with your app immediately, without installing separate wallets or extensions.
+* **Simplified authentication** – Turnkey handles secure key management and signing, including modern standards like passkeys.
+* **Improved UX** – Embedded wallets reduce friction in transactions, making dApps feel more like mainstream apps.
+* **Multi-chain-ready** – Easily support STX, sBTC and other blockchain assets without building your own wallet infrastructure.
+
+***
+
+### Additional Resources
+
+* \[[Hiro Blog](https://www.hiro.so/blog/dissecting-a-transaction-signature-on-stacks)] Dissecting a Transaction Signature on Stacks
+* \[[Twitter](https://x.com/ECBSJ/status/1976286764018077933)] Stacks DevRel Office Hours with Turnkey's Michael Lewellen
+* \[[Twitter](https://x.com/kai_builder/status/1977059253379834059)] sBTC.Cool - Example project on Stacks integrating Turnkey
+* \[[Twitter](https://x.com/turnkeyhq/status/1946239286686241228)] Turnkey supporting transaction signing for Stacks
diff --git a/docs/build/more-guides/price-oracles/README.md b/docs/build/more-guides/price-oracles/README.md
new file mode 100644
index 0000000000..c80a5be6d0
--- /dev/null
+++ b/docs/build/more-guides/price-oracles/README.md
@@ -0,0 +1,46 @@
+---
+description: Leverage real-time market price data in your Clarity smart contract
+---
+
+# Price Oracles
+
+
+
+Smart contracts written in **Clarity** run in a deterministic sandbox: they can read data in the Stacks and Bitcoin chainstate, but _nothing else_. Whenever your dApp needs the latest **BTC/USD**, **STX/BTC**, or any other market price, you’ll rely on an **oracle** to bring that data on‑chain in a verifiable way.
+
+This page explains why price‑feed oracles matter on Stacks and links to the specific oracle provider docs with instructions on how to integrate them.
+
+***
+
+## Why you need a price‑feed oracle
+
+For DeFi smart contracts, it’s crucial to leverage trusted sources for asset pricing, which has profound implications for investor returns and trading strategies.
+
+Here are some possible scenarios where you might need an oracle.
+
+| On‑chain need | Typical Stacks use case | What the oracle supplies |
+| ------------------------------------ | ---------------------------------------------- | ----------------------------------- |
+| **Liquidations & collateral ratios** | Lending / borrowing protocols, margin trading | Signed price updated every N blocks |
+| **Stablecoin peg maintenance** | BTC‑backed or exogenous‑collateral stablecoins | Reference BTC/USD (or other) price |
+| **AMM curve calculations** | DEXs that tune fees or rebalance pools | Time‑weighted average price (TWAP) |
+| **Derivatives settlement** | Options, futures, or perpetual swaps | Final settlement price at expiry |
+
+{% hint style="info" %}
+Rule of thumb: if your contract’s math depends on a real‑time market price, you need a price‑feed oracle.
+{% endhint %}
+
+## Oracle Providers for Stacks
+
+Here are the currently available oracle providers that Stacks builders commonly use for price data.
+
+### **Pyth**
+
+Pyth is a pull-based oracle. Stacks Labs currently maintains the Pyth bridge.
+
+[Learn how to use Pyth.](pyth.md)
+
+### **DIA**
+
+DIA is another oracle provider used by Stacks builders. See DIA's [guide](https://nexus.diadata.org/how-to-guides/fetch-price-data/chain-specific-guide/stacks) for how to use DIA oracles with Stacks. Check out the video tutorial to learn more on how DIA works for Clarity smart contracts:
+
+{% embed url="https://youtu.be/bhWQxHGpv2s?si=dWlBAEAuYtoQj2sC" %}
diff --git a/docs/build/more-guides/price-oracles/dia.md b/docs/build/more-guides/price-oracles/dia.md
new file mode 100644
index 0000000000..31cda65e57
--- /dev/null
+++ b/docs/build/more-guides/price-oracles/dia.md
@@ -0,0 +1,75 @@
+# Using DIA with Stacks
+
+DIA's oracle protocol utilizes a push price model. As the developer, you would only need to fetch prices directly from DIA's Clarity contracts.
+
+Price data can be fetched in Clarity by making an external call to the DIA `.dia-oracle` contract’s `get-value` read-only function with the desired asset pair.
+
+### DIA's Clarity Contracts
+
+{% hint style="info" %}
+For the full list of supported asset feeds for Stacks with DIA, check out their docs [here](https://www.diadata.org/docs/nexus/how-to-guides/fetch-price-data/chain-specific-guide/stacks).
+{% endhint %}
+
+
+
+### Example
+
+Below is an example where we are fetching the sBTC price and determining if a user has the required minimum balance to join a whitelist.
+
+It does this by:
+
+* Reading the **current sBTC/USD price** from DIA’s on-chain oracle
+* Reading the caller’s **sBTC balance**
+* Calculating the USD value of that balance
+* Whitelisting the user if they meet a minimum threshold
+
+In short: **prove you hold enough sBTC (by USD value) to be eligible for a whitelist.**
+
+{% hint style="warning" %}
+All price feeds from DIA's Clarity contracts all have an implicit decimal place of 8 unless specified otherwise.
+{% endhint %}
+
+(define-constant MIN-SBTC-BALANCE u100)
+(define-constant ERR_READING_SBTC_BALANCE (err u7001))
+(define-constant ERR_NOT_ENOUGH_SBTC (err u7002))
+(define-constant ERR_NOT_OWNER (err u7003))
+(define-constant SBTC-PRICE-EXPO 8)
+
+(define-map whitelist
+ principal
+ bool
+)
+
+(define-public (check-eligibility)
+ (let (
+ (sbtc-price-data (unwrap-panic (contract-call? 'SP1G48FZ4Y7JY8G2Z0N51QTCYGBQ6F4J43J77BQC0.dia-oracle
+ get-value "sBTC/USD"
+ )))
+ (sbtc-usd-price (to-int (get value sbtc-price-data)))
+ (price-denomination (pow 10 SBTC-PRICE-EXPO))
+ (adjusted-price (to-uint (/ sbtc-usd-price price-denomination)))
+ (user-sbtc-balance (unwrap!
+ (contract-call? 'SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token
+ get-balance-available tx-sender
+ )
+ ERR_READING_SBTC_BALANCE
+ ))
+ )
+ (if (> (/ (* user-sbtc-balance adjusted-price) (to-uint price-denomination))
+ MIN-SBTC-BALANCE
+ )
+ (ok (map-set whitelist tx-sender true))
+ ERR_NOT_ENOUGH_SBTC
+ )
+ )
+)
+
+
+
+***
+
+### Additional Resources
+
+* \[[Hiro YT](https://youtu.be/bhWQxHGpv2s?si=RsKaCe169Vu6zw_e)] How to use DIA's price data featuring Khawla, Product Manager @ DIA
+* \[[DIA Docs](https://www.diadata.org/docs/nexus/how-to-guides/fetch-price-data/chain-specific-guide/stacks)] The Stacks guide in DIA's docs
+* \[[Twitter](https://x.com/DIAdata_org/status/1945476086110032147)] DIA x Stacks Oracle Grants
diff --git a/docs/build/more-guides/price-oracles/pyth.md b/docs/build/more-guides/price-oracles/pyth.md
new file mode 100644
index 0000000000..d4169d3f4b
--- /dev/null
+++ b/docs/build/more-guides/price-oracles/pyth.md
@@ -0,0 +1,484 @@
+# Using Pyth with Stacks
+
+{% hint style="success" %}
+For the latest releases and versions of the Stacks-Pyth contracts, check out the open-source repo [here](https://github.com/stx-labs/stacks-pyth-bridge).
+{% endhint %}
+
+The contract logic, that we’ll use for this example, will mint an NFT in exchange for $100 of sBTC. Our Clarity contract will read the price of BTC/USD from the Pyth integration contract to calculate the amount of sBTC required to mint the NFT.
+
+Each Pyth Network price feed is referred to via a unique ID. The full list of price feeds is listed on the pyth.network website. To use a price feed on-chain, look up its ID, then store the feed ID in your program for price feed queries. Each price feed has its own unique id:
+
+**Available Pyth price feeds for Stacks:**
+
+* **BTC**: [0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43](https://www.pyth.network/price-feeds/crypto-btc-usd)
+* **STX:** [0xec7a775f46379b5e943c3526b1c8d54cd49749176b0b98e02dde68d1bd335c17](https://www.pyth.network/price-feeds/crypto-stx-usd)
+* **USDC:** [0xeaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a](https://www.pyth.network/price-feeds/crypto-usdc-usd)
+* **ETH**: [0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace](https://www.pyth.network/price-feeds/crypto-eth-usd)
+
+{% hint style="info" %}
+To request more supported price feeds, open an issue in the Pyth maintained repo for Stacks [here](https://github.com/Trust-Machines/stacks-pyth-bridge).
+{% endhint %}
+
+Pyth Network uses a pull price update model that is slightly different from other oracles you may be more familiar with. Most oracles today use a push model, where the oracle runs an off-chain process that continuously sends transactions to update an on-chain price. In contrast, Pyth Network does not operate an off-chain process that pushes prices on-chain. Instead, it delegates this work to Pyth Network users.
+
+
+
+The maintained Pyth integration contract for Stacks is called [.pyth-oracle-v4](https://explorer.stacks.co/txid/SP1CGXWEAMG6P6FT04W66NVGJ7PQWMDAC19R7PJ0Y.pyth-oracle-v4?chain=mainnet). This contract serves as the main entry point for updating and getting price feed data. The Pyth protocol integration is available as a Beta on both testnet and mainnet networks, to help developers test, give feedback, and ensure the reliability and stability of the integration.
+
+#### File setup
+
+Below are how the contracts and mainfest files are setup in this example Clarinet project. We'll be using Clarinet's mainnet simulation for this example, hence why we are adding mainnet contracts for Pyth in our files.
+
+{% tabs %}
+{% tab title="main.clar" %}
+{% code expandable="true" %}
+```clarity
+(define-constant CONTRACT_OWNER tx-sender)
+(define-constant COST-OF-BENJAMIN-NFT u100)
+
+(define-constant ERR_READING_SBTC_BALANCE (err u7001))
+(define-constant ERR_NOT_ENOUGH_SBTC (err u7002))
+(define-constant ERR_NOT_OWNER (err u7003))
+
+(define-public (join-the-benjamin-club (price-feed-bytes (buff 8192)))
+ (let (
+ ;; Update & verify VAA for BTC price feed
+ (update-status (try! (contract-call? 'SP1CGXWEAMG6P6FT04W66NVGJ7PQWMDAC19R7PJ0Y.pyth-oracle-v4
+ verify-and-update-price-feeds price-feed-bytes {
+ pyth-storage-contract: 'SP1CGXWEAMG6P6FT04W66NVGJ7PQWMDAC19R7PJ0Y.pyth-storage-v4,
+ pyth-decoder-contract: 'SP1CGXWEAMG6P6FT04W66NVGJ7PQWMDAC19R7PJ0Y.pyth-pnau-decoder-v3,
+ wormhole-core-contract: 'SP1CGXWEAMG6P6FT04W66NVGJ7PQWMDAC19R7PJ0Y.wormhole-core-v4,
+ })))
+ ;; Get fresh BTC price
+ (price-data (try! (contract-call? 'SP1CGXWEAMG6P6FT04W66NVGJ7PQWMDAC19R7PJ0Y.pyth-oracle-v4
+ get-price
+ ;; The official BTC price feed id.
+ 0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43
+ 'SP1CGXWEAMG6P6FT04W66NVGJ7PQWMDAC19R7PJ0Y.pyth-storage-v4
+ )))
+ ;; Adjust price and get user sBTC balance
+ ;; Price feeds represent numbers in a fixed-point format. The expo property tells us
+ ;; at what certain position is the decimal point implicity fixed.
+ (price-denomination (pow 10 (* (get expo price-data) -1)))
+ ;; We'll adjust the price to its normal decimal representation.
+ (adjusted-price (to-uint (/ (get price price-data) price-denomination)))
+ ;; Get the user's current sBTC balance.
+ (user-sbtc-balance (unwrap!
+ (contract-call? 'SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token
+ get-balance-available tx-sender
+ )
+ ERR_READING_SBTC_BALANCE
+ ))
+ )
+ ;; Determine if the user has at least $100 worth of sBTC to join the Benjamin Club and mint NFT
+ (if (> (/ (* user-sbtc-balance adjusted-price) (to-uint price-denomination))
+ COST-OF-BENJAMIN-NFT
+ )
+ (let ((hundred-dollars-in-sbtc (/ (* COST-OF-BENJAMIN-NFT (to-uint price-denomination)) adjusted-price)))
+ (try! (contract-call? 'SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token
+ transfer hundred-dollars-in-sbtc tx-sender current-contract
+ none
+ ))
+ (contract-call? .nft mint tx-sender)
+ )
+ ERR_NOT_ENOUGH_SBTC
+ )
+ )
+)
+```
+{% endcode %}
+{% endtab %}
+
+{% tab title="nft.clar" %}
+{% code expandable="true" %}
+```clarity
+;; This contract implements the SIP-009 community-standard Non-Fungible Token trait
+(impl-trait 'SP2PABAF9FTAJYNFZH93XENAJ8FVY99RRM50D2JG9.nft-trait.nft-trait)
+
+;; Define the NFT's name
+(define-non-fungible-token benjamin uint)
+
+;; Keep track of the last minted token ID
+(define-data-var last-token-id uint u0)
+
+;; Define constants
+(define-constant CONTRACT_OWNER tx-sender)
+(define-constant COLLECTION_LIMIT u100)
+
+(define-constant ERR_OWNER_ONLY (err u100))
+(define-constant ERR_NOT_TOKEN_OWNER (err u101))
+(define-constant ERR_SOLD_OUT (err u300))
+
+(define-data-var base-uri (string-ascii 80) "")
+
+;; SIP-009 function: Get the last minted token ID.
+(define-read-only (get-last-token-id)
+ (ok (var-get last-token-id))
+)
+
+;; SIP-009 function: Get link where token metadata is hosted
+(define-read-only (get-token-uri (token-id uint))
+ (ok (some (var-get base-uri)))
+)
+
+;; SIP-009 function: Get the owner of a given token
+(define-read-only (get-owner (token-id uint))
+ (ok (nft-get-owner? benjamin token-id))
+)
+
+;; SIP-009 function: Transfer NFT token to another owner.
+(define-public (transfer
+ (token-id uint)
+ (sender principal)
+ (recipient principal)
+ )
+ (begin
+ ;; #[filter(sender)]
+ (asserts! (is-eq tx-sender sender) ERR_NOT_TOKEN_OWNER)
+ (nft-transfer? benjamin token-id sender recipient)
+ )
+)
+
+;; Mint a new NFT.
+(define-public (mint (recipient principal))
+ ;; Create the new token ID by incrementing the last minted ID.
+ (let ((token-id (+ (var-get last-token-id) u1)))
+ ;; Ensure the collection stays within the limit.
+ (asserts! (< (var-get last-token-id) COLLECTION_LIMIT) ERR_SOLD_OUT)
+ ;; Only the contract owner can mint.
+ (asserts! (is-eq contract-caller .main) ERR_OWNER_ONLY)
+ ;; Mint the NFT and send it to the given recipient.
+ (try! (nft-mint? benjamin token-id recipient))
+ ;; Update the last minted token ID.
+ (var-set last-token-id token-id)
+ ;; Return a success status and the newly minted NFT ID.
+ (ok token-id)
+ )
+)
+
+```
+{% endcode %}
+{% endtab %}
+
+{% tab title="Clarinet.toml" %}
+{% code expandable="true" %}
+```toml
+[project]
+name = 'clarity-contracts'
+description = ''
+authors = []
+telemetry = false
+cache_dir = './.cache'
+
+[[project.requirements]]
+contract_id = 'SP2PABAF9FTAJYNFZH93XENAJ8FVY99RRM50D2JG9.nft-trait'
+
+[[project.requirements]]
+contract_id = 'SP1CGXWEAMG6P6FT04W66NVGJ7PQWMDAC19R7PJ0Y.pyth-oracle-v4'
+
+[[project.requirements]]
+contract_id = 'SP1CGXWEAMG6P6FT04W66NVGJ7PQWMDAC19R7PJ0Y.wormhole-core-v4'
+
+[[project.requirements]]
+contract_id = 'SP1CGXWEAMG6P6FT04W66NVGJ7PQWMDAC19R7PJ0Y.pyth-pnau-decoder-v3'
+
+[[project.requirements]]
+contract_id = 'SP1CGXWEAMG6P6FT04W66NVGJ7PQWMDAC19R7PJ0Y.pyth-storage-v4'
+
+[[project.requirements]]
+contract_id = 'SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token'
+
+[contracts.main]
+path = 'contracts/main.clar'
+clarity_version = 4
+epoch = 'latest'
+
+[contracts.nft]
+path = 'contracts/nft.clar'
+clarity_version = 4
+epoch = 'latest'
+
+[repl.analysis]
+passes = ['check_checker']
+
+[repl.analysis.lints]
+
+[repl.analysis.check_checker]
+strict = false
+trusted_sender = false
+trusted_caller = false
+callee_filter = false
+
+[repl.remote_data]
+enabled = true
+api_url = 'https://api.hiro.so'
+use_mainnet_wallets = true
+```
+{% endcode %}
+{% endtab %}
+{% endtabs %}
+
+### Contract Walkthrough
+
+The walkthrough below will use a example contract that will mint an NFT in exchange for $100 of sBTC. Our Clarity contract will read the price of BTC/USD from the Pyth integration contract to calculate the amount of sBTC required to mint the NFT. The action of minting an NFT if one has at least $100 worth of sBTC will be deemed as _"joining the benjamin club"_. Benjamin is in reference to Benjamin Franklin being the face of a one hundred dollar bill, get it?
+
+{% stepper %}
+{% step %}
+#### Verify and update the BTC price feed
+
+We'll open up our function by accepting a `(price-feed-bytes (buff 8192))` parameter. This `price-feed-bytes` is in reference to a VAA message payload. Later in this guide we'll show you how to fetch this payload on the front end.
+
+You'll notice in the Clarity snippet below we open up `let` bindings of our function to:
+
+1. Verify and update the BTC price feed with its latest VAA message (more on how to pull the VAA later in this guide). This is a means of participating in the pull price update model.
+2. Getting a fresh instance of the updated price data for BTC.
+
+{% hint style="info" %}
+The `pyth-oracle-contract`, `pyth-storage-contract`, `pyth-decoder-contract`, and `wormhole-core-contract` do not need to be hardcorded in your contract. It's recommended to pass these contracts into the outer function as arguments since these contracts are susceptible to future upgrades.
+{% endhint %}
+
+{% code title="main.clar" expandable="true" %}
+```clarity
+;; --snip--
+
+(define-public (join-the-benjamin-club (price-feed-bytes (buff 8192)))
+ (let (
+ ;; Update & verify VAA for BTC price feed
+ (update-status (try! (contract-call? 'SP1CGXWEAMG6P6FT04W66NVGJ7PQWMDAC19R7PJ0Y.pyth-oracle-v4
+ verify-and-update-price-feeds price-feed-bytes {
+ pyth-storage-contract: 'SP1CGXWEAMG6P6FT04W66NVGJ7PQWMDAC19R7PJ0Y.pyth-storage-v4,
+ pyth-decoder-contract: 'SP1CGXWEAMG6P6FT04W66NVGJ7PQWMDAC19R7PJ0Y.pyth-pnau-decoder-v3,
+ wormhole-core-contract: 'SP1CGXWEAMG6P6FT04W66NVGJ7PQWMDAC19R7PJ0Y.wormhole-core-v4,
+ })))
+ ;; Get fresh BTC price
+ (price-data (try! (contract-call? 'SP1CGXWEAMG6P6FT04W66NVGJ7PQWMDAC19R7PJ0Y.pyth-oracle-v4
+ get-price
+ ;; The official BTC price feed id.
+ 0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43
+ 'SP1CGXWEAMG6P6FT04W66NVGJ7PQWMDAC19R7PJ0Y.pyth-storage-v4
+ )))
+
+;; --snip---
+```
+{% endcode %}
+{% endstep %}
+
+{% step %}
+#### Handling \`get-price\` data
+
+After updating and verifying the price feed in question, and then getting the updated price feed data, we'll need to handle the price feed data and its properties.
+
+The price feed data returned from invoking the `get-price` function of the `.pyth-oracle-v4` contract looks like the below:
+
+```
+{
+ price-identifier: 0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43,
+ price: 10603557773590,
+ conf: u3776653890,
+ ema-price: 10602069900000,
+ ema-conf: u4062895700,
+ expo: -8,
+ publish-time: u1750425711,
+ prev-publish-time: u1750425710
+}
+```
+{% endstep %}
+
+{% step %}
+#### Adjust returned price value and determine mint eligibility
+
+With the latest price feed data returned, we can adjust the price based on the `expo` property. Price feeds represent numbers in a fixed-point format. Fixed-point numeric representation is a way of storing numbers with fractional parts using integers, where the decimal point is implicitly fixed at a certain position. So in the above returned price feed data, the returned price of `10603557773590` and given expo of `-8` should be formatted as `106035`. The same exponent is used for both the price and confidence interval.
+
+We can then determine the USD amount of sBTC the user owns and decide if it is enough to mint a `benjamin-nft` for $100 worth of sBTC. Benjamin is in reference to Benjamin Franklin being the face of a one hundred dollar bill, get it?
+
+{% code title="main.clar" fullWidth="false" expandable="true" %}
+```clarity
+;; --snip--
+
+ ;; Price feeds represent numbers in a fixed-point format. The expo property tells us
+ ;; at what certain position is the decimal point implicity fixed.
+ (price-denomination (pow 10 (* (get expo price-data) -1)))
+ ;; We'll adjust the price to its normal decimal representation.
+ (adjusted-price (to-uint (/ (get price price-data) price-denomination)))
+ ;; Get the user's current sBTC balance.
+ (user-sbtc-balance (unwrap!
+ (contract-call? 'SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token
+ get-balance-available tx-sender
+ )
+ ERR_READING_SBTC_BALANCE
+ ))
+ )
+ ;; Determine if the user has at least $100 worth of sBTC to join the Benjamin Club and mint NFT
+ (if (> (/ (* user-sbtc-balance adjusted-price) (to-uint price-denomination))
+ COST-OF-BENJAMIN-NFT
+ )
+ (let ((hundred-dollars-in-sbtc (/ (* COST-OF-BENJAMIN-NFT (to-uint price-denomination)) adjusted-price)))
+ (try! (contract-call? 'SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token
+ transfer hundred-dollars-in-sbtc tx-sender current-contract
+ none
+ ))
+ (contract-call? .nft mint tx-sender)
+ )
+ ERR_NOT_ENOUGH_SBTC
+ )
+ )
+)
+```
+{% endcode %}
+{% endstep %}
+{% endstepper %}
+
+### Interact with contract in console using mxs
+
+Since we are using Pyth and sBTC's mainnet contract addresses in our contract, we'll use Clarinet's mainnet simulation feature to interact with the contract in simnet.
+
+{% hint style="warning" %}
+Be sure you've enabled mainnet simulation in your manifest file. See the Clarinet.toml file above.
+{% endhint %}
+
+{% stepper %}
+{% step %}
+#### Set \`tx\_sender\` to a mainnet address
+
+In the Clarinet console run: `::set_tx_sender `
+
+You'll want to grab a `` that most likely has over $100 of sBTC. This is so we can have a simulation of being able to mint the NFT. Then switch the `tx_sender` context so that we can have _that_ mainnet address simulate calling our contract.
+{% endstep %}
+
+{% step %}
+#### Call \`join-the-benjamin-club\` with a VAA payload
+
+In the Clarinet console run: `(contract-call? 'SP1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRCBGD7R.main join-the-benjamin-club )`
+
+Pass in a valid VAA payload into the `join-the-benjamin-club` function. If everything passes, you should see the events emitted from the contract along with an `(ok u1)` response.
+
+
+
+Where to get a sample VAA payload?
+
+You can use this sample VAA payload to test with. This VAA payload is outdated but should be testable in simnet/console.
+
+```
+0x504e41550100000003b801000000040d0064f9d65f754bc6426b50d45047fc50c905196202e888b73182a8177579ec838f652d710879a9a0c3026bd9e44b32509b9c94e86328d89235c5221e4cd20303ca000265aa2173fe44b28c3942c984ee953e9e2a06a686656c8bd36fbf396d7b4bfe9338bd6017a484b60ca1c80a75458f55ff9c9dd3e5edfa45f6243c13d77f414d4000045529833b17cfc6b011de0b72709c785a86d0ce9281a8c21a250f55d3fbfd79b47b89f110c63acdf8e0fa251d245b6e87ccbf5747dab2ba6eaf22e27f16fc97580006f673a3f384580e0bc7c5a246fb77a37f83ded9fe1368f3c15cdbad2475f2378d0daae7d3201e23ba45c04606dedea0327bd095f7b45d9dd84600b8e877af0c810008a4018e5793e30ac8439aef1b3ce284b670e95ab5ce76090f4dac860a1267177355102ddc46d33f4c53c253b30cb945ce63c710773fa40ae846192c6d1e335921000aea43bd88cc9891274d2b7f493b362c7799b2bf1e40630181fecce951118c987345da8f194ac0a44a2f956dce99b61f2254fe6b2409382d8e887e8fa07e6894aa000b9639228e880e97da54c07a9b762849a232a6f4358d9c82ec2e9a57c55cf0d89767e9e690586e52c752f31d541b1d68f7a86f3d7dffbbd6229fae2aa9b7647815010ca826b369905ff52daa0204b2ce3cedde1eee11d167e0cbdad3350362210840523db4c95c4669bd59b5e3dcd84d8bed673d0452d2229832f9af0904f070721fd0010d1b6af9c169ab48b47d6726d35f030eddabf9e6e04058097730bca037284a114a439b7ceb984013e8bc4873182dfd893d52c91a558a4bafe32f6d9a692765fc27010ef1c798f6db4a3c6387797dff6c06779b45b03bc1fde7a1eb86942bbb8ab3d5fc70c317d51dd71cbac39b8bd038bcf72552e4bc048f4e0731b9643090eb8bb1b6000fca5d6ac6f0e6569e1072566a56075dae7db43d8a008e939422863890c64e76b81544ae0ebaaacb473241c75cf5e2a8a1fd5c1cd5ee99970113e4d4bd0a86d9c70010c66616689026b43cbcd0012c7e87c9de75b7b8f60d2c765ec298ade7862d64ce63ef95670553bc120b08b52e6c5893a0509287ad5b38cd44a9113ddce5dc4c12001177acdc2be20bef459c68d319fd121fea8c2fbd1aad4ee8ebe36a5750214c39510b60e89b4c247e6e354f64722a49eb40ba2ba164cb9e6191e14b81155f16e6a4006935e74900000000001ae101faedac5851e32b9b23b5f9411a8c2bac4aae3ed4dd7b811dd1a72ea4aa71000000000a6abf2a014155575600000000000f78660e00002710c82bc426063e681025b2a2462b81da02fbdc9ab001005500e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b4300000852e1a4948000000000ac606b00fffffff8000000006935e749000000006935e7480000084e36eef02000000000a4da13a40d0d91f61daad89890a2c5da1abd4009915ccb2042e737bd6a369235eadc65f71867b56b312545c86c2cd2cd18971f74e0ef4e849a2b295b12dab11d5650dc565595a445ea019e1258a1397dc974e42ef8315937dc38ca22e8327aa6c21decb109199d18fec07feded692d0a8b1660748d3402dcd9e84229dd201c5da161c653ae21e63acdbf9ee603deec2668923bc0435272b1fc3851957c2a7a4867704a39d4e0c43b378456f0695c944f2bc3ba3ea356d4d3318a0b8c666d8df3a74fa3cea21e74470dc680878ff8dac909832fea3e4dc56c1fa5287cd472db6db3eb54c232d4faf9080009f4fa433b6b465ced1e2826dc510e7cf81c7261bf377e1847c0f08d7280f8
+```
+
+
+
+
+
+Run unit tests
+
+You can also test your contract using mxs in unit tests. See the below unit test setup that shows how you can fetch the latest VAA for your contract call.
+
+{% code title="main.test.ts" expandable="true" %}
+```typescript
+import { describe, expect, it } from "vitest"
+import { Cl, } from "@stacks/transactions"
+import { HermesClient } from "@pythnetwork/hermes-client";
+
+const accounts = simnet.getAccounts()
+const deployer = accounts.get("deployer")
+
+async function handleFetchLatestVaa() {
+ const connection = new HermesClient("https://hermes.pyth.network", {});
+
+ const priceIds = [
+ "0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43",
+ ];
+
+ const priceUpdates = await connection.getLatestPriceUpdates(priceIds);
+ console.log(priceUpdates);
+
+ let latestVaaHex = `0x${priceUpdates.binary.data[0]}`;
+
+ return latestVaaHex;
+}
+
+describe("pyth unit tests", () => {
+ it("ensures joining of Benjaming Club", async () => {
+ let VAA = await handleFetchLatestVaa()
+
+ let confirmation = simnet.callPublicFn(
+ `${deployer}.main`,
+ "join-the-benjamin-club",
+ [Cl.bufferFromHex(VAA)],
+ ""
+ )
+
+ expect(confirmation.result).toBeOk(Cl.uint(1))
+
+ // an extended timeout value is set below due to long processing of Pyth functions
+ }, 12000)
+})
+```
+{% endcode %}
+
+
+{% endstep %}
+{% endstepper %}
+
+### Frontend Walkthrough
+
+Wormhole is a decentralized attestation engine that leverages its network of guardians to trustlessly bridge information between the chains it supports. Wormhole has a simple, elegant, and pragmatic design that has enabled it to be the first real solution to ship to market and has received wide recognition and support from its member chains.
+
+Hermes is a web service that listens to the Wormhole Network for signed and attested price updates, and serves them via a convenient web [API](https://hermes.pyth.network/docs/#/rest/latest_price_updates). It provides Pyth's latest price update data format that is more cost-effective to verify and use on-chain. Hermes allows users to easily query for recent price updates via a REST API, or subscribe to a websocket for streaming updates. The Pyth Network also provides a Javascript [SDK](https://github.com/pyth-network/pyth-crosschain/tree/main/price_service/client/js) to connect to an instance of Hermes for fetching price updates.
+
+In your front-end application code, you can install and use the methods brought by Pyth Network's `hermes-client` Javascript SDK to fetch the latest price update, known as a VAA (Verified Action Approvals) message.
+
+```typescript
+import { HermesClient } from "@pythnetwork/hermes-client";
+import { Cl, Pc } from "@stacks/transactions"
+import { request } from "@stacks/connect"
+
+// --snip--
+
+async function handleFetchLatestVaa() {
+ const connection = new HermesClient("https://hermes.pyth.network", {});
+
+ const priceIds = [
+ "0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43",
+ ];
+
+ const priceUpdates = await connection.getLatestPriceUpdates(priceIds);
+ let latestVaaHex = `0x${priceUpdates.binary.data[0]}`;
+
+ return latestVaaHex;
+}
+
+// --snip--
+```
+
+The binary data returned from the Pyth SDK will already be in hexadecimal format. We'll then take this hexadecimal VAA message and pass it into our Clarity function as an argument.
+
+Using Stacks Connect of the stacks.js monorepo, we'll open up a `stx_callContract` request and invoke our public function while passing in the `latestVaaHex` as the function argument.
+
+```typescript
+// --snip--
+
+let latestVaaHex = await handleFetchLatestVaa();
+
+let postCond1 = Pc.principal("")
+ .willSendLte(1)
+ .ustx();
+
+const response = await request("stx_callContract", {
+ contract: `SP1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRCBGD7R.benjamin-club`,
+ functionName: "join-the-benjamin-club",
+ functionArgs: [Cl.bufferFromHex(latestVaaHex)],
+ network: "mainnet",
+ postConditions: [postCond1],
+ postConditionMode: "allow",
+});
+```
+
+If you noticed, we set a post-condition statement of our user transferring less than or equal to 1 uSTX, which is 0.000001 STX. This is because the `verify-and-update-price-feeds` of the `.pyth-oracle-v4` contract applies a fee for this.
+
+Setting a separate post-condition statement on the actual sbtc token transfer in our example will also be needed. Beforehand, you could invoke the `decode-price-feeds` function with the `latestVaaHex` to simply have the contained price data decoded and returned. From there you could pre-determine the estimated amount of sbtc tokens to be transferred and set in a separate post-condition.
+
+***
+
+### Additional Resources
+
+* \[[Hiro YT](https://youtu.be/eybqQVRh_hw?si=uwlpiZq36Ad7bBb0)] How To Pull Real-Time Price Data in Your Clarity Smart Contracts (Using Pyth)
+* \[[Pyth Docs](https://docs.pyth.network/price-feeds/core/use-real-time-data/pull-integration/stacks)] How to Use Real-Time Data in Stacks Applications
+* \[[Hiro Blog](https://www.hiro.so/blog/new-oracle-alert-pyth-integration-with-stacks)] New Oracle Alert: Pyth Integration With Stacks
diff --git a/docs/build/more-guides/sbtc/README.md b/docs/build/more-guides/sbtc/README.md
new file mode 100644
index 0000000000..10bf8e5309
--- /dev/null
+++ b/docs/build/more-guides/sbtc/README.md
@@ -0,0 +1,11 @@
+---
+description: Integrate sBTC in your app
+---
+
+# sBTC
+
+
+
+Integrating **sBTC** lets apps use real Bitcoin in smart contracts, unlocking programmable BTC without needing wrapped or custodial assets. It enables fast, low-fee interactions anchored to Bitcoin security while still benefiting from expressive on-chain logic on Stacks. For developers, sBTC dramatically expands what’s possible with Bitcoin—powering lending, trading, gaming, and new user experiences backed by the world’s hardest money.
+
+The guides in this section provide step-by-step instructions for interacting with sBTC, including developer guides on how to interact with sBTC and how to bridge BTC into sBTC.
diff --git a/docs/build/more-guides/sbtc/bridging-bitcoin/README.md b/docs/build/more-guides/sbtc/bridging-bitcoin/README.md
new file mode 100644
index 0000000000..5e62cd5af3
--- /dev/null
+++ b/docs/build/more-guides/sbtc/bridging-bitcoin/README.md
@@ -0,0 +1,26 @@
+---
+description: >-
+ A Javascript/Typescript package for integrating your own peg-in/out bridging
+ flow.
+---
+
+# How to Use the sBTC JS Library for Bridging
+
+Currently, the official [sBTC Bridge app](https://sbtc.stacks.co/) provides users the interface for pegging BTC into sBTC, and vice versa. Building your own sBTC bridging app would consist of working with the construction of bitcoin P2TR transactions, handling user UTXOs, broadcasting transactions, notifying the sBTC Signers' of incoming transactions, and etc. You could check out the complexity of that in the sBTC Bridge app's open-source repo [here](https://github.com/stacks-sbtc/sbtc-bridge). But thankfully there is a library for all of that.
+
+The [`sbtc`](https://www.npmjs.com/package/sbtc) npm library was built to abstract away the complexities of the bridging process of sBTC.
+
+{% hint style="info" %}
+Check out the `sbtc` reference [section](https://app.gitbook.com/s/GVj1Z9vMuEOMe7oH7Wnq/stacks.js/sbtc) for definitions, configurations, and more examples.
+{% endhint %}
+
+#### **Architecture**
+
+* **Bitcoin:** The original funds are sourced from Bitcoin. A depositor sends these funds to a group of signers, which manage a (rotating) multisignature address formatted for sBTC transactions.
+* **sBTC API (Emily):** This API is responsible for tracking deposits and notifying the signers about pending deposits.
+* **Stacks:** The network where sBTC is minted. Once the deposit is confirmed, the signers mint the corresponding amount of sBTC to the depositor's specified address on the Stacks network.
+
+#### This guide will provide a walkthrough of using the `sbtc` library for:
+
+* **Depositing**: pegging BTC into sBTC
+* **Withdrawing**: pegging sBTC into BTC
diff --git a/docs/build/more-guides/sbtc/bridging-bitcoin/btc-to-sbtc.md b/docs/build/more-guides/sbtc/bridging-bitcoin/btc-to-sbtc.md
new file mode 100644
index 0000000000..d99c8ca957
--- /dev/null
+++ b/docs/build/more-guides/sbtc/bridging-bitcoin/btc-to-sbtc.md
@@ -0,0 +1,291 @@
+# Depositing: Pegging BTC into sBTC
+
+This guides shows how you can integrate the deposit (peg-in) flow from your front-end app to allow users to peg BTC into sBTC on the Stacks network. For more information about sBTC and an explainer of its architecture, check out the general sBTC section [here](https://app.gitbook.com/s/H74xqoobupBWwBsVMJhK/sbtc) in the Learn category.
+
+### Breakdown of the deposit (peg-in) flow
+
+* **Create Deposit (Bitcoin) Transaction:**
+ * Structure a Bitcoin transaction to send funds to the group of signers.
+ * Use a specialized format that includes:
+ * Deposit Script: Identifies which _Stacks address_ the sBTC will be minted to and what the _maximum fee_ (in satoshis) the signers may take in exchange for minting.
+ * Reclaim Script: Allows the sender to reclaim their funds if the transaction is not processed by the signers.
+* **Sign and Broadcast the Transaction:**
+ * Sign the transaction with the sender's private key.
+ * Broadcast the transaction to the Bitcoin network (Bitcoin Regtest for Stacks Testnet).
+* **Notify the sBTC API (Emily):**
+ * Inform the API about the transaction by submitting its details. This step ensures that the signers are aware of the deposit and can track it.
+* **Processing by Signers:** (_no action required_)
+ * The signers retrieve and verify the deposit transaction from the Bitcoin blockchain.
+ * Once verified, the signers mint the equivalent amount of sBTC on the Stacks network.
+* **Receive sBTC (Stacks):** (_no action required_)
+ * The minted sBTC is sent to the depositor's designated Stacks address, completing the deposit process.
+ * sBTC is SIP-010 compatible and will show up in Stacks wallets and explorers.
+
+In this guide you'll touch on some of the steps above but its much simpler than you'd expect. Using the `sbtc` and `@stacks/connect` libraries, putting together the peg-in process from BTC into sBTC will simply involve the following steps:
+
+1. Building the sBTC deposit address
+2. Invoking the user's wallet to sign and broadcast the bitcoin transaction
+3. Notifying the sBTC signers
+4. Confirm user's sBTC balance
+
+{% hint style="info" %}
+This guide assumes you have a front-end bootstrapped with the Stacks Connect library for wallet interactions. Head to the guides for Stacks Connect before continuing with this guide.
+{% endhint %}
+
+{% stepper %}
+{% step %}
+#### Building the sBTC deposit address
+
+You're not directly sending bitcoin to the public sBTC Signers' [bitcoin address](https://mempool.space/address/bc1prcs82tvrz70jk8u79uekwdfjhd0qhs2mva6e526arycu7fu25zsqhyztuy), but rather sending to a custom P2TR address where both the user and sBTC Signers have control over. This custom P2TR address is special because it contains tapscripts that specify which parties are able to unlock the UTXOs via a script path spend.
+
+The construction of these tapscripts is what ultimately generates the custom P2TR address that the user will be sending their UTXOs to. Constructing tapscripts, or bitcoin scripts in general, are complex and tricky. The `sbtc` library provides useful methods for abstracting away the complexities of working with taproot related functions.
+
+```typescript
+import { buildSbtcDepositAddress, MAINNET, SbtcApiClientMainnet } from 'sbtc';
+
+// Initialize the sBTC API client based on network
+const client = new SbtcApiClientMainnet();
+
+// Build the deposit address with metadata
+const deposit = buildSbtcDepositAddress({
+ stacksAddress: 'SP14ZYP25NW67XZQWMCDQCGH9S178JT78QJYE6K37', // the address to send/mint the sBTC to
+ signersPublicKey: await client.fetchSignersPublicKey(), // the aggregated public key of the signers
+ reclaimLockTime: 700, // default value is 950
+ reclaimPublicKey: btcPubKey.value, // public key for reclaiming failed deposits
+ network: MAINNET,
+ maxSignerFee: 4000 // optional property, default value is 80,000 sats
+});
+
+// `deposit.address` is the deposit address (send funds here, aka the deposit address as an output)
+```
+
+{% hint style="info" %}
+The `maxSignerFee` refers to the fee in the bitcoin transaction sweeping funds into, or out of, the consolidated UTXO locked exclusively by sBTC Signers' aggregate address. Depending on network congestion, specify a custom fee your users would be willing to spend. The default value will be 80,000 sats. The user's responsibility of the actual fee spent is actually deducted from the amount of sBTC that will be minted.
+{% endhint %}
+
+The `buildSbtcDepositAddress` will return with a schema of:
+
+```
+deposit {
+ depositScript: string;
+ reclaimScript: string;
+ trOut: P2TROut;
+ address: string; // the custom P2TR address to deposit bitcoin to
+}
+```
+{% endstep %}
+
+{% step %}
+#### Sign and broadcast the bitcoin transaction
+
+Invoke the user's Stacks wallet to sign and broadcast the deposit bitcoin transaction.
+
+The string literal `sendTransfer` method will invoke the user's wallet to construct a bitcoin transaction. Be certain that the user's Stacks-supported wallet also supports `sendTransfer` as it is part of [WBIP005](https://wbips.netlify.app/wbips/WBIP005) for default Bitcoin methods.
+
+```typescript
+import { request } from '@stacks/connect';
+
+const result = await request('sendTransfer', {
+ recipients: [
+ {
+ address: deposit.address,
+ amount: 100_000,
+ },
+ ],
+})
+```
+{% endstep %}
+
+{% step %}
+#### Notify the sBTC Signers
+
+Immediately after the deposit bitcoin transaction is broadcasted, fetch the transaction hex and notify the sBTC Signers via the Emily API.
+
+{% hint style="warning" %}
+You'll want to wait until the transaction hits the bitcoin mempool before fetching the transaction hex. Usually this is within seconds.
+{% endhint %}
+
+```typescript
+// below should be delayed until txid appears in the bitcoin mempool
+const transaction = await client.fetchTxHex(result.txid);
+
+// 3. NOTIFY THE SIGNERS
+let response = await client.notifySbtc({ transaction, ...deposit });
+console.log('Notify response:', response);
+```
+
+The `notifySbtc` method will return with a schema of:
+
+{% code expandable="true" %}
+```
+export type SbtcApiNotifyResponse = {
+ bitcoinTxid: string;
+ bitcoinTxOutputIndex: number;
+ recipient: string;
+ amount: number;
+ lastUpdateHeight: number;
+ lastUpdateBlockHash: string;
+ status: string;
+ statusMessage: string;
+ parameters: {
+ maxFee: number;
+ lockTime: number;
+ };
+ reclaimScript: string;
+ depositScript: string;
+};
+```
+{% endcode %}
+{% endstep %}
+
+{% step %}
+#### Confirm user's sBTC balance
+
+The user should expect to receive their newly minted sBTC in about 20 minutes, or within 1 to 2 confirmations on the Bitcoin chain. Poll the user's specified `stacksAddress` to check if they've received sBTC and display that to the user on the front-end.
+
+The API client comes with a `fetchSbtcBalance` method that can help with this:
+
+```typescript
+const balance = await client.fetchSbtcBalance('SP3FGQ8Z7JY9BWYZ5WM53E0M9NK7WHJF0691NZ159');
+// 1000000n (in micro-sBTC)
+```
+
+You could also fetch the deposit data from the API client. This will return data pertaining to the 3 total transactions that make up the entire deposit (peg-in) flow:
+
+1. \[Bitcoin] Initial bitcoin deposit by the user ([example](https://mempool.space/tx/174bff280dff56d5c1d86d341ddee213d248f375c2552d2d333a59d82a59a35c))
+2. \[Bitcoin] Sweep bitcoin transaction by the Signers ([example](https://mempool.space/tx/15029c5cabbd759ae31f58d8a08b50f9e0d9181c128fa61c3bea9c48e8ac8ea7))
+3. \[Stacks] Mint sBTC by the Signers ([example](https://explorer.hiro.so/txid/0xe26c60bce407147c6f538805776039b1ed2710b903255a5726d46f4bbe97fc75?chain=mainnet))
+
+{% code expandable="true" %}
+```typescript
+let depositInfo = await client.fetchDeposit(txid) // txid of initial bitcoin deposit
+
+// example depositInfo result below
+{
+ "nextToken": null,
+ "deposits": [
+ {
+ "bitcoinTxid": "174bff280dff56d5c1d86d341ddee213d248f375c2552d2d333a59d82a59a35c",
+ "bitcoinTxOutputIndex": 0,
+ "recipient": "0516a3e1feb8787ea10053bcf8761534112f8057e2af",
+ "amount": 300000,
+ "lastUpdateHeight": 4512460,
+ "lastUpdateBlockHash": "297a564dcbc5a327ceac5674e194bde3218f68d55f40616fd748874e0fcdf838",
+ "status": "confirmed",
+ "statusMessage": "Included in block 297a564dcbc5a327ceac5674e194bde3218f68d55f40616fd748874e0fcdf838",
+ "parameters": {
+ "maxFee": 80000,
+ "lockTime": 950
+ },
+ "reclaimScript": "02b603b275203b992a2735a7af6da02cbdfcb723fe5e669765505903db59270b852d0f2d6fe3ac",
+ "depositScript": "1e00000000000138800516a3e1feb8787ea10053bcf8761534112f8057e2af7520d8c4344861fc7590fd812c24884a3bfd9374d8ba865a787ff53c9060020aa967ac",
+ "fulfillment": {
+ "BitcoinTxid": "15029c5cabbd759ae31f58d8a08b50f9e0d9181c128fa61c3bea9c48e8ac8ea7",
+ "BitcoinTxIndex": 0,
+ "StacksTxid": "e26c60bce407147c6f538805776039b1ed2710b903255a5726d46f4bbe97fc75",
+ "BitcoinBlockHash": "00000000000000000001aab771f33914381ad92b3f5cfedf729172f2afd9c65c",
+ "BitcoinBlockHeight": 921715,
+ "BtcFee": 235
+ }
+ }
+ ]
+}
+```
+{% endcode %}
+{% endstep %}
+{% endstepper %}
+
+And that's all to it. You've successfully allowed your app to handle incoming BTC to be pegged into sBTC onto the Stacks network.
+
+***
+
+### \[Additional Insights]
+
+### What scripts make up the custom P2TR bitcoin address?
+
+As mentioned above, you're not directly sending bitcoin to the public sBTC Signers' [bitcoin address](https://mempool.space/address/bc1prcs82tvrz70jk8u79uekwdfjhd0qhs2mva6e526arycu7fu25zsqhyztuy), but rather sending to a custom P2TR address where both the user and sBTC Signers have control over. Besides the default key path spend, this custom P2TR address also contains 2 sets of scripts:
+
+
+
+#### Deposit script
+
+The deposit script is used by the sBTC Signers to "sweep" the deposited UTXO into their aggregate bitcoin address used to hold the entire balance of deposited bitcoin. So in a way they are consolidating all UTXOs into one single UTXO.
+
+The construction of the deposit script:
+
+{% code expandable="true" %}
+```typescript
+export function buildSbtcDepositScript(opts: {
+ maxSignerFee: number;
+ stacksAddress: string;
+ signersPublicKey: string;
+}) {
+ const maxSignerFeeBytes = P.U64BE.encode(BigInt(opts.maxSignerFee));
+ const recipientBytes = stacksAddressBytes(opts.stacksAddress);
+ const signersPublicKeyBytes = hexToBytes(opts.signersPublicKey);
+
+ if (signersPublicKeyBytes.length !== 32) {
+ throw new Error('Signers public key must be 32 bytes (schnorr)');
+ }
+
+ return btc.Script.encode([
+ P.utils.concatBytes(maxSignerFeeBytes, recipientBytes),
+ 'DROP',
+ signersPublicKeyBytes,
+ 'CHECKSIG',
+ ]);
+}
+```
+{% endcode %}
+
+#### Reclaim script
+
+The reclaim script allows the initial depositor to reclaim their UTXOs.
+
+The construction of the reclaim script:
+
+{% code expandable="true" %}
+```typescript
+export function buildSbtcReclaimScript(opts: {
+ reclaimLockTime: number;
+ reclaimPublicKey: string;
+}) {
+ const reclaimLockTime =
+ opts.reclaimLockTime <= 16
+ ? opts.reclaimLockTime // number if can be encoded as a OP_
+ : btc.ScriptNum().encode(BigInt(opts.reclaimLockTime));
+ const publicKeyBytes = hexToBytes(opts.reclaimPublicKey);
+
+ if (publicKeyBytes.length !== 32) throw new Error('Public key must be 32 bytes (schnorr)');
+
+ return btc.Script.encode([
+ reclaimLockTime,
+ 'CHECKSEQUENCEVERIFY',
+ 'DROP',
+ publicKeyBytes,
+ 'CHECKSIG',
+ ]);
+}
+```
+{% endcode %}
+
+Behind the scenes, these two script construction methods are being abstracted away by `buildSbtcDepositAddress` which you've implemented on the front-end.
+
+### How are fees dealt with?
+
+**During deposits**
+
+The `maxSignerFee` refers to the fee in the bitcoin transaction sweeping funds into the consolidated UTXO locked exclusively by sBTC Signers' aggregate address. Depending on network congestion, specify a custom fee your users would be willing to spend. The default value will be 80,000 sats. The user's responsibility of the actual fee spent (for the sweep transaction) is actually deducted from the amount of sBTC that will be minted.
+
+**During withdrawals**
+
+The fees specified in `max-fee` of the function `initiate-withdrawal-request` of the [`.sbtc-withdrawal`](https://explorer.hiro.so/txid/SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-withdrawal?chain=mainnet) contract are referring to the fees paid of the bitcoin withdrawal transaction.
+
+#### How to estimate how much in fees one should spend?
+
+If you want to estimate how much one would expect to be charged in fees, you'd have to estimate the size of the transaction (vbytes) and the current network's fee rate. Below are some estimations you could use as a benchmark:
+
+**For deposits**: \~250 vbytes times the prevailing sats per vbyte fee rate\
+**For withdrawals**: \~170 vbtytes times the prevailing sats per vbyte rate
+
+And although many deposits and withdrawals can be combined, these values should be the maximum that a user will be charged regardless of how many other deposits or withdrawals are being serviced in a single transaction by the Signers. Meaning when more than one user's request is included in a sweep transaction on the L1, the users share the fees in proportion to their deposit or withdrawal request's actual weight on the L1.
diff --git a/docs/build/more-guides/sbtc/bridging-bitcoin/sbtc-to-btc.md b/docs/build/more-guides/sbtc/bridging-bitcoin/sbtc-to-btc.md
new file mode 100644
index 0000000000..badc946dc1
--- /dev/null
+++ b/docs/build/more-guides/sbtc/bridging-bitcoin/sbtc-to-btc.md
@@ -0,0 +1,208 @@
+# Withdrawing: Pegging sBTC into BTC
+
+This guides shows how you can integrate the withdrawal (peg-out) flow from your front-end app to allow users to peg sBTC back into BTC on the Bitcoin network. For more information about sBTC and an explainer of its architecture, check out the general sBTC section [here](https://app.gitbook.com/s/H74xqoobupBWwBsVMJhK/sbtc) in the Learn category.
+
+### Breakdown of the withdrawal (peg-in) flow
+
+* **Validate and deconstruct bitcoin address**
+ * Validate user's inputted bitcoin address, to be used to receive BTC, is a valid bitcoin address.
+ * Deconstruct the bitcoin address to identify its version type and hashbytes.
+* **Construct a Stacks contract call:**
+ * Determine amount to withdraw and a reasonable max fee.
+ * Construct a contract call to invoke `initiate-withdrawal-request` of `.sbtc-withdrawal` contract.
+ * Broadcast the transaction to the Stacks network.
+* **Processing by Signers:** (_no action required_)
+ * The signers retrieve and verify the withdrawal transaction from the Stacks network.
+ * Once verified, the signers burn the sBTC and sends the equivalent amount of BTC back to the user.
+* **Receive BTC (Bitcoin):** (_no action required_)
+ * The returned BTC is sent to the depositor's designated bitcoin address, completing the withdrawal process.
+
+{% hint style="info" %}
+At the moment, the `sbtc` library does not have any direct helper methods, but as you'll see in the guide, it's relatively straightforward to do it without any abstraction methods.
+{% endhint %}
+
+In this guide you'll touch on some of the steps above but its much less complex than the deposit flow. Putting together the peg-out process from sBTC into BTC will simply involve the following steps:
+
+1. Validating the withdrawal bitcoin address
+2. Contract call to `initiate-withdrawal-request`
+3. Confirm BTC withdrawal
+
+{% hint style="info" %}
+This guide assumes you have a front-end bootstrapped with the Stacks Connect library for wallet interactions. Head to the guides for Stacks Connect before continuing with this guide.
+{% endhint %}
+
+{% stepper %}
+{% step %}
+#### Validating the withdrawal bitcoin address
+
+Validating a Bitcoin address before using it in code is essential to prevent errors and potential financial losses from incorrect or malicious addresses. It ensures compliance with types like P2PKH, P2SH, or P2TR, and adherence to network protocols. Without proper validation, there's a higher risk of failed transactions and security vulnerabilities, jeopardizing user funds and application reliability.
+
+After validating, you'll want to deconstruct the bitcoin address to identify its version type and hashbytes. The version type is pertaining to the bitcoin address type and how they map to its corresponding Clarity value.
+
+We'll use the `getAddressInfo` method from the [`bitcoin-address-validation`](https://github.com/ruigomeseu/bitcoin-address-validation) library to help us deconstruct the receiving bitcoin address.
+
+import { AddressType, getAddressInfo } from "bitcoin-address-validation";
+import * as bitcoin from "bitcoinjs-lib";
+
+function deconstructBtcAdd(address: string) {
+ const typeMapping = {
+ [AddressType.p2pkh]: "0x00",
+ [AddressType.p2sh]: "0x01",
+ [AddressType.p2wpkh]: "0x04",
+ [AddressType.p2wsh]: "0x05",
+ [AddressType.p2tr]: "0x06",
+ };
+
+ const addressInfo = getAddressInfo(address);
+
+ const { bech32 } = addressInfo;
+ let hashbytes: Uint8Array;
+ if (bech32) {
+ hashbytes = bitcoin.address.fromBech32(address).data;
+ } else {
+ hashbytes = bitcoin.address.fromBase58Check(address).hash;
+ }
+
+ const type = typeMapping[addressInfo.type];
+ if (!type) {
+ throw new Error(`Unsupported address type: ${addressInfo.type}`);
+ }
+
+ return {
+ type ,
+ hash bytes,
+ };
+}
+
+
+In the next step, the returned `type` and `hashbytes` are to be passed in as a tuple param of a contract call. The constraints and meaning of the `type` and `hashbytes` param are summarized as:
+
+```
+;; version == 0x00 and (len hashbytes) == 20 => P2PKH
+;; version == 0x01 and (len hashbytes) == 20 => P2SH
+;; version == 0x02 and (len hashbytes) == 20 => P2SH-P2WPKH
+;; version == 0x03 and (len hashbytes) == 20 => P2SH-P2WSH
+;; version == 0x04 and (len hashbytes) == 20 => P2WPKH
+;; version == 0x05 and (len hashbytes) == 32 => P2WSH
+;; version == 0x06 and (len hashbytes) == 32 => P2TR
+```
+{% endstep %}
+
+{% step %}
+#### Contract call to `initiate-withdrawal-request`
+
+The function `initiate-withdrawal-request` of the [`.sbtc-withdrawal`](https://explorer.hiro.so/txid/SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-withdrawal?chain=mainnet) contract locks up `amount` + `max-fee` from the sender's account. When the withdrawal request is accepted, the signers will then send BTC `amount` of sats to the recipient and spend the fee `amount` to bitcoin miners (where fee less than or equal to max-fee). If actual fee is less than `max-fee`, then the difference will be minted back to the user when `accept-withdrawal-request` is invoked by the Signers.
+
+The network used, for the bitcoin address, is inherited from the network of the underlying transaction itself (basically, if on Stacks mainnet the Signers will send to mainnet Bitcoin addresses and similarly on Stacks testnet, to Bitcoin testnet addresses).
+
+import { request } from '@stacks/connect';
+import { Cl, Pc } from '@stacks/transactions';
+
+let { type, hashbytes } = deconstructBtcAdd(<btcAddress>)
+
+let amount = 100000
+let recipient = {
+ version: Cl.bufferFromHex(type),
+ hashbytes: Cl.buffer(hashbytes)
+}
+let maxFee = 3000
+
+let postCond_1 = Pc.principal(<stxAddress>)
+ .willSendEq(amount + maxFee)
+ .ft('SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token', 'sbtc-token')
+
+let result = await request('stx_callContract', {
+ contract: 'SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-withdrawal',
+ functionName: 'initiate-withdrawal-request',
+ functionArgs: [Cl.uint(amount), Cl.tuple(recipient), Cl.uint(maxFee)],
+ postConditions: [postCond_1],
+ postConditionMode: 'deny',
+ network: "mainnet",
+})
+
+console.log(result)
+// {
+// "transaction": "0000000001040049ff5845af0c7efefca31b764229c84e8968e8bc000000000000009f0000000000000bb800015772b7ea414879826e90da34f9030ad6f8b6fb3f7c07d766906d7d9f9a65752147961e3de57d8fcaa1dfd6d92e0d085af3491efdfe2ec78d9a403c258f5c092e0301000000000214f6decc7cfff2a413bd7cd4f53c25ad7fd1899acc0f736274632d7769746864726177616c1b696e6974696174652d7769746864726177616c2d726571756573740000000301000000000000000000000000000186a00c0000000209686173686279746573020000001457873a539bfb7c071f8cd91805068d546a4941950776657273696f6e0200000001010100000000000000000000000000000bb8",
+// "txid": "cd73c7c3023d4f271981d85cb1c29446a5513dcfc182963ee2d1cfee06b9a4ad"
+// }
+
+{% endstep %}
+
+{% step %}
+#### Confirm BTC withdrawal
+
+The Stacks contract call transaction will be confirmed by the Stacks network within seconds. But the actual BTC withdrawal confirmation is longer than the deposit confirmation. Usually around 6 Bitcoin block confirmations are needed.
+
+After confirming the Stacks transaction, confirm that the user has received the withdrawn BTC back into their designated bitcoin address by polling the Emily API endpoint below:
+
+```
+https://sbtc-emily.com/withdrawal/sender/
+```
+
+This will return the status of all withdrawals from the specified sender:
+
+{
+ "nextToken": null,
+ "withdrawals": [
+ {
+ "requestId": 748,
+ "stacksBlockHash": "e19bea7a651136ed5a156e69d5952e86a3792f78df2bb20c8c5ab2009fd5617e",
+ "stacksBlockHeight": 4461632,
+ "recipient": "0020a6abc068c9783dea16451549cebb174ee82618f9999b53334b2397e02c8a106f",
+ "sender": "SP14ZYP25NW67XZQWMCDQCGH9S178JT78QJYE6K37",
+ "amount": 110000,
+ "lastUpdateHeight": 4462339,
+ "lastUpdateBlockHash": "32b2834eb507ec9484ea1bbce97cb2dc241c8ab18bd443181aa5b0c178546bed",
+ "status": "confirmed",
+ "txid": "a355cd64374446e1d0de7096a7c1583bb4564fb6a997650bd9af26605805bfa0"
+ },
+ ]
+}
+
+
+So in total there are 2 on-chain transactions that make up the entire withdrawal (peg-out) flow:
+
+1. \[Stacks] Initial sBTC withdrawal request by the user ([example](https://explorer.hiro.so/txid/0x4f4000a0ca61ea10e31bc7950672f57612880b6de3a61463bb98e29ca6bb6491?chain=mainnet))
+2. \[Bitcoin] Returned BTC transaction by the Signers ([example](https://mempool.space/tx/4ec2396bebb79d11be6dae3ae133cb0501d05af4ff368425fe19740d050b74dc))
+{% endstep %}
+{% endstepper %}
+
+And that's all to it. You've successfully allowed your app to handle incoming sBTC to be pegged out back into BTC.
+
+***
+
+### \[Additional Insights]
+
+### What are the different bitcoin address types?
+
+Bitcoin addresses come in several types, each serving specific purposes and providing different functionalities. Each address type has evolved to enhance security, scalability, and functionality of Bitcoin transactions in response to the network's growing needs.
+
+Check out the dedicated Hiro blog post to learn more about the why and how different bitcoin addresses are constructed:
+
+{% embed url="https://www.hiro.so/blog/understanding-the-differences-between-bitcoin-address-formats-when-developing-your-app" %}
+
+### Why does the withdrawal (peg-out) take longer to provide a bitcoin txid from the Emily API?
+
+The current flow right now goes like this:
+
+1. The user creates a withdrawal request via a contract call on Stacks. In this example, let's say the withdrawal transaction is confirmed in a Stacks block anchored to a Bitcoin block at height N.
+2. The Signers and Emily get the event from the contract call above. Emily marks the withdrawal as pending.
+3. The Signers wait until that Bitcoin block is final enough, which is at Bitcoin block N+6. When that Bitcoin block arrives they create and broadcast a sweep transaction fulfilling the withdrawal request. Then the Signers tell Emily that they have accepted the withdrawal request.
+4. Usually the sweep transaction is included in the next block, so it's confirmed at block N+7.
+5. The Signers issue the contract call finalizing the withdrawal on Stacks, and Emily finds out about the transaction fulfilling the withdrawal.
+
+Here are some useful notes about the above process:\
+When the Signers tell Emily that the withdrawal has been accepted, they don't tell her about the bitcoin transaction that it's accepted in. This is intentional, because the final transaction fulfilling the withdrawal is not known until it is confirmed. It could also be the case that the Signers attempt to fulfill the withdrawal request but end up never fulfilling it. As in, the Signers could create a transaction fulfilling the withdrawal request, where they broadcast it to the Bitcoin network, but that transaction is never confirmed and never will be. Moreover, this situation is not too unlikely; it can happen when fees spike relative to the user's max fee. The current approach sidesteps all of that UX complexity and prudently informs Emily about the transaction ID after it is known to be confirmed. Moreover, some wallets can tell you if there is a payment made out to you by just examining the Bitcoin mempool.
+
+[^1]: ```
+ type AddressInfo = {
+ bech32: boolean;
+ network: Network;
+ address: string;
+ type: AddressType;
+ }
+ ```
+
+[^2]: type: string
+
+[^3]: type: Uint8Array
diff --git a/docs/build/more-guides/sbtc/sbtc-builder-quickstart.md b/docs/build/more-guides/sbtc/sbtc-builder-quickstart.md
new file mode 100644
index 0000000000..ea94fb42d3
--- /dev/null
+++ b/docs/build/more-guides/sbtc/sbtc-builder-quickstart.md
@@ -0,0 +1,158 @@
+# sBTC Builder Quickstart
+
+source: Hiro
+
+Get up and running with sBTC in 30 minutes or less. This guide covers the essentials for working with sBTC as a SIP-010 token in your smart contracts.
+
+### What is sBTC?
+
+sBTC is Bitcoin on Stacks. It's a SIP-010 fungible token that maintains a 1:1 peg with Bitcoin, enabling you to use Bitcoin in smart contracts and DeFi applications on the Stacks blockchain.
+
+Key points:
+
+* **1:1 Bitcoin peg**: 1 sBTC always equals 1 BTC
+* **SIP-010 token**: Works like any other fungible token on Stacks
+* **Programmable**: Use Bitcoin in smart contracts, DeFi protocols, and dApps
+
+### Quick Setup
+
+#### Prerequisites
+
+In order to get the most from this quickstart, you should familiarize yourself with Clarity, Clarinet, Stacks.js, and the Hiro Platform. These are the fundamental building blocks of building Stacks applications.
+
+* [Stacks Developer Quickstart](https://app.gitbook.com/o/hoh4mQXTl8NvI3cETroY/s/Zz9BLmTU9oydDpL3qiUh/) - For a quick holistic introduction to the Stacks development process, tools, and fundamentals
+* [Clarity Crash Course](../../get-started/clarity-crash-course.md) - For a quick introduction to Clarity
+* [Clarinet Docs](https://docs.hiro.so/tools/clarinet)
+* [Stacks.js Docs](https://docs.hiro.so/reference/stacks.js)
+
+Choose your preferred development environment:
+
+#### Hiro Platform (Recommended)
+
+The fastest way to start building with sBTC is using the Hiro Platform's hosted devnet. The Platform integrates with your GitHub account. You can either import an existing project from GitHub or start with a Platform template and have it synced with your GitHub account.
+
+After you create the project in the Platform, you can clone it locally and work with the Platform's cloud devnet by connecting your API key as described in the template's README files. This will allow you to work on your code locally but let Platform handle the complexities of actually running the devnet.
+
+{% stepper %}
+{% step %}
+#### Create an account
+
+Create an account at:\
+https://platform.hiro.so
+{% endstep %}
+
+{% step %}
+#### Create or import a project
+
+* Select a template or import your own project from GitHub. There are several templates available to use as a starting point. Some have only smart contracts and some are full-stack dapp templates. Starting with one of these ensures you are building with best practices.
+* Navigate to your project dashboard
+{% endstep %}
+
+{% step %}
+#### Start devnet
+
+* Click the "Devnet" tab
+* Click "Start Devnet"
+* Wait for status to show "Active"
+{% endstep %}
+
+{% step %}
+#### Connect your wallet
+
+* Your devnet wallets are automatically funded with STX and sBTC
+* Use the provided wallet addresses within the templates
+* The platform templates are automatically connected to Devnet, and there are instructions in the READMEs of the templates for how to connect your frontend to your Devnet instance
+{% endstep %}
+{% endstepper %}
+
+#### Local with Clarinet
+
+If you would prefer to have your devnet running locally instead of in the Platform cloud, you can run one yourself.
+
+{% stepper %}
+{% step %}
+#### Install Clarinet (version 3.x)
+
+```bash
+brew install clarinet
+```
+{% endstep %}
+
+{% step %}
+#### Create a new project
+
+```bash
+clarinet new my-sbtc-project
+cd my-sbtc-project
+```
+{% endstep %}
+
+{% step %}
+#### Add sBTC requirements
+
+```bash
+clarinet requirements add SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-deposit
+```
+
+This automatically includes the sBTC token contract in your Clarinet context so you can reference it within your contracts.
+{% endstep %}
+
+{% step %}
+#### Start devnet
+
+```bash
+clarinet devnet start
+```
+
+With either of these options, your Devnet wallets are automatically funded with sBTC. You just need to include the sBTC contract in your contract requirements as shown above.
+{% endstep %}
+{% endstepper %}
+
+### Working with sBTC in Smart Contracts
+
+sBTC follows the SIP-010 standard, making it easy to integrate into your contracts.
+
+The primary function you'll be using is the `transfer` function. That's because sBTC exists as a 1:1 Bitcoin peg via a SIP-010 token. Minting is handled by the protocol, the main function of writing smart contracts that use sBTC is to move it around, which means using the `transfer` function.
+
+Here's a very basic example of how to transfer sBTC within your contract.
+
+#### Basic Transfer Example
+
+Create a new contract that accepts sBTC payments. You can do this within the Clarinet project folder with `clarinet contract new sbtc-payment`.
+
+{% code title="contracts/sbtc-payment.clar" %}
+```clarity
+;; contracts/sbtc-payment.clar
+
+;; Define the sBTC token contract reference
+(define-constant sbtc-token 'SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token)
+
+;; Error codes
+(define-constant err-insufficient-balance (err u100))
+(define-constant err-transfer-failed (err u101))
+
+;; Accept sBTC payment
+(define-public (pay-with-sbtc (amount uint) (recipient principal))
+ (contract-call? sbtc-token transfer
+ amount
+ tx-sender
+ recipient
+ none))
+```
+{% endcode %}
+
+You can test out this contract by either using the UI within the Platform to call the functions directly if you have devnet running or by opening the console with `clarinet console`.
+
+Once you do that you'll see that your devnet accounts have automatically been funded with sBTC.
+
+
+
+Once you are ready to deploy to testnet, you can do so by editing your deployment plan as outlined in [this guide](https://docs.hiro.so/tools/clarinet/sbtc-integration).
+
+### Conclusion
+
+You can build pretty much anything you want using this simple foundation, as all of the complexity of sBTC is handled behind the scenes by the protocol.
+
+What's needed now is for builders to take this foundation and build interesting, useful things with it. sBTC unlocks a lot of additional functionality for Bitcoin that previously would have only been possible with either custodied solutions or slow, complex solutions with poor UX.
+
+If you are interested, you can read more about how sBTC works in the [sBTC Concept Guide](https://app.gitbook.com/s/H74xqoobupBWwBsVMJhK/sbtc).
diff --git a/docs/build/more-guides/verify-bitcoin-transactions-clarity/README.md b/docs/build/more-guides/verify-bitcoin-transactions-clarity/README.md
new file mode 100644
index 0000000000..2d4669c729
--- /dev/null
+++ b/docs/build/more-guides/verify-bitcoin-transactions-clarity/README.md
@@ -0,0 +1,589 @@
+---
+description: Trustlessly validate Bitcoin data on-chain.
+---
+
+# Verifying Bitcoin Transactions in Clarity
+
+
+
+{% hint style="info" %}
+The current version of the `clarity-bitcoin-lib` is version 7. Click [here](https://explorer.hiro.so/txid/0xe433b35e95acfd24595e601860b4240cfaacd689ae7e7938a80c5505f186516b) for the deployed mainnet contract.
+{% endhint %}
+
+## Intro
+
+One of the unique features of the Stack chain and the Clarity language is that it allows for using read-only functions to trustlessly validate on-chain Bitcoin activity from Clarity smart contracts. This enables developers to build applications that **react to real Bitcoin activity** — such as deposits, transfers, and proofs of inclusion — without relying on off-chain indexers or oracles. In this guide, you’ll learn how to verify Bitcoin transactions in Clarity and safely bridge Bitcoin state into on-chain logic.
+
+> _Knowledge of Bitcoin state: has knowledge of the full Bitcoin state; it can trustlessly read_\
+> _Bitcoin transactions and state changes and execute smart contracts triggered by Bitcoin_\
+> _transactions. The Bitcoin read functionality helps to keep the decentralized peg state_\
+> _consistent with BTC locked on Bitcoin L1, amongst other things. **- Stacks Whitepaper**_
+
+### tl;dr
+
+* We'll be using a popular smart contract `clarity-bitcoin-lib` to verify bitcoin transactions on-chain in Clarity.
+* Allows contracts to enforce logic based on Bitcoin events—deposits, withdrawals, lockups, or multisig activity.
+* Powers designs like wrapped assets, and deposits that mint or unlock value only after provable Bitcoin transactions.
+
+### Steps
+
+* Fetch bitcoin transaction metadata: block height and header, transaction hex, and the transaction's merkle proof of inclusion.
+* Pass in transaction metadata as arguments to `clarity-bitcoin-lib` contract's `was-tx-mined-compact` read-only function.
+* Returns `(ok )` if the proof checks out and the transaction is indeed mined in the specified Bitcoin block.
+
+### Key Tools To Use
+
+* [Clarity Bitcoin library](https://github.com/friedger/clarity-bitcoin): A Clarity library for parsing Bitcoin transactions and verifying Merkle proofs.
+* [mempool.space APIs](https://mempool.space/docs/api/rest): Bitcoin explorer APIs used to fetch bitcoin transaction metadata.
+* [Bitcoin Transaction Proof](https://github.com/kenrogers/bitcoin-tx-proof) \[optional]: A TypeScript library for generating Bitcoin transaction proofs, including witness data and merkle proofs.
+* [Clarity Bitcoin Client](https://github.com/BigMarketDao/clarity-bitcoin-client) \[optional]: Clarity Bitcoin Client is an open-source TypeScript library for interacting with the `clarity-bitcoin-lib` contract on Stacks.
+
+***
+
+## Complete Code
+
+If you want to jump straight to the full implementation, the complete working code used in this guide is shown below.
+
+{% tabs %}
+{% tab title="Main" %}
+The below consists of the main client side code of preparing the bitcoin transaction metadata and passing them into a contract call to the `clarity-bitcoin-lib` contract.
+
+{% code expandable="true" %}
+```typescript
+import {
+ fetchCallReadOnlyFunction,
+ bufferCV,
+ uintCV,
+ tupleCV,
+ listCV,
+ cvToString,
+} from "@stacks/transactions"
+import { hexToBytes } from "@stacks/common"
+import { getTxHex, getTxMerkleProof, getBlkHeader, removeWitnessData } from "./fetch-bitcoin-data.js"
+
+// Data of read-only function of below clarity-bitcoin-lib contract:
+const contractAddress = "SP2PABAF9FTAJYNFZH93XENAJ8FVY99RRM50D2JG9"
+const contractName = "clarity-bitcoin-lib-v7"
+const functionName = "was-tx-mined-compact"
+
+// Fetching btc tx metadata. You can replace this with any bitcoin transaction id.
+let txid = "fb88309b4041f76bea0c196633c768dca82bb0dd424cbfe19be38569007f92d9"
+
+// Fetching and returning non-witness tx hex
+let fullTxHex = await getTxHex(txid)
+let txHex = removeWitnessData(fullTxHex)
+let { block_height, merkle, pos } = await getTxMerkleProof(txid)
+let { blockHeader } = await getBlkHeader(block_height)
+
+let txIndex = pos
+let hashes = merkle.map(hash => bufferCV(hexToBytes(hash).reverse()))
+let treeDepth = merkle.length
+
+// Preparing arguments for clarity function call
+let functionArgs = [
+ // (height)
+ uintCV(block_height),
+ // (tx)
+ bufferCV(Buffer.from(txHex, "hex")),
+ // (header)
+ bufferCV(Buffer.from(blockHeader, "hex")),
+ // (proof)
+ tupleCV({
+ "tx-index": uintCV(txIndex),
+ hashes: listCV(hashes),
+ "tree-depth": uintCV(treeDepth)
+ })
+]
+
+// Calling clarity read-only function
+let result = await fetchCallReadOnlyFunction({
+ contractAddress,
+ contractName,
+ functionName,
+ functionArgs,
+ network: 'mainnet',
+ // this could be any principal address
+ senderAddress: 'SP1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRCBGD7R'
+})
+
+// Logging results
+console.log("Full tx hex: ", fullTxHex)
+console.log("Non-witness tx hex: ", txHex)
+console.log("Block height: ", block_height)
+console.log("Block header: ", blockHeader)
+console.log("Merkle proof hashes: ", merkle)
+console.log("Transaction index in block: ", txIndex)
+console.log("Merkle tree depth: ", treeDepth)
+console.log("Was the transaction mined (from clarity-bitcoin)? ")
+console.log(cvToString(result))
+```
+{% endcode %}
+{% endtab %}
+
+{% tab title="Helpers" %}
+Helper functions to fetch the bitcoin transaction metadata from an explorer's API.
+
+{% code title="fetch-bitcoin-data.js" expandable="true" %}
+```typescript
+import mempoolJS from "@mempool/mempool.js"
+import { Transaction } from "bitcoinjs-lib"
+
+// https://www.npmjs.com/package/@mempool/mempool.js
+const {
+ bitcoin: { transactions, blocks }
+} = mempoolJS({
+ hostname: "mempool.space"
+})
+
+export const getTxHex = async (txid: string) => {
+ // Using mempool.space's GET /api/tx/:txid/hex
+ const txHex = await transactions.getTxHex({ txid })
+
+ return txHex
+}
+
+export const getTxMerkleProof = async (txid: string) => {
+ // Using mempool.space's GET /api/tx/:txid/merkle-proof
+ const { block_height, merkle, pos } = await transactions.getTxMerkleProof({ txid })
+
+ return { block_height, merkle, pos }
+}
+
+export const getBlkHeader = async (height: number) => {
+ // Using mempool.space's GET /api/block-height/:height
+ let blockHash = await blocks.getBlockHeight({ height })
+
+ // Using mempool.space's GET /api/block/:hash/header
+ const blockHeader = await blocks.getBlockHeader({ hash: blockHash })
+
+ return { blockHash, blockHeader }
+}
+
+// Function to remove witness data from a Bitcoin transaction hex
+// `was-tx-mined-compact` requires non-witness transaction format
+export const removeWitnessData = (txHex: string) => {
+ const tx = Transaction.fromHex(txHex)
+
+ if (!tx.hasWitnesses()) {
+ return txHex
+ }
+
+ // Create a new empty transaction
+ const newTx = new Transaction()
+
+ // Copy version from original transaction
+ newTx.version = tx.version
+
+ // Copy inputs from original transaction
+ tx.ins.forEach(input => {
+ newTx.addInput(input.hash, input.index, input.sequence, input.script)
+ })
+
+ // Copy outputs from original transaction
+ tx.outs.forEach(output => {
+ newTx.addOutput(output.script, output.value)
+ })
+
+ // Copy locktime from original transaction
+ newTx.locktime = tx.locktime
+
+ return newTx.toHex()
+}
+```
+{% endcode %}
+{% endtab %}
+
+{% tab title="Clarity Contract Preview" %}
+This is a snippet of the contract function we invoke to verify a bitcoin transaction.
+
+{% code title="clarity-bitcoin-lib.clar" expandable="true" %}
+```clarity
+;; --snip--
+
+(define-read-only (was-tx-mined-compact
+ (height uint)
+ (tx (buff 4096))
+ (header (buff 80))
+ (proof {
+ tx-index: uint,
+ hashes: (list 14 (buff 32)),
+ tree-depth: uint,
+ })
+ )
+ (let ((block (unwrap! (parse-block-header header) (err ERR-BAD-HEADER))))
+ (was-tx-mined-internal height tx header (get merkle-root block) proof)
+ )
+)
+
+;; --snip--
+```
+{% endcode %}
+{% endtab %}
+{% endtabs %}
+
+***
+
+## Walkthrough
+
+{% stepper %}
+{% step %}
+### Fetch bitcoin transaction metadata
+
+Using mempool.space's APIs and with a bitcoin txid, fetch the required bitcoin transaction metadata needed for Clarity.
+
+* Fetches the transaction hex
+* Fetches the transaction merkle proof
+* Fetches the block header
+* Removes witness data from transaction hex
+
+{% code title="fetch-bitcoin-data.ts" expandable="true" %}
+```typescript
+import mempoolJS from "@mempool/mempool.js"
+import { Transaction } from "bitcoinjs-lib"
+
+// https://www.npmjs.com/package/@mempool/mempool.js
+const {
+ bitcoin: { transactions, blocks }
+} = mempoolJS({
+ hostname: "mempool.space"
+})
+
+export const getTxHex = async (txid: string) => {
+ // Using mempool.space's GET /api/tx/:txid/hex
+ const txHex = await transactions.getTxHex({ txid })
+
+ return txHex
+}
+
+export const getTxMerkleProof = async (txid: string) => {
+ // Using mempool.space's GET /api/tx/:txid/merkle-proof
+ const { block_height, merkle, pos } = await transactions.getTxMerkleProof({ txid })
+
+ return { block_height, merkle, pos }
+}
+
+export const getBlkHeader = async (height: number) => {
+ // Using mempool.space's GET /api/block-height/:height
+ let blockHash = await blocks.getBlockHeight({ height })
+
+ // Using mempool.space's GET /api/block/:hash/header
+ const blockHeader = await blocks.getBlockHeader({ hash: blockHash })
+
+ return { blockHash, blockHeader }
+}
+
+// Function to remove witness data from a Bitcoin transaction hex
+// `was-tx-mined-compact` requires non-witness transaction format
+export const removeWitnessData = (txHex: string) => {
+ const tx = Transaction.fromHex(txHex)
+
+ if (!tx.hasWitnesses()) {
+ return txHex
+ }
+
+ // Create a new empty transaction
+ const newTx = new Transaction()
+
+ // Copy version from original transaction
+ newTx.version = tx.version
+
+ // Copy inputs from original transaction
+ tx.ins.forEach(input => {
+ newTx.addInput(input.hash, input.index, input.sequence, input.script)
+ })
+
+ // Copy outputs from original transaction
+ tx.outs.forEach(output => {
+ newTx.addOutput(output.script, output.value)
+ })
+
+ // Copy locktime from original transaction
+ newTx.locktime = tx.locktime
+
+ return newTx.toHex()
+}
+```
+{% endcode %}
+
+
+
+Are there libraries to help with fetching of the bitcoin transaction metadata?
+
+There sure are. Here are two community-built libraries that can abstract away some of the complexities with gathering the bitcoin transaction metadata.
+
+* [**Bitcoin Transaction Proof**](https://github.com/kenrogers/bitcoin-tx-proof) - A TypeScript library for generating Bitcoin transaction proofs, including witness data and merkle proofs.
+* [**Clarity Bitcoin Client**](https://github.com/BigMarketDao/clarity-bitcoin-client) - A TypeScript library for interacting with the clarity-bitcoin-lib contract on Stacks.
+
+
+
+
+
+Don't have a bitcoin transaction id?
+
+Learn how to create and broadcast a bitcoin transaction on the frontend [here](creating-btc-tx.md).
+
+
+{% endstep %}
+
+{% step %}
+### Prepare metadata as Clarity arguments
+
+Let's circle back to the `was-tx-mined-compact` function of the `clarity-bitcoin-lib` contract for a second and analyze the order/type of parameters.
+
+You can see that it intakes the parameters with a certain typing and order:
+
+* `(height uint)` the block height you are looking to verify the transaction within
+* `(tx (buff 1024))` the raw transaction hex of the transaction you are looking to verify
+* `(header (buff 80))` the block header of the block
+* `(proof { tx-index: uint, hashes: (list 14 (buff 32)), tree-depth: uint})` a merkle proof formatted as a Clarity tuple
+
+In short, the `was-tx-mined-compact` function takes the block height, the transaction hex, the block header, and a merkle proof, and determines that:
+
+* the block header corresponds to the block that was mined at the given Bitcoin height
+* the transaction's merkle proof links it to the block header's merkle root.
+
+{% hint style="info" %}
+The current version of the `clarity-bitcoin-lib` is version 7. Click [here](https://explorer.hiro.so/txid/0xe433b35e95acfd24595e601860b4240cfaacd689ae7e7938a80c5505f186516b) for the deployed mainnet contract.
+{% endhint %}
+
+{% code title="clarity-bitcoin-lib.clar" %}
+```clarity
+;; --snip--
+
+(define-read-only (was-tx-mined-compact
+ (height uint)
+ (tx (buff 4096))
+ (header (buff 80))
+ (proof {
+ tx-index: uint,
+ hashes: (list 14 (buff 32)),
+ tree-depth: uint,
+ })
+ )
+ (let ((block (unwrap! (parse-block-header header) (err ERR-BAD-HEADER))))
+ (was-tx-mined-internal height tx header (get merkle-root block) proof)
+ )
+)
+
+;; --snip--
+```
+{% endcode %}
+
+So after you've fetched the bitcoin tx metadata and have removed the witness data from the original transaction hex, let's go ahead and prepare the metadata into it's Clarity parameter values.
+
+{% code expandable="true" %}
+```typescript
+import {
+ fetchCallReadOnlyFunction,
+ bufferCV,
+ uintCV,
+ tupleCV,
+ listCV,
+ cvToString,
+} from "@stacks/transactions"
+import { hexToBytes } from "@stacks/common"
+import { getTxHex, getTxMerkleProof, getBlkHeader, removeWitnessData } from "./fetch-bitcoin-data.js"
+
+// Data of read-only function of below clarity-bitcoin-lib contract:
+const contractAddress = "SP2PABAF9FTAJYNFZH93XENAJ8FVY99RRM50D2JG9"
+const contractName = "clarity-bitcoin-lib-v7"
+const functionName = "was-tx-mined-compact"
+
+// Fetching btc tx metadata. You can replace this with any bitcoin transaction id.
+let txid = "fb88309b4041f76bea0c196633c768dca82bb0dd424cbfe19be38569007f92d9"
+
+// Fetching and returning non-witness tx hex
+let fullTxHex = await getTxHex(txid)
+let txHex = removeWitnessData(fullTxHex)
+let { block_height, merkle, pos } = await getTxMerkleProof(txid)
+let { blockHeader } = await getBlkHeader(block_height)
+
+let txIndex = pos
+let hashes = merkle.map(hash => bufferCV(hexToBytes(hash).reverse()))
+let treeDepth = merkle.length
+
+// Preparing arguments for clarity function call
+let functionArgs = [
+ // (height)
+ uintCV(block_height),
+ // (tx)
+ bufferCV(Buffer.from(txHex, "hex")),
+ // (header)
+ bufferCV(Buffer.from(blockHeader, "hex")),
+ // (proof)
+ tupleCV({
+ "tx-index": uintCV(txIndex),
+ hashes: listCV(hashes),
+ "tree-depth": uintCV(treeDepth)
+ })
+]
+```
+{% endcode %}
+
+
+
+What is the purpose of the merkle proof?
+
+A Merkle proof is a mathematically efficient and compact manner to prove that a transaction is included in a block in the Bitcoin blockchain.
+
+#### How transactions are combined into the Merkle root
+
+Transactions in a block are hashed and paired, then the hashes of the pairs are hashed and paired, and so on until a single hash remains — this is called the Merkle root.
+
+#### Merkle root in the block header
+
+The Merkle root is included in the block header. By providing the hashes that lead from a transaction's hash up to the Merkle root, along with the block header, one can prove that the transaction is included in that block.
+
+#### Merkle proof (Merkle path)
+
+The hashes that connect a transaction to the Merkle root are called the Merkle proof or Merkle path. By providing the Merkle proof along with the transaction hash and block header, anyone can verify that the transaction is part of that block.
+
+#### Efficient decentralized verification
+
+This allows for efficient decentralized verification of transactions without having to download the entire blockchain. One only needs the transaction hash, Merkle proof, and block header to verify.
+
+
+
+
+
+Why are we removing the witness data from the original tx hex?
+
+The `clarity-bitcoin-lib` contract's `was-tx-mined-compact` function only accepts a non-witness transaction hex. Usually only legacy bitcoin transactions are deemed as non-witness transactions. The contract also has a dedicated function for bitcoin transactions with witness data called `was-segwit-tx-mined-compact` .
+
+But you could still verify any transaction type in `was-tx-mined-compact` by simply removing the witness data from the original tx hex.
+
+
+{% endstep %}
+
+{% step %}
+### Invoke \`was-tx-mined-compact\` function
+
+Construct a read-only function call, pass in the contract call options, and await the results. If the bitcoin transaction in question is indeed mined in an existing Bitcoin block, the contract will return a response that looks like:
+
+`(ok 0xfb88309b4041f76bea0c196633c768dca82bb0dd424cbfe19be38569007f92d9)`
+
+You'll see your exact bitcoin txid returned wrapped in an `ok` response.
+
+{% code expandable="true" %}
+```typescript
+// --snip--
+
+// Calling clarity read-only function
+let result = await fetchCallReadOnlyFunction({
+ contractAddress,
+ contractName,
+ functionName,
+ functionArgs,
+ network: 'mainnet',
+ // this could be any principal address
+ senderAddress: 'SP1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRCBGD7R'
+})
+
+// Logging results
+console.log("Full tx hex: ", fullTxHex)
+console.log("Non-witness tx hex: ", txHex)
+console.log("Block height: ", block_height)
+console.log("Block header: ", blockHeader)
+console.log("Merkle proof hashes: ", merkle)
+console.log("Transaction index in block: ", txIndex)
+console.log("Merkle tree depth: ", treeDepth)
+console.log("Was the transaction mined (from clarity-bitcoin)? ")
+console.log(cvToString(result))
+```
+{% endcode %}
+{% endstep %}
+{% endstepper %}
+
+That's the end-to-end flow: fetch the bitcoin transaction metadata and its merkle proof, prepare and assemble the data for the contract's read-only function call, and finally call the Clarity contract function that verifies inclusion in a Bitcoin block.
+
+***
+
+## Example Usage
+
+Here are some example projects/contracts that would leverage the `clarity-bitcoin-lib` contract in their own code.
+
+#### Square Runes
+
+A Clarity implementation for parsing Bitcoin Runes protocol data. Check out the project repo [here](https://github.com/Rapha-btc/square-runes).
+
+;; --snip--
+
+;; Main entry point: Process a Runes deposit with full merkle proof verification
+(define-public (process-deposit
+ (height uint)
+ (wtx {
+ version: (buff 4),
+ ins: (list 50 { outpoint: { hash: (buff 32), index: (buff 4) }, scriptSig: (buff 1376), sequence: (buff 4) }),
+ outs: (list 50 { value: (buff 8), scriptPubKey: (buff 1376) }),
+ locktime: (buff 4),
+ })
+ (witness-data (buff 1650))
+ (header (buff 80))
+ (tx-index uint)
+ (tree-depth uint)
+ (wproof (list 14 (buff 32)))
+ (witness-merkle-root (buff 32))
+ (witness-reserved-value (buff 32))
+ (ctx (buff 4096))
+ (cproof (list 14 (buff 32)))
+ (mom-token <sr-trait>)
+ )
+ (let (
+ ;; Build full tx buffer
+ (tx-buff (contract-call?
+ 'SP2PABAF9FTAJYNFZH93XENAJ8FVY99RRM50D2JG9.bitcoin-helper-wtx-v2
+ concat-wtx wtx witness-data
+ ))
+ )
+ ;; Verify tx was mined on Bitcoin
+ (match (contract-call?
+ 'SP2PABAF9FTAJYNFZH93XENAJ8FVY99RRM50D2JG9.clarity-bitcoin-lib-v7
+ was-segwit-tx-mined-compact height tx-buff header tx-index tree-depth
+ wproof witness-merkle-root witness-reserved-value ctx cproof
+ )
+ btc-tx-id (process-verified-deposit btc-tx-id tx-buff height mom-token)
+ error (err (* error u1000)) ;; ERR-TX-NOT-MINED
+ )
+ )
+)
+
+;; --snip--
+
+
+#### Bitcoin Transaction Enabled NFT
+
+This contract example implements a basic NFT collection that is mintable only upon a user's bitcoin transaction. You can find this template available in the [Hiro Platform](https://platform.hiro.so/).
+
+;; --snip--
+
+;; Mint a new NFT if a specific bitcoin transaction has been mined.
+(define-public (mint (recipient principal) (height uint) (tx (buff 1024)) (header (buff 80)) (proof { tx-index: uint, hashes: (list 14 (buff 32)), tree-depth: uint}))
+ (let
+ (
+ ;; Create the new token ID by incrementing the last minted ID.
+ (token-id (+ (var-get last-token-id) u1))
+ ;; Calls external contract function to confirm mined status on the supplied bitcoin transaction data. Will return (ok txid)
+ (tx-was-mined (contract-call? 'SP2PABAF9FTAJYNFZH93XENAJ8FVY99RRM50D2JG9.clarity-bitcoin-lib-v7 was-tx-mined-compact height tx header proof))
+ )
+ ;; Only the contract owner can mint.
+ (asserts! (is-eq tx-sender contract-owner) err-owner-only)
+ ;; Confirms if supplied bitcoin transaction data has been mined or not.
+ (asserts! (is-ok tx-was-mined) err-tx-not-mined)
+ ;; Mint the NFT and send it to the given recipient.
+ (try! (nft-mint? Your-NFT-Name token-id recipient))
+ ;; Update the last minted token ID.
+ (var-set last-token-id token-id)
+ ;; Return a success status and the newly minted NFT ID.
+ (ok token-id)
+ )
+)
+
+;; --snip--
+
+
+***
+
+## Additional Resources
+
+* \[[Hiro YT](https://youtu.be/mPba9vJEDlc?si=wTCqweRWWFP-jyCJ)] Bitcoin Enabled NFT - Stacks NFTs Minted By Bitcoin Transactions
+* \[[Hiro Blog](https://www.hiro.so/blog/how-to-use-bitcoin-data-in-clarity-unit-tests)] How to Use Bitcoin Data in Clarity Unit Tests
diff --git a/docs/build/more-guides/verify-bitcoin-transactions-clarity/creating-btc-tx.md b/docs/build/more-guides/verify-bitcoin-transactions-clarity/creating-btc-tx.md
new file mode 100644
index 0000000000..dd91f86d07
--- /dev/null
+++ b/docs/build/more-guides/verify-bitcoin-transactions-clarity/creating-btc-tx.md
@@ -0,0 +1,38 @@
+# Creating a Bitcoin Transaction
+
+For usage with the `clarity-bitcoin-lib` contract or if you just want to learn how to invoke a bitcoin transaction from your wallet on the front end, check out this guide.
+
+Using Stacks Connect and with a Stacks-supported wallet, you can initiate a simple Bitcoin transaction from a frontend app in a few lines of code. With this Bitcoin transaction, you can then use to verify it's inclusion in a Bitcoin block through Clarity.
+
+{% hint style="info" %}
+Check out the [Stacks Connect](/broken/pages/JLRpUuDHPMxXaInZ9Vll) guides for more info on setup and wallet connection.
+{% endhint %}
+
+{% stepper %}
+{% step %}
+#### Initiate a Bitcoin transaction
+
+Use the `request("sendTransfer", ...)` method to initiate a bitcoin transaction. Provide the recipient address and the amount in satoshis.
+
+```typescript
+import { request } from '@stacks/connect';
+
+const result = await request('sendTransfer', {
+ recipients: [
+ {
+ address: "",
+ amount: 100_000,
+ },
+ ],
+ })
+
+let txid = result.txid;
+```
+{% endstep %}
+
+{% step %}
+#### Cache the \`txid\`
+
+As you'll see in the next section, in order to verify a transaction was mined in Clarity, you'll use the returned `txid` to fetch its transaction metadata. The transaction metadata can be fetched from a Bitcoin explorer or from some custom helper libraries built by the community. So it's important to cache or store the `txid` for your app.
+{% endstep %}
+{% endstepper %}
diff --git a/docs/build/more-guides/verify-bitcoin-transactions-clarity/parsing-a-bitcoin-transaction.md b/docs/build/more-guides/verify-bitcoin-transactions-clarity/parsing-a-bitcoin-transaction.md
new file mode 100644
index 0000000000..3c0311b120
--- /dev/null
+++ b/docs/build/more-guides/verify-bitcoin-transactions-clarity/parsing-a-bitcoin-transaction.md
@@ -0,0 +1,166 @@
+# Parsing a Bitcoin Transaction
+
+### Intro
+
+While we can verify that a transaction was mined using the `clarity-bitcoin-lib` contract library, we can also parse a Bitcoin transaction using Clarity directly.
+
+If you aren't familiar with how Bitcoin transactions are encoded in raw form, take a quick look at that. The tl;dr is that all of the data from a Bitcoin transaction is encoded in hexadecimal form in a string of bytes; we can slice out pieces of that hex value to pull out all of our transaction data components.
+
+The process to do this is relatively complex, but the `clarity-bitcoin-lib` provides a function called `parse-tx` or `parse-wtx` (for witness transactions) that makes this simple. All we need to do is pass in a raw transaction hex and we get back the data of the transaction, including inputs and outputs.
+
+{% hint style="info" %}
+The current version of the `clarity-bitcoin-lib` is version 7. Click [here](https://explorer.hiro.so/txid/0xe433b35e95acfd24595e601860b4240cfaacd689ae7e7938a80c5505f186516b) for the deployed mainnet contract.
+{% endhint %}
+
+The `parse-tx` function of the `clarity-bitcoin-lib` contract looks like this:
+
+{% code title="clarity-bitcoin-lib" %}
+```clarity
+;; --snip--
+
+(define-read-only (parse-tx (tx (buff 4096)))
+ (let (
+ (ctx {
+ txbuff: tx,
+ index: u0,
+ })
+ (parsed-version (try! (read-uint32 ctx)))
+ (parsed-txins (try! (read-txins (get ctx parsed-version))))
+ (parsed-txouts (try! (read-txouts (get ctx parsed-txins))))
+ (parsed-locktime (try! (read-uint32 (get ctx parsed-txouts))))
+ )
+ ;; check if it is a non-segwit transaction?
+ ;; at least check what happens
+ (asserts! (is-eq (len tx) (get index (get ctx parsed-locktime)))
+ (err ERR-LEFTOVER-DATA)
+ )
+ (ok {
+ version: (get uint32 parsed-version),
+ ins: (get txins parsed-txins),
+ outs: (get txouts parsed-txouts),
+ locktime: (get uint32 parsed-locktime),
+ })
+ )
+)
+```
+{% endcode %}
+
+Where `txRaw` is a string containing the raw transaction hex. Passing that buffer into `parse-tx` returns the parsed transaction object with version, inputs (ins), outputs (outs), and locktime. You can then extract whatever fields you need from that returned data.
+
+***
+
+### Steps
+
+{% stepper %}
+{% step %}
+#### Get the raw transaction hex
+
+Obtain the raw transaction hex from a Bitcoin explorer API. This is a single hex string representing the entire transaction.
+
+Example raw bitcoin transaction hex:
+
+`0200000000010196277c04c986c1ad78c909287fd12dba2924324699a0232e0533f46a6a3916bb0100000000ffffffff026400000000000000160014274ae586ad2035efb4c25049c155f98310d7e106ca16440000000000160014599bcef6387256c6b019030c421b4a4d382fe2600247304402204d94a1e4047ca38a450177ccb6f88585ca147f1939df343d8ac5d962c5f35bb302206f7fa42c21c47ebccdc460393d35c5dfd3b6f0a26cf10fac23d3e6fab71835c20121020cb972a66e3fb1cdcc9efcad060b4457ebec534942700d4af1c0d82a33aa13f100000000`
+
+{% hint style="info" %}
+You can paste this into a raw transaction decoder like this one to inspect the decoded fields: [https://live.blockcypher.com/btc/decodetx/](https://live.blockcypher.com/btc/decodetx/)
+{% endhint %}
+{% endstep %}
+
+{% step %}
+#### Pass the transaction hex into Clarity-Bitcoin's parser
+
+Convert the hex string to a Clarity buffer and pass it to the `parse-tx` function (via your stack.js read-only function call). In stacks.js:
+
+If using stacks.js, pass the raw hex to your Clarity function as a Clarity typed buffer:
+
+import {
+ fetchCallReadOnlyFunction,
+ bufferCV,
+} from "@stacks/transactions"
+import { hexToBytes } from "@stacks/common"
+
+let txRaw = '<raw-transaction-hex>'
+
+// Data of read-only function of below clarity-bitcoin-lib contract:
+const contractAddress = "SP2PABAF9FTAJYNFZH93XENAJ8FVY99RRM50D2JG9"
+const contractName = "clarity-bitcoin-lib-v7"
+const functionName = "parse-tx"
+
+// Calling clarity read-only function
+let result = await fetchCallReadOnlyFunction({
+ contractAddress,
+ contractName,
+ functionName,
+ functionArgs: [bufferCV(Buffer.from(txRaw, "hex"))],
+ network: 'mainnet',
+ // this could be any principal address
+ senderAddress: 'SP1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRCBGD7R'
+})
+
+{% endstep %}
+
+{% step %}
+#### Examine and use the parsed result
+
+`parse-tx` returns an object containing:
+
+* version
+* ins (transaction inputs)
+* outs (transaction outputs)
+* locktime
+
+Extract whatever fields you need from that returned object.
+{% endstep %}
+{% endstepper %}
+
+***
+
+### Example Usage
+
+#### Square Runes
+
+A Clarity implementation for parsing Bitcoin Runes protocol data, allowing Stacks smart contracts to understand and react to Runes transactions on the Bitcoin chain.
+
+Check out the project repo [here](https://github.com/Rapha-btc/square-runes).
+
+;; --snip--
+
+;; ============================================
+;; PARSING HELPERS (using runes-decoder)
+;; ============================================
+
+;; Parse OP_RETURN from tx buffer using the runes-decoder library
+(define-read-only (parse-deposit-opreturn (tx-buff (buff 4096)))
+ (let (
+ (output0 (unwrap! (get-output-at-index tx-buff u0) (err u500)))
+ (script (get scriptPubKey output0))
+ )
+ ;; decode-any-runestone is more generic - handles Tag 0, 11, 22
+ (contract-call? .runes-decoder decode-any-runestone script)
+ )
+)
+
+;; Get output at specific index from parsed tx
+;; is this different for legacy Rafa?
+(define-read-only (get-output-at-index (tx (buff 4096)) (index uint))
+ (let (
+ (parsed-tx (contract-call?
+ 'SP2PABAF9FTAJYNFZH93XENAJ8FVY99RRM50D2JG9.clarity-bitcoin-lib-v7
+ parse-wtx tx false
+ ))
+ )
+ (match parsed-tx
+ result (let (
+ (outs (get outs result))
+ (out (unwrap! (element-at? outs index) (err u502)))
+ )
+ (ok {
+ scriptPubKey: (get scriptPubKey out),
+ value: (get value out)
+ })
+ )
+ error (err u503) ;; missing
+ )
+ )
+)
+
diff --git a/docs/build/post-conditions/implementation.md b/docs/build/post-conditions/implementation.md
new file mode 100644
index 0000000000..6c157826dc
--- /dev/null
+++ b/docs/build/post-conditions/implementation.md
@@ -0,0 +1,228 @@
+---
+description: Learn how to add post-conditions to protect your Stacks transactions.
+---
+
+# Implementing Post-Conditions
+
+Post-conditions are a powerful security feature in Stacks that protect users from unexpected transaction outcomes. This tutorial will walk you through implementing post-conditions in your applications to ensure transactions behave exactly as users expect.
+
+## What you'll learn
+
+* Construct post-conditions using the `Pc` helper API
+* Add post-conditions to different transaction types
+* Configure post-condition modes for transaction security
+* Implement post-conditions for STX, fungible tokens, and NFTs
+* Handle semi-fungible tokens (SFTs) with post-conditions
+
+## Prerequisites
+
+* Basic understanding of Stacks transactions
+* Stacks.js library installed (`npm install @stacks/transactions`)
+* A development environment set up for Stacks
+
+## Constructing post-conditions
+
+The Pc helper in Stacks.js provides a fluent, BDD-inspired API for constructing post-conditions. Start with `Pc.principal()` to specify which address will be verified, then chain methods to define the condition.
+
+```ts
+import { Pc } from '@stacks/transactions';
+
+// Basic structure of a post-condition
+const postCondition = Pc
+ .principal('STB44HYPYAT2BB2QE513NSP81HTMYWBJP02HPGK6')
+ .willSendEq(1000)
+ .ustx();
+```
+
+The Pc helper uses method chaining for intuitive condition building. Your IDE will provide auto-completion for available methods at each step.
+
+## Available transfer methods
+
+Post-conditions support different comparison operators and asset types. Choose the appropriate method based on your security requirements.
+
+### STX and fungible token methods
+
+```ts
+// Exact amount
+Pc.principal(address).willSendEq(1000).ustx();
+
+// Greater than or equal
+Pc.principal(address).willSendGte(500).ustx();
+
+// Less than
+Pc.principal(address).willSendLt(2000).ustx();
+```
+
+Comparison methods available:
+
+* `.willSendEq(amount)` - Exactly equal to amount
+* `.willSendGte(amount)` - Greater than or equal to amount
+* `.willSendGt(amount)` - Greater than amount
+* `.willSendLte(amount)` - Less than or equal to amount
+* `.willSendLt(amount)` - Less than amount
+
+### Asset type methods
+
+```ts
+// STX transfers
+.ustx()
+
+// Fungible token transfers
+.ft(contractAddress, tokenName)
+
+// NFT transfers
+.nft(assetIdentifier, tokenId)
+```
+
+### NFT-specific methods
+
+```ts
+// Ensure NFT is sent
+Pc.principal(address).willSendAsset().nft(...);
+
+// Ensure NFT is NOT sent
+Pc.principal(address).willNotSendAsset().nft(...);
+```
+
+## Setting the post-condition mode
+
+The post-condition mode determines how the Stacks blockchain handles asset transfers not explicitly covered by your post-conditions. This is a critical security setting.
+
+```ts
+import { PostConditionMode, makeContractCall } from '@stacks/transactions';
+
+const tx = await makeContractCall({
+ // ... other transaction properties
+ postConditionMode: PostConditionMode.Deny, // Recommended default
+ postConditions: [
+ // your post-conditions here
+ ],
+});
+```
+
+Mode options:
+
+* PostConditionMode.Deny (default): Transaction fails if any unspecified transfers occur
+* PostConditionMode.Allow: Transaction allows transfers beyond specified post-conditions
+
+## Common implementation patterns
+
+### STX transfer post-conditions
+
+Protect STX transfers by specifying exact amounts or ranges.
+
+```ts
+import { Pc, makeSTXTokenTransfer } from '@stacks/transactions';
+
+// Exact amount post-condition
+const exactAmountCondition = Pc
+ .principal('STB44HYPYAT2BB2QE513NSP81HTMYWBJP02HPGK6')
+ .willSendEq(1000)
+ .ustx();
+
+// Use in a transaction
+const tx = await makeSTXTokenTransfer({
+ recipient: 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM',
+ amount: 1000,
+ postConditions: [exactAmountCondition],
+ postConditionMode: PostConditionMode.Deny,
+ // ... other properties
+});
+```
+
+### Fungible token post-conditions
+
+Ensure fungible tokens are transferred as expected in contract calls.
+
+```ts
+import { Pc, makeContractCall } from '@stacks/transactions';
+
+// Minimum amount condition
+const ftCondition = Pc
+ .principal('STB44HYPYAT2BB2QE513NSP81HTMYWBJP02HPGK6')
+ .willSendGte(500)
+ .ft('STB44HYPYAT2BB2QE513NSP81HTMYWBJP02HPGK6.token-ft', 'token');
+
+// Use in a contract call
+const tx = await makeContractCall({
+ contractAddress: 'STB44HYPYAT2BB2QE513NSP81HTMYWBJP02HPGK6',
+ contractName: 'token-transfer',
+ functionName: 'transfer',
+ functionArgs: [
+ // ... function arguments
+ ],
+ postConditions: [ftCondition],
+ // ... other properties
+});
+```
+
+### NFT transfer post-conditions
+
+Control NFT ownership changes with specific post-conditions.
+
+```ts
+import { Pc, Cl } from '@stacks/transactions';
+
+// Ensure NFT is sent
+const sendNftCondition = Pc
+ .principal('STB44HYPYAT2BB2QE513NSP81HTMYWBJP02HPGK6')
+ .willSendAsset()
+ .nft('STB44HYPYAT2BB2QE513NSP81HTMYWBJP02HPGK6.nft-contract::nft-name', Cl.uint(1));
+
+// Ensure NFT is NOT sent (protection against unwanted transfers)
+const keepNftCondition = Pc
+ .principal('STB44HYPYAT2BB2QE513NSP81HTMYWBJP02HPGK6')
+ .willNotSendAsset()
+ .nft('STB44HYPYAT2BB2QE513NSP81HTMYWBJP02HPGK6.nft-contract::nft-name', Cl.uint(1));
+```
+
+Use `willNotSendAsset()` to protect valuable NFTs from being transferred unexpectedly.
+
+### Semi-fungible token (SFT) post-conditions
+
+SFTs require special handling as they have both fungible and non-fungible properties.
+
+```ts
+import { Cl, Pc } from '@stacks/transactions';
+
+// SFT as NFT (specific token ID)
+const sftNftCondition = Pc
+ .principal('STB44HYPYAT2BB2QE513NSP81HTMYWBJP02HPGK6')
+ .willSendAsset()
+ .nft(
+ 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.sft-contract::sft-id',
+ Cl.tuple({
+ 'token-id': Cl.uint(1),
+ owner: Cl.principal('STB44HYPYAT2BB2QE513NSP81HTMYWBJP02HPGK6')
+ })
+ );
+
+// SFT as FT (amount-based)
+const sftFtCondition = Pc
+ .principal('STB44HYPYAT2BB2QE513NSP81HTMYWBJP02HPGK6')
+ .willSendEq(500)
+ .ft('ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.sft-contract', 'sft-token');
+```
+
+## Multiple post-conditions
+
+Complex transactions often require multiple post-conditions to fully protect all asset transfers.
+
+```ts
+const tx = await makeContractCall({
+ // ... transaction properties
+ postConditions: [
+ // Sender must send exactly 1000 uSTX
+ Pc.principal(senderAddress).willSendEq(1000).ustx(),
+
+ // Contract must send at least 100 tokens to user
+ Pc.principal(contractAddress).willSendGte(100)
+ .ft(contractAddress + '.my-token', 'my-token'),
+
+ // User must not lose their NFT
+ Pc.principal(senderAddress).willNotSendAsset()
+ .nft(nftContract + '::my-nft', Cl.uint(1)),
+ ],
+ postConditionMode: PostConditionMode.Deny,
+});
+```
diff --git a/docs/build/post-conditions/overview.md b/docs/build/post-conditions/overview.md
new file mode 100644
index 0000000000..f6e889491f
--- /dev/null
+++ b/docs/build/post-conditions/overview.md
@@ -0,0 +1,177 @@
+---
+description: Learn how post-conditions protect users from unexpected transaction outcomes.
+---
+
+# Overview
+
+source: Hiro Blog
+
+### What are post-conditions?
+
+Post-conditions are assertions about an on-chain transaction that must be met; otherwise, the transaction will abort during execution. In other words, post-conditions act as a safety net, allowing you to specify what state changes can occur in a transaction. This logic helps limit the amount of damage that can be done to a user and their assets, whether due to a bug or malicious behavior.
+
+Put simply, post conditions are a set of conditions that must be met before a user's transaction will execute. The primary goal behind post conditions is to limit the amount of damage that can be done to a user's assets due to a bug, intentional or otherwise.
+
+Post conditions are an additional safety feature built into the Stacks chain itself that help to protect end users. Rather than being a function of Clarity smart contracts, they are implemented on the client side and meant to be an additional failsafe against malicious contracts.
+
+They are sent as part of the transaction when the user initiates it, meaning we need to implement post-conditions on the frontend. Whenever you are transferring an asset (fungible or non-fungible) from one address to another, you should take advantage of post conditions.
+
+### The post-condition stack
+
+Post-conditions are enforced by the Stacks protocol itself but do not exist in the smart contracts themselves. Instead, they are programmatically constructed in your front-end application code using Stacks.js, specifically by passing them in as options to the transaction payload construction.
+
+By having post-conditions in the frontend code, Stacks-enabled wallets, such as Leather and Xverse, are able to display the post-conditions in a human-readable format for the user when confirming their transactions. Once a user confirms the transaction, the post-conditions get carried along with the transaction payload where eventually the Stacks protocol will evaluate them together.
+
+A visualization of the “post-conditions stack" and the entities involved
+
+If there were no post-conditions in the front-end application code, a user’s wallet will display an abstract warning message, where it would be up to the user to decide whether they want to blindly proceed with the transaction or not. And whatever the underlying contract code wants to do, it will do without any post-condition restrictions. So if a contract tries to send your STX tokens to a drainer wallet, it will without you knowing.
+
+Even with post-conditions set up on the frontend code, a user is still blind to the underlying Clarity smart contract code, but at least they know what to _expect_ will happen in the transaction. And if that expectation is not met, the transaction will abort and fail.
+
+### Example of a post-condition
+
+Post-conditions act as safeguards that verify asset transfers match your expectations. They can check STX transfers, fungible tokens, and non-fungible token ownership changes.
+
+```ts
+import { Pc } from '@stacks/transactions';
+
+const tx = await makeContractCall({
+ // ...
+ postConditions: [
+ Pc.principal('STB44HYPYAT2BB2QE513NSP81HTMYWBJP02HPGK6').willSendEq(1000).ustx(),
+ ],
+});
+```
+
+In the example code snippet below, we are declaring that the user should expect to send exactly 1000 uSTX during the execution of this contract call transaction. If this condition is not met, the transaction will fail.
+
+### Using the Pc helper
+
+The `Pc` helper provides a fluent API for creating post-conditions with better type safety and readability.
+
+```ts
+import { Pc } from '@stacks/transactions';
+
+// STX transfer post-condition
+const stxCondition = Pc
+ .principal('STB44HYPYAT2BB2QE513NSP81HTMYWBJP02HPGK6')
+ .willSendGte(1000)
+ .ustx();
+
+// Fungible token post-condition
+const ftCondition = Pc
+ .principal('STB44HYPYAT2BB2QE513NSP81HTMYWBJP02HPGK6')
+ .willSendEq(50)
+ .ft('SP3D6PV2ACBPEKYJTCMH7HEN02KP87QSP8KTEH335.my-token', 'my-token');
+
+// NFT post-condition
+const nftCondition = Pc
+ .principal('STB44HYPYAT2BB2QE513NSP81HTMYWBJP02HPGK6')
+ .willSendAsset()
+ .nft('SP3D6PV2ACBPEKYJTCMH7HEN02KP87QSP8KTEH335.my-nft::my-asset', Cl.uint(1));
+```
+
+### Manual creation
+
+Create post-conditions manually using type definitions when building conditions dynamically.
+
+```ts
+import {
+ StxPostCondition,
+ FungiblePostCondition,
+ NonFungiblePostCondition
+} from '@stacks/transactions';
+
+// STX post-condition
+const stxPostCondition: StxPostCondition = {
+ type: 'stx-postcondition',
+ address: 'SP2JXKMSH007NPYAQHKJPQMAQYAD90NQGTVJVQ02B',
+ condition: 'gte', // 'eq' | 'gt' | 'gte' | 'lt' | 'lte'
+ amount: '100',
+};
+```
+
+Available condition types:
+
+* `eq`: Exactly equal to amount
+* `gt`: Greater than amount
+* `gte`: Greater than or equal to amount
+* `lt`: Less than amount
+* `lte`: Less than or equal to amount
+
+#### Fungible tokens
+
+```ts
+const ftPostCondition: FungiblePostCondition = {
+ type: 'ft-postcondition',
+ address: 'SP2JXKMSH007NPYAQHKJPQMAQYAD90NQGTVJVQ02B',
+ condition: 'eq',
+ amount: '100',
+ asset: 'SP3D6PV2ACBPEKYJTCMH7HEN02KP87QSP8KTEH335.my-ft-token::my-token',
+};
+```
+
+#### Non-fungible tokens
+
+```ts
+const nftPostCondition: NonFungiblePostCondition = {
+ type: 'nft-postcondition',
+ address: 'SP2JXKMSH007NPYAQHKJPQMAQYAD90NQGTVJVQ02B',
+ condition: 'sent', // 'sent' | 'not-sent'
+ asset: 'SP3D6PV2ACBPEKYJTCMH7HEN02KP87QSP8KTEH335.my-nft::my-asset',
+ assetId: Cl.uint(602),
+};
+```
+
+### Post-condition modes
+
+Control how unspecified, unexpected, or unforeseen asset transfers are handled with post-condition mode.
+
+#### **Deny Mode**
+
+Deny mode is the default for post-conditions. Deny is a more-strict setting for post-conditions, and it says that any other asset transfers that do not meet the criteria of the post-condition are denied. In deny mode, any transaction that does not meet the post-condition criteria will fail.
+
+```ts
+import { PostConditionMode } from '@stacks/transactions';
+
+const tx = await makeContractCall({
+ // ...
+ postConditionMode: PostConditionMode.Deny,
+ postConditions: [
+ // your conditions
+ ],
+});
+```
+
+This setting is useful when you want to limit any transfer events to a specific set of criteria. This setting is ultimately what makes post-conditions powerful, hence the reason why this is defaulted as `deny` if you don’t or forget to pass in a `postConditionMode` option.
+
+{% hint style="warning" %}
+Post-condition mode\
+Always use `Deny` mode unless you have a specific reason to allow additional transfers. This provides maximum security for users.
+{% endhint %}
+
+#### Allow mode
+
+Allow mode is a less-strict setting, in which it “allows” any transaction to execute as long as it meets the criteria of the specified post-conditions. In other words, this `allow` mode enables additional transactions to occur as long as the post-condition is met in that process. This setting is useful when you want to allow other unknown or dynamic transfers to happen. But usually you wouldn’t want to have this happen as this can open up unintended consequences for the user.
+
+### How post-conditions appear to the user
+
+Since post-conditions are declared on your frontend code, they also need to be visually displayed to users. Stacks-supported wallets handle that by displaying post-conditions on the transaction confirmation modals that popup when a user needs to confirm/approve a transaction.
+
+How post-conditions appear in wallets under different post-condition modes
+
+### Things to remember
+
+While powerful, post-conditions have some limitations you should keep in mind. Post-conditions only track who _sends_ an asset, and how much. They do not monitor who owns any set of assets when the transaction finishes, nor do they monitor the sequence of owners an asset might have during transaction execution.
+
+Alongside those limitations, it should be obvious, but it’s worth explicitly stating that post-conditions are not a catch-all. Just because you implement post-conditions doesn’t mean your contract or next transaction are guaranteed to be safe. Bugs can still occur, and you still need to build with security in mind. Debugging and extensive tests are still your best friend.
+
+***
+
+### Additional Resources
+
+* \[[Hiro Blog](https://www.hiro.so/blog/a-developers-guide-to-post-conditions)] A Developer’s Guide to Post-Conditions
+* \[[dev.to](https://dev.to/stacks/understanding-stacks-post-conditions-e65)] Understanding Stacks Post Conditions
+* \[[Hiro YT](https://youtu.be/xXgQB8NfdEY?si=aEY_wrLybfWPMJTt)] ELI5: Post-Condtions on Stacks
+* \[[Hiro YT](https://youtu.be/wagcE_IXfME?si=kDqxzPAQ-XsA478l)] Understanding Post-Conditions in a Stacks Blockchain Transaction
+* \[[StacksGov](https://github.com/stacksgov/sips/blob/main/sips/sip-005/sip-005-blocks-and-transactions.md#transaction-post-conditions)] Post-conditions section in SIP-005
diff --git a/docs/build/rendezvous/overview.md b/docs/build/rendezvous/overview.md
new file mode 100644
index 0000000000..5e344bbc61
--- /dev/null
+++ b/docs/build/rendezvous/overview.md
@@ -0,0 +1,159 @@
+---
+description: >-
+ Rendezvous is a fuzzer for Clarity smart contracts that finds vulnerabilities
+ through stateful, randomized testing, all in Clarity.
+---
+
+# Overview
+
+{% hint style="danger" %}
+Smart contracts on Stacks are immutable. Bugs are forever. Test early. Test often. Fuzzing finds edge cases that unit tests often miss.
+{% endhint %}
+
+## What is Fuzz Testing?
+
+Fuzzing hits your code with random inputs. It helps uncover unexpected behavior and subtle bugs. Unlike unit tests, it explores paths you didn't think of.
+
+## What is Rendezvous?
+
+Rendezvous (`rv`) is a Clarity fuzzer. It supports:
+
+### Property-Based Testing
+
+You extract properties about your smart contract using Clarity. Rendezvous checks them multiple times with random inputs, in a stateful manner (the smart contract's state is not refreshed during the run).
+
+**What is a property?**
+
+A property is a universal truth about your smart contract's state, functions, etc.
+
+**How to extract a property?**
+
+Say that your smart contract has a function that reverses a list of `uint`s. In this case, one property can be that "reversing a list twice returns the original list". The property will look like this:
+
+```clarity
+(define-public (test-reverse-list (seq (list 127 uint)))
+ (begin
+ (asserts!
+ (is-eq seq
+ (reverse-uint
+ (reverse-uint seq)
+ )
+ )
+ (err u999)
+ )
+ (ok true)
+ )
+)
+```
+
+**Making your property valid for Rendezvous**
+
+> For a property to be cosidered valid by Rendezvous, it has to comply with the following rules:
+>
+> * Function name starts with `test-`
+> * Function is declared as `public`
+> * Test passes when it returns `(ok true)`
+> * Test would be discarded if it returned `(ok false)`
+> * Test fails if it returns an error or throws an exception
+
+***
+
+### Invariant Testing
+
+You define read-only conditions in Clarity that must always hold true. Rendezvous attempts to create state transitions in your smart contract and continuously checks the conditions you defined to hold.
+
+**What is an invariant?**
+
+An invariant is a general truth regarding your smart contract's internal state. It will not be able to mutate the state, its role being solely to check the integrity of the state.
+
+**How to extract an invariant?**
+
+Say that you have a counter contract, having functions to `increment` and `decrement`. In this case, you could use the Rendezvous [`context`](https://stacks-network.github.io/rendezvous/chapter_6.html?#the-rendezvous-context) to extract an invariant regarding your smart contract's internal state:
+
+```clarity
+(define-read-only (invariant-counter-gt-zero)
+ (let
+ (
+ (increment-num-calls
+ (default-to u0 (get called (map-get? context "increment")))
+ )
+ (decrement-num-calls
+ (default-to u0 (get called (map-get? context "decrement")))
+ )
+ )
+ (if
+ (<= increment-num-calls decrement-num-calls)
+ true
+ (> (var-get counter) u0)
+ )
+ )
+)
+```
+
+**Making your invariant valid for Rendezvous**
+
+> For an invariant to be cosidered valid by Rendezvous, it has to complain to the following ruleset:
+>
+> * Function name starts with invariant-
+> * Function is declared as read-only (not public)
+> * Function returns a boolean value (true if the invariant holds, false if violated)
+> * The test can use the special context map to access execution history
+
+## Why Test in Clarity?
+
+{% stepper %}
+{% step %}
+#### Same constraints as production
+
+Tests operate under the exact same constraints as production code.
+{% endstep %}
+
+{% step %}
+#### Better understanding of Clarity
+
+Writing tests in Clarity improves your familiarity with the language and its semantics.
+{% endstep %}
+
+{% step %}
+#### No need to expose internals
+
+You don't have to expose internal functions as public solely for testing.
+{% endstep %}
+
+{% step %}
+#### Fewer tools to manage
+
+Running tests in Clarity reduces the number of external tools and integrations you need to maintain.
+{% endstep %}
+{% endstepper %}
+
+## Getting Started
+
+Put tests next to contracts. Rendezvous will find them.
+
+```
+my-project/
+├── Clarinet.toml
+├── contracts/
+│ ├── my-contract.clar # Contract
+│ ├── my-contract.tests.clar # Tests
+└── settings/
+ └── Devnet.toml
+```
+
+### Installation
+
+To install Rendezvous as a dependency in your project, use `npm`:
+
+```
+npm install @stacks/rendezvous
+```
+
+This will add Rendezvous to your project's `node_modules` and update your `package.json`.
+
+***
+
+### Additional Resources
+
+* \[[Github](https://stacks-network.github.io/rendezvous/)] Rendezvous repo
+* \[[Youtube @jofawole](https://youtu.be/deWQxCEy9_M?si=bBpUoKGpJvFLFu_9)] How to Use Rendezvous to Fuzz Clarity Contracts
diff --git a/docs/build/rendezvous/quickstart.md b/docs/build/rendezvous/quickstart.md
new file mode 100644
index 0000000000..28f0b2aa51
--- /dev/null
+++ b/docs/build/rendezvous/quickstart.md
@@ -0,0 +1,694 @@
+---
+description: >-
+ Learn how to test your Clarity smart contracts thoroughly using Rendezvous
+ property-based testing.
+---
+
+# Quickstart Tutorial
+
+This tutorial walks you through testing a DeFi lending contract with Rendezvous. You’ll see how Rendezvous uncovers subtle vulnerabilities that traditional unit tests might miss, and learn how to design property-based tests that help expose real bugs.
+
+## What You'll Learn
+
+You will test a simplified DeFi lending contract that allows users to deposit STX and borrow against those deposits. This contract hides a subtle bug that passes all example-based tests, but fails when running Rendezvous property-based testing.
+
+You’ll learn to:
+
+- Write property-based tests directly in Clarity
+- Catch real vulnerabilities using randomized, stateful test runs
+- Replay and fix failing test sequences deterministically
+
+> Note: This example is adapted from the [stx-defi](https://github.com/hirosystems/clarity-examples/blob/ccd9ecf0bf136d7f28ef116706ed2936f6d8781a/examples/stx-defi/contracts/stx-defi.clar) contract in the [hirosystems/clarity-examples](https://github.com/hirosystems/clarity-examples) repository.
+
+## Prerequisites
+
+Before you begin, make sure you have:
+
+- Node.js (version >= 20)
+- Clarinet installed ([installation guide](https://github.com/stx-labs/clarinet))
+
+## Step 1: Create a New Clarinet Project
+
+Open your terminal and create a new Clarinet project:
+
+```bash
+clarinet new rendezvous-tutorial
+cd rendezvous-tutorial
+```
+
+This creates a new directory with the basic Clarinet structure:
+
+```
+rendezvous-tutorial/
+├── Clarinet.toml
+├── contracts/
+├── settings/
+│ └── Devnet.toml
+└── tests/
+```
+
+## Step 2: Add Rendezvous
+
+Add Rendezvous to your project:
+
+```bash
+npm install @stacks/rendezvous
+```
+
+Verify the installation:
+
+```bash
+npx rv --help
+```
+
+## Step 3: Add the Lending Contract
+
+Add a new contract to the Clarinet project:
+
+```bash
+clarinet contract new stx-defi
+```
+
+Open `contracts/stx-defi.clar` and add this Clarity code:
+
+```clarity
+;; stx-defi.clar
+;; A simplified DeFi lending protocol.
+
+(define-map deposits
+ { owner: principal }
+ { amount: uint }
+)
+
+(define-map loans
+ principal
+ { amount: uint }
+)
+
+(define-constant err-overborrow (err u300))
+
+(define-public (deposit (amount uint))
+ (let
+ (
+ (current-balance
+ (default-to u0 (get amount (map-get? deposits { owner: tx-sender })))
+ )
+ )
+ (try! (stx-transfer? amount tx-sender (as-contract tx-sender)))
+ (map-set deposits
+ { owner: tx-sender }
+ { amount: (+ current-balance amount) }
+ )
+ (ok true)
+ )
+)
+
+(define-public (borrow (amount uint))
+ (let
+ (
+ (user-deposit
+ (default-to u0 (get amount (map-get? deposits { owner: tx-sender })))
+ )
+ (allowed-borrow (/ user-deposit u2))
+ (current-loan
+ (default-to u0 (get amount (map-get? loans tx-sender)))
+ )
+ (new-loan (+ amount))
+ )
+ (asserts! (<= new-loan allowed-borrow) err-overborrow)
+ (let
+ ((recipient tx-sender))
+ (try! (as-contract (stx-transfer? amount tx-sender recipient)))
+ )
+ (map-set loans tx-sender { amount: new-loan })
+ (ok true)
+ )
+)
+
+(define-read-only (get-loan-amount)
+ (ok (default-to u0 (get amount (map-get? loans tx-sender))))
+)
+```
+
+**What this contract does:**
+
+- Users can `deposit` STX into the protocol
+- Users can `borrow` up to 50% of their deposit value
+- The contract tracks deposits and loans for each user
+
+## Step 4: Write Some Unit Tests
+
+Let's first write some example-based unit tests.
+
+Open `tests/stx-defi.test.ts` and add these example-based unit tests:
+
+```typescript
+describe("stx-defi unit tests", () => {
+ it("can deposit", () => {
+ const amountToDeposit = 1000;
+
+ const { result } = simnet.callPublicFn(
+ "stx-defi",
+ "deposit",
+ [Cl.uint(amountToDeposit)],
+ address1
+ );
+
+ expect(result).toBeOk(Cl.bool(true));
+ });
+
+ it("can borrow half of deposit", () => {
+ const amountToDeposit = 1000;
+ const amountToBorrow = 500;
+
+ const { result: depositResult } = simnet.callPublicFn(
+ "stx-defi",
+ "deposit",
+ [Cl.uint(amountToDeposit)],
+ address1
+ );
+ expect(depositResult).toBeOk(Cl.bool(true));
+
+ const { result } = simnet.callPublicFn(
+ "stx-defi",
+ "borrow",
+ [Cl.uint(amountToBorrow)],
+ address1
+ );
+
+ expect(result).toBeOk(Cl.bool(true));
+ });
+
+ it("loan amount is correct", () => {
+ const amountToDeposit = 1000;
+ const amountToBorrow = 500;
+
+ simnet.callPublicFn(
+ "stx-defi",
+ "deposit",
+ [Cl.uint(amountToDeposit)],
+ address1
+ );
+
+ simnet.callPublicFn(
+ "stx-defi",
+ "borrow",
+ [Cl.uint(amountToBorrow)],
+ address1
+ );
+
+ const { result } = simnet.callReadOnlyFn(
+ "stx-defi",
+ "get-loan-amount",
+ [],
+ address1
+ );
+
+ expect(result).toBeOk(Cl.uint(amountToBorrow));
+ });
+
+ it("cannot borrow more than half of deposit", () => {
+ const amountToDeposit = 1000;
+ const amountToBorrow = 501;
+
+ simnet.callPublicFn(
+ "stx-defi",
+ "deposit",
+ [Cl.uint(amountToDeposit)],
+ address1
+ );
+
+ const { result } = simnet.callPublicFn(
+ "stx-defi",
+ "borrow",
+ [Cl.uint(amountToBorrow)],
+ address1
+ );
+
+ // err-overborrow
+ expect(result).toBeErr(Cl.uint(300));
+ });
+});
+```
+
+Install dependencies and run the tests:
+
+```bash
+npm install
+npm test
+```
+
+**Looking good!** ✅ (or so it seems...)
+
+The main functions and state of the contract are now covered by tests. Line coverage is probably high as well. Looks great, right? But here's the thing: example-based tests only verify the examples you thought of. Let's see if the contract holds up under **Rendezvous property-based testing**.
+
+## Step 5: Add Rendezvous Property-Based Tests
+
+Rendezvous lets you test a broader range of inputs, not just specific examples. Let's see how to write your first property-based test and why it matters.
+
+### Create the Test File
+
+Create the Rendezvous test file:
+
+```bash
+touch contracts/stx-defi.tests.clar
+```
+
+### Add an Ice-Breaker Test
+
+Before writing any meaningful properties, it's a good idea to check that Rendezvous can run. Add a simple "always-true" test to verify your setup.
+Open `contracts/stx-defi.tests.clar` and add an always-true test:
+
+```clarity
+(define-public (test-always-true)
+ (ok true)
+)
+```
+
+Check if Rendezvous can execute the test:
+
+```bash
+npx rv . stx-defi test
+```
+
+Expected output:
+
+```
+$ npx rv . stx-defi test
+Using manifest path: Clarinet.toml
+Target contract: stx-defi
+
+Starting property testing type for the stx-defi contract...
+
+₿ 1 Ӿ 3 deployer [PASS] stx-defi test-always-true (ok true)
+₿ 1 Ӿ 4 wallet_5 [PASS] stx-defi test-always-true (ok true)
+₿ 11 Ӿ 15 wallet_1 [PASS] stx-defi test-always-true (ok true)
+₿ 690 Ӿ 695 wallet_1 [PASS] stx-defi test-always-true (ok true)
+...
+₿ 12348 Ӿ 12447 wallet_3 [PASS] stx-defi test-always-true (ok true)
+₿ 12348 Ӿ 12448 wallet_3 [PASS] stx-defi test-always-true (ok true)
+₿ 12357 Ӿ 12458 wallet_5 [PASS] stx-defi test-always-true (ok true)
+
+OK, properties passed after 100 runs.
+
+
+EXECUTION STATISTICS
+
+│ PROPERTY TEST CALLS
+│
+├─ + PASSED
+│ └─ test-always-true: x100
+│
+├─ ! DISCARDED
+│ └─ test-always-true: x0
+│
+└─ - FAILED
+ └─ test-always-true: x0
+
+LEGEND:
+
+ PASSED properties verified for given inputs
+ DISCARDED skipped due to invalid preconditions
+ FAILED property violations or unexpected behavior
+```
+
+If you see similar output, your setup works. You're ready to write a **real property-based test**.
+
+### Define a Borrowing Property
+
+You want to test that **borrowing always updates the loan amount correctly**:
+
+```clarity
+;; stx-defi.tests.clar
+
+;; Property: Borrowing should always update the loan amount correctly.
+;; The new loan amount should equal the old loan amount plus the borrowed
+;; amount.
+(define-public (test-borrow (amount uint))
+ (let (
+ ;; Record the loan amount before performing any action that would end up
+ ;; changing the internal state of the smart contract. Query the loans map
+ ;; for the selected tx-sender and store the result in the initial-loan
+ ;; local variable.
+ (initial-loan (default-to u0 (get amount (map-get? loans tx-sender))))
+ )
+ ;; Since the initial-loan is recorded before the borrow call, you can now
+ ;; call the borrow function to allow checking the effects after the call.
+ (try! (borrow amount))
+ ;; Verify the property: updated loan = initial loan + borrowed amount
+ (asserts!
+ (is-eq (default-to u0 (get amount (map-get? loans tx-sender)))
+ (+ initial-loan amount)
+ )
+ (err u999) ;; any error code to identify the test failure.
+ )
+ (ok true)
+ )
+)
+```
+
+> At this stage, **the test will likely fail**. This is an important learning moment: Rendezvous runs your tests in a **stateful, randomized environment** that simulates real contract interactions.
+
+### How Rendezvous Executes Property Tests
+
+Rendezvous:
+
+1. Injects all property-based tests directly into the deployed contract.
+2. Detects all public `test-*` functions automatically.
+3. Generates a random sequence to call each test.
+4. Produces random argument values for each function parameter.
+5. Randomly selects senders from settings/Devnet.toml.
+6. Randomly advances Bitcoin and Stacks block heights during testing.
+7. Accumulates state across test calls instead of resetting each time.
+8. Discards test cases where preconditions fail, returning (ok false).
+
+This design allows you to test your contract in **realistic, varied scenarios** that a simple/example-based unit test could never reach.
+
+### Why the First Test Fails
+
+The test likely failed because the `borrow` call failed—the contract wasn't in a suitable state. Rendezvous allows you to discard test cases when preconditions aren't met (wrong state, invalid arguments, caller, height, etc.). In our case, `borrow` will fail for one of these reasons:
+
+- no deposits were made
+- the generated amount argument is non-positive (u0)
+- the generated amount argument is more than the allowed borrow value
+
+To fix this, you need to **simulate deposits** and add **discard logic**.
+
+Let's address them one by one.
+
+### Handle Preconditions
+
+**First, you need deposits.** You can create a helper function that Rendezvous will pick up during property-based testing runs. This helper will allow deposits to be created so other tests can check properties that require deposits:
+
+```clarity
+;; This is a helper function that will eventually be picked up during
+;; property-based-testing runs. It allows creating deposits in the smart
+;; contract so other tests can check properties requiring a deposit.
+(define-public (test-deposit-helper (amount uint))
+ (let (
+ ;; Call the deposit function and ignore the result.
+ (deposit-result (deposit amount))
+ )
+ (ok true)
+ )
+)
+```
+
+**Next, add discard logic to the borrow test.** A test is discarded when it returns `(ok false)`. Wrap the core test logic in a conditional that checks for invalid preconditions (the three cases listed above) and returns `(ok false)` to discard those cases:
+
+```clarity
+;; Property: Borrowing should always update the loan amount correctly.
+;; The new loan amount should equal the old loan amount plus the borrowed
+;; amount.
+(define-public (test-borrow (amount uint))
+ (if (or
+ ;; If amount is 0, the STX transfer performed in the borrow operation
+ ;; would fail, resulting in a false negative.
+ (is-eq amount u0)
+ ;; If the amount to borrow would exceed the allowed limit defined in the
+ ;; borrow function, the borrow operation would fail, resulting in a false
+ ;; negative.
+ (> (+ (default-to u0 (get amount (map-get? loans tx-sender))) amount)
+ (/ (default-to u0 (get amount (map-get? deposits { owner: tx-sender })))
+ u2
+ ))
+ )
+ ;; Discard the test if preconditions aren't met.
+ (ok false)
+ ;; Run the test.
+ (let ((initial-loan (default-to u0 (get amount (map-get? loans tx-sender)))))
+ (unwrap! (borrow amount) (err "Borrow call failed"))
+ (let ((updated-loan (default-to u0 (get amount (map-get? loans tx-sender)))))
+ ;; Verify the property: new loan = old loan + borrowed amount
+ (asserts! (is-eq updated-loan (+ initial-loan amount))
+ (err "Loan amount not updated correctly")
+ )
+ (ok true)
+ )
+ )
+ )
+)
+```
+
+The test discards invalid cases: when `amount` is `u0`, or when the new total loan would exceed half the deposit (which also covers cases with no deposits).
+
+> Now the test only runs when valid preconditions are met.
+
+### Run Rendezvous and Catch the Bug
+
+Start a new property-based testing run:
+
+```bash
+npx rv . stx-defi test
+```
+
+Rendezvous will probably catch the bug in the very first run, showing output like this:
+
+```
+$ npx rv . stx-defi test
+Using manifest path: Clarinet.toml
+Target contract: stx-defi
+
+Starting property testing type for the stx-defi contract...
+
+₿ 1 Ӿ 3 wallet_7 [PASS] stx-defi test-deposit-helper 2 (ok true)
+₿ 1001 Ӿ 1004 wallet_7 [WARN] stx-defi test-borrow 2015589496 (ok false)
+₿ 1001 Ӿ 1005 wallet_8 [PASS] stx-defi test-deposit-helper 2147483636 (ok true)
+₿ 1898 Ӿ 1903 wallet_6 [WARN] stx-defi test-borrow 1984339073 (ok false)
+₿ 1898 Ӿ 1904 deployer [PASS] stx-defi test-deposit-helper 195930186 (ok true)
+₿ 1898 Ӿ 1905 wallet_2 [PASS] stx-defi test-deposit-helper 13 (ok true)
+...
+₿ 3464 Ӿ 3485 deployer [PASS] stx-defi test-borrow 28 (ok true)
+₿ 3468 Ӿ 3490 wallet_1 [WARN] stx-defi test-borrow 25 (ok false)
+₿ 3468 Ӿ 3491 wallet_8 [FAIL] stx-defi test-borrow 11 (err "Loan amount not updated correctly")
+₿ 3468 Ӿ 3492 wallet_1 [PASS] stx-defi test-deposit-helper 1653600941 (ok true)
+₿ 4058 Ӿ 4083 wallet_8 [PASS] stx-defi test-deposit-helper 1653600941 (ok true)
+₿ 4058 Ӿ 4084 wallet_8 [WARN] stx-defi test-borrow 1653600941 (ok false)
+₿ 4058 Ӿ 4085 wallet_8 [WARN] stx-defi test-borrow 0 (ok false)
+₿ 4058 Ӿ 4086 wallet_8 [FAIL] stx-defi test-borrow 6 (err "Loan amount not updated correctly")
+₿ 4058 Ӿ 4087 wallet_8 [FAIL] stx-defi test-borrow 3 (err "Loan amount not updated correctly")
+₿ 4058 Ӿ 4088 wallet_8 [FAIL] stx-defi test-borrow 2 (err "Loan amount not updated correctly")
+₿ 4058 Ӿ 4089 wallet_8 [FAIL] stx-defi test-borrow 1 (err "Loan amount not updated correctly")
+₿ 4058 Ӿ 4090 wallet_8 [WARN] stx-defi test-borrow 0 (ok false)
+₿ 4058 Ӿ 4091 wallet_8 [FAIL] stx-defi test-borrow 1 (err "Loan amount not updated correctly")
+₿ 4058 Ӿ 4092 wallet_8 [WARN] stx-defi test-borrow 0 (ok false)
+₿ 4058 Ӿ 4093 wallet_8 [FAIL] stx-defi test-borrow 1 (err "Loan amount not updated correctly")
+
+Error: Property failed after 22 tests.
+Seed : 1880056597
+
+Counterexample:
+- Test Contract : stx-defi
+- Test Function : test-borrow (public)
+- Arguments : [1]
+- Caller : wallet_8
+- Outputs : {"type":{"response":{"ok":"bool","error":{"string-ascii":{"length":33}}}}}
+
+What happened? Rendezvous went on a rampage and found a weak spot:
+
+The test function "test-borrow" returned:
+
+(err "Loan amount not updated correctly")
+
+EXECUTION STATISTICS
+
+│ PROPERTY TEST CALLS
+│
+├─ + PASSED
+│ ├─ test-borrow: x2
+│ └─ test-deposit-helper: x13
+│
+├─ ! DISCARDED
+│ ├─ test-borrow: x12
+│ └─ test-deposit-helper: x0
+│
+└─ - FAILED
+ ├─ test-borrow: x7
+ └─ test-deposit-helper: x0
+
+LEGEND:
+
+ PASSED properties verified for given inputs
+ DISCARDED skipped due to invalid preconditions
+ FAILED property violations or unexpected behavior
+
+! FAILED tests indicate that your function properties don't hold for all inputs. Review the counterexamples above for debugging.
+```
+
+The output shows a failure: `(err "Loan amount not updated correctly")`. The contract isn't tracking loan amounts correctly.
+
+> **Note:** The output includes a seed (`1880056597`) you can use to reproduce this exact sequence.
+
+You can also stop at the first failure:
+
+```bash
+npx rv . stx-defi test --bail
+```
+
+## Step 6: Identify and Fix the Borrow Bug
+
+After taking a closer look at the lending contract, the bug is in this line of the `borrow` function:
+
+```clarity
+(new-loan (+ amount))
+```
+
+Change the line to correctly accumulate loans:
+
+```clarity
+(new-loan (+ current-loan amount))
+```
+
+### Re-run Rendezvous with the Same Seed
+
+Re-run with the same seed, to find out if you completely fixed the bug for that random sequence of events:
+
+```clarity
+npx rv . stx-defi test --seed=1880056597
+```
+
+Output:
+
+```
+$ npx rv . stx-defi test --seed=1880056597
+Using manifest path: Clarinet.toml
+Target contract: stx-defi
+Using seed: 1880056597
+
+Starting property testing type for the stx-defi contract...
+
+₿ 1 Ӿ 3 wallet_7 [PASS] stx-defi test-deposit-helper 2 (ok true)
+₿ 1001 Ӿ 1004 wallet_7 [WARN] stx-defi test-borrow 2015589496 (ok false)
+₿ 1001 Ӿ 1005 wallet_8 [PASS] stx-defi test-deposit-helper 2147483636 (ok true)
+₿ 1898 Ӿ 1903 wallet_6 [WARN] stx-defi test-borrow 1984339073 (ok false)
+₿ 1898 Ӿ 1904 deployer [PASS] stx-defi test-deposit-helper 195930186 (ok true)
+₿ 1898 Ӿ 1905 wallet_2 [PASS] stx-defi test-deposit-helper 13 (ok true)
+...
+₿ 17291 Ӿ 17388 wallet_4 [PASS] stx-defi test-borrow 708340522 (ok true)
+₿ 17291 Ӿ 17389 wallet_4 [PASS] stx-defi test-deposit-helper 589199221 (ok true)
+₿ 17565 Ӿ 17664 wallet_2 [PASS] stx-defi test-deposit-helper 2147483627 (ok true)
+₿ 18559 Ӿ 18659 wallet_8 [PASS] stx-defi test-borrow 1622181282 (ok true)
+₿ 18559 Ӿ 18660 wallet_3 [PASS] stx-defi test-deposit-helper 2147483630 (ok true)
+
+OK, properties passed after 100 runs.
+```
+
+> The bug is fixed! The contract now correctly tracks cumulative loans.
+
+### Run Multiple Random Sequences
+
+Test additional random sequences (each run generates a new random sequence):
+
+```bash
+npx rv . stx-defi test
+```
+
+Run more tests to increase confidence (default is 100 runs):
+
+```bash
+npx rv . stx-defi test --runs=1000
+```
+
+**Rendezvous caught the bug and you successfully fixed it!** 🎯
+
+## Step 7: Understand the Bug
+
+**What was the bug?**
+
+Rendezvous discovered that when a user borrows multiple times, only the most recent borrow amount is recorded.
+
+The bug means the contract doesn't track cumulative borrows correctly. When a user borrows multiple times, only the most recent borrow amount is recorded, not the total. The existing loan amount (`current-loan`) is completely ignored!
+
+**Why did example-based unit tests miss this?**
+
+The unit tests passed because they only tested single borrow scenarios. Look back at the unit test:
+
+```typescript
+it("loan amount is correct after single borrow", () => {
+ // Only ONE borrow call - bug not triggered!
+ simnet.callPublicFn(
+ "stx-defi",
+ "borrow",
+ [Cl.uint(amountToBorrow)],
+ address1
+ );
+ // ...
+});
+```
+
+When there's only one borrow, `(+ amount)` and `(+ current-loan amount)` produce the same result because the initial loan is `u0`.
+
+**Rendezvous caught the bug by:**
+
+1. Randomly generating test sequences
+2. Calling `borrow` multiple times with different amounts
+3. Verifying the property holds for ALL sequences
+
+This is the power of using Rendezvous!
+
+## What You Learned
+
+You've successfully:
+
+✅ Created a simple DeFi lending contract
+
+✅ Wrote traditional unit tests that passed but missed a critical bug
+
+✅ Wrote your first Rendezvous property-based test
+
+✅ Discovered how Rendezvous catches bugs through random stateful testing
+
+✅ Fixed the bug and verified the fix
+
+✅ Understood the difference between stateless example-based and stateful property-based testing
+
+## The Key Insight
+
+**Example-based tests check specific examples. Property-based tests check a much broader range of inputs.**
+
+Example-based tests ask:
+
+- "Does this work for input A?"
+- "Does this work for input B?"
+
+Property-based tests ask:
+
+- "Does this ALWAYS work?"
+- "Can I find ANY input that breaks this?"
+
+Rendezvous explores your contract's state space automatically, finding edge cases you might never think to test manually.
+
+## Real-World Impact
+
+This bug in a production DeFi protocol would allow users to:
+
+1. Deposit 1000 STX
+2. Borrow 500 STX (maximum allowed)
+3. Borrow another 500 STX (should fail, but succeeds due to bug)
+4. Total borrowed: 1000 STX with only 500 STX recorded
+5. User only needs to repay 500 STX despite borrowing 1000 STX
+
+This would drain the protocol's funds — a critical vulnerability caught by Rendezvous in seconds.
+
+## Example Implementation
+
+You can see a complete step-by-step implementation of this tutorial with commit-by-commit progress in the [rendezvous-tutorial repository](https://github.com/BowTiedRadone/rendezvous-tutorial) ([view commits](https://github.com/BowTiedRadone/rendezvous-tutorial/commits/master/)).
+
+## Next Steps
+
+Now that you understand the power of Rendezvous, explore:
+
+- **More examples**: Study other smart contracts in the [Examples Chapter](https://stacks-network.github.io/rendezvous/chapter_8.html) of the [Rendezvous Docs](https://stacks-network.github.io/rendezvous/)
+- **Your own contracts**: Apply Rendezvous to your projects and find bugs before they reach production
+
+---
+
+## Get Involved
+
+**Found this tutorial useful?** Star the [Rendezvous repository on GitHub](https://github.com/stacks-network/rendezvous) to show your support!
+
+Have questions, found a bug, or want to contribute? We'd love to hear from you:
+
+- **Open an issue** on [GitHub](https://github.com/stacks-network/rendezvous/issues)
+- **Reach out** with questions or feedback
+- **Share your findings** — contribute examples of bugs you've caught to show others how powerful advanced testing techniques can be
diff --git a/docs/build/stacks-connect/broadcast-transactions.md b/docs/build/stacks-connect/broadcast-transactions.md
new file mode 100644
index 0000000000..bd62c7a742
--- /dev/null
+++ b/docs/build/stacks-connect/broadcast-transactions.md
@@ -0,0 +1,168 @@
+# Broadcast Transactions
+
+The process of broadcasting transactions is fundamental for interacting with blockchains, whether you're transferring tokens, deploying contracts, or executing contract functions.
+
+In this guide you will:
+
+* Install the required packages
+* Connect to a user's wallet
+* Sign and broadcast different transaction types
+* Handle transaction results
+
+## Setup and installation
+
+Install the required packages to start building and broadcasting transactions.
+
+{% tabs %}
+{% tab title="npm" %}
+```bash
+npm install @stacks/connect @stacks/transactions
+```
+{% endtab %}
+
+{% tab title="yarn" %}
+```bash
+yarn add @stacks/connect @stacks/transactions
+```
+{% endtab %}
+
+{% tab title="pnpm" %}
+```bash
+pnpm add @stacks/connect @stacks/transactions
+```
+{% endtab %}
+{% endtabs %}
+
+## Connect to a user's wallet
+
+Before signing transactions, users need to connect their wallet to your application. Use the `connect` function to initiate a wallet connection:
+
+```ts
+import { connect, isConnected } from '@stacks/connect';
+
+async function connectWallet() {
+ if (!isConnected()) {
+ const response = await connect();
+ console.log('Connected with addresses:', response);
+ }
+}
+```
+
+## Sign and broadcast transactions
+
+There are three common transaction flows you can build:
+
+{% stepper %}
+{% step %}
+#### STX transfer
+
+Use `stx_transferStx` to send tokens:
+
+```ts
+import { request } from '@stacks/connect';
+
+async function transferStx() {
+ const response = await request('stx_transferStx', {
+ recipient: 'ST2EB9WEQNR9P0K28D2DC352TM75YG3K0GT7V13CV',
+ amount: '100',
+ memo: 'Reimbursement',
+ });
+
+ console.log('Transaction ID:', response.txId);
+}
+```
+{% endstep %}
+
+{% step %}
+#### Contract deployment
+
+Deploy a contract with `stx_deployContract`:
+
+```ts
+import { request } from '@stacks/connect';
+
+async function deployContract() {
+ const codeBody = '(define-public (say-hi) (ok "hello world"))';
+
+ const response = await request('stx_deployContract', {
+ name: 'my-contract',
+ code: codeBody,
+ clarityVersion: 3,
+ });
+
+ console.log('Transaction ID:', response.txId);
+}
+```
+
+{% hint style="info" %}
+Contracts deploy to the Stacks address of the connected wallet.
+{% endhint %}
+{% endstep %}
+
+{% step %}
+#### Contract execution
+
+Call contract functions with `stx_callContract`:
+
+```clarity
+(define-public (say-hi)
+ (print "hi")
+ (ok u0)
+)
+```
+
+```ts
+import { request } from '@stacks/connect';
+
+async function callContract() {
+ const response = await request('stx_callContract', {
+ contractAddress: 'ST22T6ZS7HVWEMZHHFK77H4GTNDTWNPQAX8WZAKHJ',
+ contractName: 'my-contract',
+ functionName: 'say-hi',
+ functionArgs: [],
+ });
+
+ console.log('Transaction ID:', response.txId);
+}
+```
+
+When passing arguments, construct Clarity values via `Cl`:
+
+```ts
+import { Cl } from '@stacks/transactions';
+
+const functionArgs = [
+ Cl.uint(123),
+ Cl.stringAscii('hello'),
+ Cl.standardPrincipalCV('ST1X..'),
+];
+```
+{% endstep %}
+{% endstepper %}
+
+## Handle transaction results
+
+When a transaction is signed and broadcast, the `request` method returns a response object containing information about the transaction:
+
+```ts
+interface TransactionResponse {
+ txId: string; // The transaction ID
+ txRaw: string; // The raw transaction hex
+}
+```
+
+You can use the transaction ID to create a link to view the transaction in the explorer:
+
+```ts
+import { request } from '@stacks/connect';
+
+async function handleTransaction() {
+ const response = await request('stx_transferStx', {
+ recipient: 'ST2EB9WEQNR9P0K28D2DC352TM75YG3K0GT7V13CV',
+ amount: '100',
+ });
+
+ const explorerUrl = `https://explorer.stacks.co/txid/${response.txId}`;
+ console.log('View transaction in explorer:', explorerUrl);
+}
+```
diff --git a/docs/build/stacks-connect/connect-wallet.md b/docs/build/stacks-connect/connect-wallet.md
new file mode 100644
index 0000000000..d89bdee0f2
--- /dev/null
+++ b/docs/build/stacks-connect/connect-wallet.md
@@ -0,0 +1,125 @@
+# Connect Wallet
+
+Learn how to integrate wallet connections into your Stacks application. Connecting a wallet authenticates users and enables blockchain interactions like transfers and contract calls.
+
+source: Hiro blog
+
+{% hint style="success" %}
+For the latest releases and versions of `@stacks/connect`, check out its npm page [here](https://www.npmjs.com/package/@stacks/connect).
+{% endhint %}
+
+## What you'll learn
+
+* Install the `@stacks/connect` package
+* Connect to a wallet and authenticate users
+* Manage authentication state
+* Access user account data
+
+{% hint style="info" %}
+Prerequisites:
+
+* Node.js installed on your machine
+* A web application setup (React, Vue, or vanilla JS)
+* Basic understanding of async/await
+{% endhint %}
+
+## Quickstart
+
+{% stepper %}
+{% step %}
+#### Install package
+
+Add Stacks Connect to your project:
+
+{% code title="Install" %}
+```bash
+npm install @stacks/connect
+```
+{% endcode %}
+{% endstep %}
+
+{% step %}
+#### Connect and authenticate
+
+Use `connect` to initiate a wallet session and persist user data:
+
+{% code title="connect.ts" %}
+```ts
+import { connect, isConnected } from '@stacks/connect';
+
+async function connectWallet() {
+ if (isConnected()) {
+ console.log('Already authenticated');
+ return;
+ }
+
+ const response = await connect();
+ console.log('Connected:', response.addresses);
+}
+```
+{% endcode %}
+
+Manage authentication state in your app:
+
+{% code title="auth.ts" %}
+```ts
+import { disconnect, isConnected } from '@stacks/connect';
+
+const authenticated = isConnected();
+
+function logout() {
+ disconnect();
+ console.log('User disconnected');
+}
+```
+{% endcode %}
+{% endstep %}
+
+{% step %}
+#### Access user data
+
+Read persisted addresses and request full account details:
+
+{% code title="user-data.ts" %}
+```ts
+import { getLocalStorage, request } from '@stacks/connect';
+
+const userData = getLocalStorage();
+if (userData?.addresses) {
+ const stxAddress = userData.addresses.stx[0].address;
+ const btcAddress = userData.addresses.btc[0].address;
+ console.log('STX:', stxAddress);
+ console.log('BTC:', btcAddress);
+}
+
+const accounts = await request('stx_getAccounts');
+const account = accounts.addresses[0];
+console.log('Address:', account.address);
+console.log('Public key:', account.publicKey);
+console.log('Gaia URL:', account.gaiaHubUrl);
+```
+{% endcode %}
+{% endstep %}
+
+{% step %}
+#### Make your first transaction
+
+Request the wallet to broadcast a transfer:
+
+{% code title="send-transaction.ts" %}
+```ts
+import { request } from '@stacks/connect';
+
+async function sendTransaction() {
+ const response = await request('stx_transferStx', {
+ amount: '1000000',
+ recipient: 'SP2MF04VAGYHGAZWGTEDW5VYCPDWWSY08Z1QFNDSN',
+ memo: 'First transfer',
+ });
+
+ console.log('Transaction ID:', response.txid);
+}
+```
+{% endcode %}
+{% endstep %}
+{% endstepper %}
diff --git a/docs/build/stacks-connect/message-signing.md b/docs/build/stacks-connect/message-signing.md
new file mode 100644
index 0000000000..437aca5574
--- /dev/null
+++ b/docs/build/stacks-connect/message-signing.md
@@ -0,0 +1,191 @@
+# Message Signing
+
+Learn how to implement message signing in your Stacks application. Message signing allows users to cryptographically prove they control an address without making an on-chain transaction, enabling authentication, authorization, and verifiable statements.
+
+## What you'll learn
+
+* Connect to a user's wallet and request message signatures
+* Sign both simple text messages and structured data
+* Verify signatures to ensure authenticity
+
+## Prerequisites
+
+* Node.js installed on your machine
+* A code editor like VS Code
+
+## Installation
+
+Install the required packages for message signing and verification.
+
+```bash
+npm install @stacks/connect @stacks/encryption
+```
+
+## Connect to wallet
+
+Before signing messages, establish a connection to the user's wallet. The connection persists across page reloads.
+
+```ts
+import { connect, isConnected } from '@stacks/connect';
+
+async function connectWallet() {
+ if (!isConnected()) {
+ const response = await connect();
+ console.log('Connected addresses:', response.addresses);
+ }
+}
+```
+
+Call this function when your app loads or when the user clicks a connect button.
+
+## Sign text messages
+
+Request a signature for a simple text message using the `request` method.
+
+```ts
+import { request } from '@stacks/connect';
+
+async function signMessage() {
+ const message = 'Hello World';
+
+ const response = await request('stx_signMessage', {
+ message,
+ });
+
+ console.log('Signature:', response.signature);
+ console.log('Public key:', response.publicKey);
+
+ return response;
+}
+```
+
+The wallet will display the message to the user for approval before signing.
+
+## Sign structured data
+
+For more complex data, use structured message signing with Clarity values.
+
+```ts
+import { request } from '@stacks/connect';
+import { Cl } from '@stacks/transactions';
+
+async function signStructuredMessage() {
+ const message = Cl.tuple({
+ action: Cl.stringAscii('transfer'),
+ amount: Cl.uint(1000),
+ recipient: Cl.stringAscii('alice.btc')
+ });
+
+ const domain = Cl.tuple({
+ name: Cl.stringAscii('My App'),
+ version: Cl.stringAscii('1.0.0'),
+ 'chain-id': Cl.uint(1) // 1 for mainnet
+ });
+
+ const response = await request('stx_signStructuredMessage', {
+ message,
+ domain
+ });
+
+ return response;
+}
+```
+
+Structured messages provide better type safety and are easier to parse on-chain.
+
+## Verify signatures
+
+Validate signatures to ensure they match the expected message and public key.
+
+```ts
+import { verifyMessageSignatureRsv } from '@stacks/encryption';
+
+async function verifySignature(
+ message: string,
+ signature: string,
+ publicKey: string
+): Promise {
+ const isValid = verifyMessageSignatureRsv({
+ message,
+ signature,
+ publicKey
+ });
+
+ if (isValid) {
+ console.log('✓ Signature verified successfully');
+ } else {
+ console.log('✗ Invalid signature');
+ }
+
+ return isValid;
+}
+```
+
+Always verify signatures before trusting the signed data.
+
+## Complete verification flow
+
+```ts
+async function signAndVerify() {
+ // Request signature
+ const message = 'Authorize login at ' + new Date().toISOString();
+ const signResponse = await request('stx_signMessage', { message });
+
+ // Verify immediately
+ const isValid = await verifySignature(
+ message,
+ signResponse.signature,
+ signResponse.publicKey
+ );
+
+ if (isValid) {
+ // Proceed with authenticated action
+ console.log('Authentication successful');
+ }
+}
+```
+
+## Try it out
+
+Create a simple authentication system using message signatures.
+
+```ts
+// Generate a unique challenge
+function generateChallenge(): string {
+ const nonce = Math.random().toString(36).substring(7);
+ const timestamp = Date.now();
+ return `Sign this message to authenticate:\nNonce: ${nonce}\nTime: ${timestamp}`;
+}
+
+// Complete auth flow
+async function authenticate() {
+ const challenge = generateChallenge();
+
+ try {
+ const response = await request('stx_signMessage', {
+ message: challenge
+ });
+
+ const isValid = verifyMessageSignatureRsv({
+ message: challenge,
+ signature: response.signature,
+ publicKey: response.publicKey
+ });
+
+ if (isValid) {
+ // Store auth token or session
+ localStorage.setItem('auth', JSON.stringify({
+ publicKey: response.publicKey,
+ timestamp: Date.now()
+ }));
+
+ return { success: true };
+ }
+ } catch (error) {
+ console.error('Authentication failed:', error);
+ }
+
+ return { success: false };
+}
+```
+
diff --git a/docs/build/stacks-connect/migration-guide.md b/docs/build/stacks-connect/migration-guide.md
new file mode 100644
index 0000000000..9690e9c120
--- /dev/null
+++ b/docs/build/stacks-connect/migration-guide.md
@@ -0,0 +1,90 @@
+# Migration Guide
+
+For a while now, the Stacks community has been working on a new standard for wallet-to-dapp communication. Stacks Connect and related projects now use standards like [WBIPs](https://wbips.netlify.app/) and [SIP-030](https://github.com/janniks/sips/blob/main/sips/sip-030/sip-030-wallet-interface.md) to allow wallets to communicate with dapps in a more simplified and flexible way.
+
+{% hint style="info" %}
+Migration status\
+Feel free to continue using Stacks Connect `7.x.x` while things stabilize. The `7.x.x` version may still be better supported by some wallets.
+
+Legacy installs:
+
+```bash
+npm install @stacks/connect@7.10.1
+```
+{% endhint %}
+
+## Deprecations
+
+The following classes, methods, and types are deprecated in favor of the new `request` RPC methods:
+
+* `show...` and `open...` methods
+* `authenticate` method
+* `UserSession` class and related functionality
+* `AppConfig` class
+* `SessionOptions` interface
+* `SessionData` interface
+* `UserData` interface
+* `SessionDataStore` class
+* `InstanceDataStore` class
+* `LocalStorageStore` class
+
+{% hint style="info" %}
+Backwards compatibility\
+`UserSession` and `AppConfig` remain available in `8.x.x` for caching addresses via `loadUserData`, but consider them temporary helpers while you migrate.
+{% endhint %}
+
+## Migration steps
+
+{% stepper %}
+{% step %}
+#### Update your @stacks/connect version
+
+```bash
+npm install @stacks/connect@latest
+```
+{% endstep %}
+
+{% step %}
+#### Replace legacy methods with `request`
+
+Switch from `showXyz`, `openXyz`, and `doXyz` helpers to the generic `request(method, params)` API. The `request` function is async, so replace `onFinish`/`onCancel` callbacks with `await` or `.then().catch()` chains.
+
+Examples:
+
+* `showConnect()`, `authenticate()` → `connect()`
+* `useConnect().doContractCall({})` → `request('stx_callContract', {})`
+* `openContractDeploy()` → `request('stx_deployContract', {})`
+{% endstep %}
+
+{% step %}
+#### Use `connect` instead of `showConnect` / `authenticate`
+
+`connect()` is an alias for `request('getAddresses', { forceWalletSelect: true })` and caches the selected address in local storage by default.
+{% endstep %}
+
+{% step %}
+#### Update authentication state management
+
+* Replace `UserSession.isSignedIn()` with `isConnected()`
+* Replace `UserSession.signUserOut()` with `disconnect()`
+{% endstep %}
+
+{% step %}
+#### Remove legacy code
+
+* Delete references to deprecated helpers (`AppConfig`, `UserSession`, etc.)
+* Remove the `@stacks/connect-react` package
+ * Manually reload components if you rely on local storage updates
+ * Hooks are no longer required for Stacks Connect
+* A new `@stacks/react` package is in development to simplify state tracking (transaction status, network changes, and more)
+{% endstep %}
+{% endstepper %}
+
+## Address Access
+
+Previously, the `UserSession` class was used to access the user's addresses and data, which abstracted away the underlying implementation details. Now, the `request` method is used to directly interact with the wallet, giving developers more explicit control and clarity over what's happening under the hood. This manual approach makes the wallet interaction more transparent and customizable. Developers can manually manage the currently connected user's address in e.g. local storage, jotai, etc. or use the `connect()`/`request()` method to cache the address in local storage.
+
+{% hint style="warning" %}
+Security note\
+`8.x.x` wallets return only the current network's address (previous versions returned both mainnet and testnet).
+{% endhint %}
diff --git a/docs/build/stacks-connect/wallet-implementation.md b/docs/build/stacks-connect/wallet-implementation.md
new file mode 100644
index 0000000000..be24d485c9
--- /dev/null
+++ b/docs/build/stacks-connect/wallet-implementation.md
@@ -0,0 +1,197 @@
+---
+description: Support Stacks Connect in your own wallet
+---
+
+# Wallet Implementation
+
+
+
+Connect provides a streamlined way for wallets to integrate with dapps by using a simple, direct RPC-based protocol, avoiding unnecessary abstraction layers. It defines a clear wallet provider interface and discovery mechanism, enabling consistent, conflict-free wallet connections. This approach makes it easier for applications to integrate wallets and for anyone to build a wallet that is reliably discoverable by Connect-enabled dapps.
+
+### Discovery Mechanism
+
+**Enable Your Custom Wallet to be Detected by Stacks Apps**
+
+
+
+We will show you how your wallet can interact with incoming JSON RPC 2.0 requests and responses to handle modern Connect methods in order to connect to apps. But first, you’ll want to make sure you have a good understanding of the different context script standards of a [Chrome extension](https://developer.chrome.com/docs/extensions). The context scripts mainly consist of your popup script, background script, and content script.
+
+**3 scripts of a Chrome extension:**
+
+* **Popup**: This is the main script that handles the visual UI of the actual popup modal when interacting with an extension.
+* **Background**: This script allows your extension to hand off logic that may require intensive computation or for dealing with secure data.
+* **Content**: This allows your extension to interact with the web page itself.
+
+In your content script, which enables you to run scripts on the web page a user is currently on, you’ll want to “inject” a `StacksProvider` object type into the global `window` object of the web page. It’s important to note that this must be handled by your extension’s content script, which should automatically load anytime you land on a webpage. This injected object is what will allow web apps to directly interact with your wallet. It’s like your wallet extension saying, “Hey! I’m available to communicate with your app, let’s connect!”
+
+The `StacksProvider` object needs to at least have a `.request` method that takes in the name of a string literal method, and an parameters object.
+
+{% code title="injection.js" expandable="true" %}
+```typescript
+// --snip--
+
+window.MyProvider = {
+ async request(method, params) {
+ // Somehow communicate with the wallet (e.g. via events)
+
+ // Recommendation: Create a JSON RPC 2.0 request object
+ // https://www.jsonrpc.org/specification
+
+ return Promise.resolve({
+ // Respond with a JSON RPC 2.0 response object
+ id: crypto.randomUUID(), // required, same as request
+ jsonrpc: '2.0', // required
+
+ // `.result` is required on success
+ result: {
+ // object matching specified RPC methods
+ },
+
+ // `.error` is required on error
+ error: {
+ // Use existing codes from https://www.jsonrpc.org/specification#error_object
+ code: number, // required, integer
+ message: string, // recommended, single sentence
+ data: object, // optional
+ },
+ });
+ },
+ isMyWallet: true, // optional, a way of identifying the wallet for developers
+};
+
+// --snip--
+```
+{% endcode %}
+
+This `StacksProvider` object type could be named anything. In the example above, it’s named `MyProvider`.
+
+From here, web apps can directly call your wallet extension provider via `window.MyProvider` directly, and you don’t even need to use the Stacks Connect library. However, your wallet app would need to manually handle other important implementation details, such as the storage of the wallet info and individual method calling.
+
+But with the Connect library, apps don’t have to manually roll their own methods and implementations. The Connect library will handle all those functionalities for the app.
+
+In order for you to make your wallet provider object (from the previous section) be discoverable by the Connect modal UI wallet selector used by frontend apps, you’ll need to then pass it into a separate `wbip_providers` array on the `window` object. The `wbip_providers` array is a new standard set forth by [WBIP004](https://wbips.netlify.app/wbips/WBIP004).
+
+Any wallet that registers their provider in this array is declaring that they are conforming to the WBIP standards, which are a set of specifications for web apps and client providers to facilitate communication with Bitcoin-related apps. Wallets SHOULD register their provider information under `window.wbip_providers` to be discoverable by websites/libraries expecting this WBIP.
+
+{% code title="injection.js" expandable="true" %}
+```typescript
+// --snip--
+
+window.wbip_providers = window.wbip_providers || [];
+window.wbip_providers.push({
+ // `WbipProvider` type
+ /** The global "path" of the provider (e.g. `"MyProvider"` if registered at `window.MyProvider`) */
+ id: 'MyProvider',
+ /** The name of the provider, as displayed to the user */
+ name: 'My Wallet';
+ /** The data URL of an image to show (e.g. `data:image/png;base64,iVBORw0...`) @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs */
+ icon?: 'data:image/png;base64,iVBORw0...';
+ /** Web URL of the provider */
+ webUrl?: 'https://mywallet.example.com';
+
+ // Additional URLs
+ chromeWebStoreUrl?: string;
+ mozillaAddOnsUrl?: string;
+ googlePlayStoreUrl?: string;
+ iOSAppStoreUrl?: string;
+});
+
+// --snip--
+```
+{% endcode %}
+
+Literally injecting these scripts can come from your content script as shown below. You could leverage the content.js script for injecting the `injection.js` into the document page and forwarding messages between the document page and the background script. Setup is dependent on your architecture.
+
+{% code title="content.js" %}
+```typescript
+// --snip--
+
+const script = document.createElement("script");
+script.src = chrome.runtime.getURL("injection.js");
+script.type = "module";
+document.head.prepend(script);
+
+// --snip--
+```
+{% endcode %}
+
+### Handling Method Requests and Responses
+
+**Enable your wallet to handle requests from the frontend app**
+
+Structuring the manner in which your wallet handles methods internally is up to your discretion (most methods can be properly handled by methods from [@stacks/transactions](https://docs.hiro.so/stacks/stacks.js/packages/transactions)), but receiving and responding to messages should adhere to the JSON RPC 2.0 standard and data types based on the string literal methods of the incoming request.
+
+Let’s take the most basic function of connecting. From the Connect modal UI wallet selector, once a user clicks on the `connect` button of your wallet, it will invoke the string literal method of `getAddresses`, which accepts an optional parameter of `network`.
+
+Communication flows are based off of standards like WBIP and SIP-030 to allow wallets to communicate with apps in a more simplified and flexible way.
+
+Once your wallet receives this JSON RPC 2.0 request message, it needs to handle the request and then return a response that conforms to the return type for `getAddresses`.
+
+Using the `MethodParams` and `MethodResult` type helpers from the Connect library can help you here. Here’s a simplified example of how your wallet should handle the string literal method of `getAddresses`, which allows a standard connection between your wallet and app.
+
+{% code expandable="true" %}
+```typescript
+import { type MethodResult, type MethodParams } from "@stacks/connect";
+
+async function handleGetAddresses(payload: JsonRpcRequest) {
+ let params: MethodParams<"getAddresses"> = payload.params;
+
+ // handle generation of account addresses to return back to the app
+
+ let result: MethodResult<"getAddresses"> = {
+ addresses: [
+ {
+ symbol: "BTC",
+ address: btcP2PKHAddress,
+ publicKey: pubKey,
+ },
+ {
+ symbol: "BTC",
+ address: btcP2TRAddress,
+ publicKey: pubKey,
+ },
+ {
+ symbol: "STX",
+ address: stxAddress,
+ publicKey: pubKey,
+ }
+ ]
+ };
+
+ return result
+}
+```
+{% endcode %}
+
+You can also add your own unstandardized methods to your wallet. However, the minimum recommended methods to handle basic wallet functions are standardized and include:
+
+* `getAddresses`
+* `sendTransfer`
+* `signPsbt`
+* `stx_getAddresses`
+* `stx_transferStx`
+* `stx_callContract`
+* `stx_signMessage`
+* `stx_signStructuredMessage`
+
+### Stacks Wallet Template
+
+**Build your own Stacks wallet with the Wallet Template in the Hiro Platform**
+
+
+
+This template is a Chrome extension that comes with basic wallet functionalities, such as generating Stacks and Bitcoin addresses, changing accounts, and importing of external mnemonic seed phrases. Using this template as a starting point, you can build on this template to add other wallet features, such as displaying Stacks NFTs, fetching [Ordinals](https://www.hiro.so/ordinals-api) or [Runes](https://www.hiro.so/runes-api) balances with our dedicated APIs, securing of user mnemonic seed phrases, and much more.
+
+It’s important to have an ecosystem that boasts a plethora of diverse wallet providers for different use cases, and learning how to build a wallet is a great entry point to Web3 and the Stacks ecosystem. Check out this [article](https://www.hiro.so/blog/an-intro-to-web3-wallets-for-web3-founders) to learn more about the importance of web3 wallets for web3 founders.
+
+Head to the [Hiro Platform](https://platform.hiro.so/) to start building with this template.
+
+***
+
+### Additional Resources
+
+* \[[Hiro Platform](https://platform.hiro.so/templates/wallet-extension)] Stacks Wallet Extension Template
+* \[[Hiro YT](https://www.youtube.com/watch?v=PdluvfFPWoU)] Build Your Own Bitcoin L2 Wallet Browser Extension
+* \[[Github repo](https://github.com/hirosystems/platform-template-stacks-wallet)] Open-source repo of the Stacks wallet extension template
+* \[[WBIP](https://wbips.netlify.app/)] Stacks Wallet BIPs
+* \[[SIP-030](https://github.com/janniks/sips/blob/main/sips/sip-030/sip-030-wallet-interface.md)] Definition of a Modern Stacks Wallet Interface Standard
diff --git a/docs/build/stacks-connect/wallet-support.md b/docs/build/stacks-connect/wallet-support.md
new file mode 100644
index 0000000000..12eeb41025
--- /dev/null
+++ b/docs/build/stacks-connect/wallet-support.md
@@ -0,0 +1,61 @@
+# Wallet Support
+
+{% hint style="info" %}
+Legend:
+
+* 🔴 No support (yet)
+* 🟡 Partial support
+* 🟢 Supported
+* 🔵 Compatibility overrides present (may transform/normalize behavior)
+{% endhint %}
+
+## Wallet Support
+
+This page provides detailed information about which methods and events are supported by different wallet providers in the Stacks ecosystem.
+
+### Method Compatibility
+
+| Method | Leather | Xverse-like |
+| --------------------------- | --------------------------------------- | ------------------------------------------------------------------- |
+| `getAddresses` | 🟡 No support for experimental purposes | 🟡 Use `wallet_connect` instead |
+| `sendTransfer` | 🟡 Expects `amount` as string | 🟡 Expects `amount` as number |
+| `signPsbt` | 🟡 Uses signing index array only | 🟡 Uses `signInputs` record instead of array |
+| `stx_getAddresses` | 🟢 | 🔴 |
+| `stx_getAccounts` | 🔴 | 🟢 |
+| `stx_getNetworks` | 🔴 | 🔴 |
+| `stx_transferStx` | 🟢 | 🟢 |
+| `stx_transferSip10Ft` | 🟢 | 🔴 |
+| `stx_transferSip9Nft` | 🟢 | 🔴 |
+| `stx_callContract` | 🟡 Hex-encoded Clarity values only | 🟡 Hex-encoded Clarity values only, no support for `postConditions` |
+| `stx_deployContract` | 🟡 Hex-encoded Clarity values only | 🟡 Hex-encoded Clarity values only, no support for `postConditions` |
+| `stx_signTransaction` | 🟡 Hex-encoded Clarity values only | 🟡 Hex-encoded Clarity values only |
+| `stx_signMessage` | 🟡 Hex-encoded Clarity values only | 🟡 Hex-encoded Clarity values only |
+| `stx_signStructuredMessage` | 🟡 Hex-encoded Clarity values only | 🟡 Hex-encoded Clarity values only |
+| `stx_updateProfile` | 🔴 | 🔴 |
+
+### Event Compatibility
+
+| Event | Leather | Xverse |
+| ------------------- | ------- | ------ |
+| `stx_accountChange` | 🔴 | 🔴 |
+| `stx_networkChange` | 🔴 | 🔴 |
+
+### Compatibility Layer
+
+The `request` method in `@stacks/connect` adds a layer of auto-compatibility for different wallet providers. This helps unify the interface where wallet providers may implement methods and results differently.
+
+* 🟢 No overrides needed for any wallet
+* 🔵 Has compatibility overrides that maintain functionality
+* 🟡 Has breaking overrides that may lose some information
+
+| Method | Status | Notes |
+| --------------------------- | ------ | ----------------------------------------------------------------------------------------- |
+| `getAddresses` | 🔵 | Maps to `wallet_connect` for Xverse-like wallets |
+| `sendTransfer` | 🔵 | Converts `amount` to number for Xverse, string for Leather |
+| `signPsbt` | 🟡 | Transforms PSBT format for Leather (base64 to hex) with lossy restructure of `signInputs` |
+| `stx_getAddresses` | 🔵 | Maps to `wallet_connect` for Xverse-like wallets |
+| `stx_callContract` | 🔵 | Transforms Clarity values to hex-encoded format for compatibility |
+| `stx_deployContract` | 🔵 | Transforms Clarity values to hex-encoded format for compatibility |
+| `stx_signTransaction` | 🔵 | Transforms Clarity values to hex-encoded format for compatibility |
+| `stx_signMessage` | 🔵 | Transforms Clarity values to hex-encoded format for compatibility |
+| `stx_signStructuredMessage` | 🔵 | Transforms Clarity values to hex-encoded format for compatibility |
diff --git a/docs/build/stacks-devtools-ecosystem.md b/docs/build/stacks-devtools-ecosystem.md
new file mode 100644
index 0000000000..a49dd0e169
--- /dev/null
+++ b/docs/build/stacks-devtools-ecosystem.md
@@ -0,0 +1,140 @@
+---
+description: A Devtools Catalog for Building with Stacks
+---
+
+# Stacks Devtools Ecosystem
+
+
+
+Discover the full range of developer tools available for building on Stacks.
+
+This page aggregates all open-sourced developer & experimental tools for building on Stacks. **Tools vary in scope, maturity, and maintenance status.** Whether you’re developing smart contracts, integrating wallets, querying blockchain data, or experimenting with new ideas, this page helps you find the resources to accelerate your projects and navigate the Stacks devtooling ecosystem.
+
+{% hint style="info" %}
+Official Stacks devtools are built and maintained by either **Stacks Labs** or **Hiro**.
+{% endhint %}
+
+### Smart Contract Development
+
+* [**Clarinet**](https://github.com/stx-labs/clarinet) **\[StacksLabs]** – A local Clarity smart contract development environment with testing and deployment tools, designed to help you build, debug, and iterate on Stacks contracts quickly.
+* [**Clarity Playground**](https://github.com/stx-labs/clarity-playground) **\[StacksLabs]** - Run Clarity code in the browser with the Clarinet SDK.
+* [**Clarity-Zed**](https://github.com/stx-labs/clarity-zed) **\[StacksLabs]** - Clarity Language Support for Zed editor.
+* [**Stacks Pyth Bridge**](https://github.com/stx-labs/stacks-pyth-bridge) **\[StacksLabs]** - The Pyth protocol integration is available as a beta on both testnet and mainnet networks for Stacks, to help developers test, give feedback, and ensure the reliability and stability of the integration.
+* [**Clarity-WASM**](https://github.com/stx-labs/clarity-wasm) **\[StacksLabs]** - `clar2wasm` is a compiler for generating WebAssembly from Clarity.
+
+
+
+Community & Experimental
+
+* [**Clarity Deployed Contracts**](https://github.com/boomcrypto/clarity-deployed-contracts) - Browse the source code of all deployed Clarity contracts on Stacks' mainnet and testnet.
+
+
+
+***
+
+### SDKs & Libraries
+
+* [**Stacks.js**](https://github.com/stx-labs/stacks.js) **\[StacksLabs]** – A JavaScript/Typescript library that makes it easy to interact with the Stacks blockchain, including authentication, transactions, and smart contract calls from web apps.
+* [**Clarity-Go**](https://github.com/stx-labs/clarity-go) **\[StacksLabs]** - A Go library for decoding Clarity values from their binary serialization format used by the Stacks blockchain.
+
+
+
+Community & Experimental
+
+* [**Clarigen**](https://www.clarigen.dev/) - Clarigen is a developer tool that automatically generates TypeScript-friendly clients that can interact with Clarity smart contracts.
+* [**Stacks.js Starters**](https://github.com/stx-labs/stacks.js-starters) **\[StacksLabs]** - Quickly bootstrap frontend applications with Stacks.js on top of multiple JavaScript frameworks as the foundation.
+* [**SecondLayer**](https://github.com/ryanwaits/secondlayer) - Generate fully typed contract interfaces, functions, and React hooks for Clarity smart contracts.
+* [**Clarity-types**](https://github.com/ryanwaits/clarity-types) - Strict TypeScript types for Clarity ABI properties and values.
+* [**Stacks Kit**](https://github.com/karkigrishmin/stacks-kit) - React toolkit for Stacks blockchain. Think RainbowKit, but for Bitcoin L2.
+* [**Stacks.rs**](https://github.com/52/stacks.rs) - A Rust toolkit to interact with the Stacks Blockchain.
+* [**StacksPy**](https://github.com/rohitverma007/stackspy) - Python Library to interact with the Stacks blockchain.
+* [**Bitcoin TX Proof**](https://github.com/kenrogers/bitcoin-tx-proof) - A TypeScript library for generating Bitcoin transaction proofs, including witness data and merkle proofs. This package helps developers verify Bitcoin transactions in Clarity.
+* [**Clarity Bitcoin Client**](https://github.com/BigMarketDao/clarity-bitcoin-client) - TypeScript library for interacting with the `clarity-bitcoin-lib` contract on Stacks.
+
+
+
+***
+
+### Indexing & Data
+
+* [**Stacks Blockchain APIs**](https://github.com/hirosystems/stacks-blockchain-api) **\[Hiro]** – High-performance APIs to query blockchain data, explore blocks, transactions, smart contracts, and more, without running your own node.
+* [**Token Metadata APIs**](https://github.com/hirosystems/token-metadata-api) **\[Hiro] -** Fetch metadata for every token on Stacks and effortlessly put tokens into your app. Verify and display tokens in your app, for everything from DeFi to NFTs.
+* [**Bitcoin Indexer**](https://github.com/hirosystems/bitcoin-indexer) **\[Hiro] -** Index Bitcoin meta-protocols like Ordinals, BRC-20, and Runes.
+* [**Chainhooks**](https://github.com/hirosystems/chainhook) **\[Hiro]** – A notification service for dApps that triggers webhooks on specific blockchain events, helping you respond to transactions, contract calls, and chain reorganizations in real time.
+
+
+
+Community & Experimental
+
+* [**Chainhooks-Go-Client**](https://github.com/tony1908/chainhooks-client-go) - A comprehensive Go client library for interacting with the Hiro Chainhooks API.
+* [**BNS**](https://www.bnsv2.com/docs) - [API](https://github.com/Strata-Labs/bnsv2-api) and [SDK](https://github.com/Strata-Labs/bns-v2-sdk) documentation for BNSv2, covering how to programmatically register, resolve, and manage Bitcoin Name System identities using on-chain contracts and developer libraries.
+* [**Signal21**](https://signal21.io/) - Data analytics platform for the Bitcoin Economy: on-chain visibility into Bitcoin L1, L2s, and Dapps.
+* [**Velar Devtools**](https://docs.velar.com/velar/developers) - Velar SDK and APIs allowing developers to implement token swaps, manage liquidity, and interact with the Velar DEX/DeFi ecosystem.
+* [**Bitflow Devtools**](https://docs.bitflow.finance/bitflow-documentation/developers/overview) - Documentation on Bitflow's SDKs and contracts for interacting with Bitflow's DeFi ecosystem.
+* [**x402-Stacks**](https://github.com/tony1908/x402Stacks) - A TypeScript library for implementing the x402 payment protocol on Stacks blockchain.
+* [**StacksAgent MCP**](https://github.com/kai-builder/stacksagent-mcp) - A Model Context Protocol (MCP) server that enables Claude Desktop to interact with the Stacks blockchain.
+* [**AIBTC**](https://github.com/aibtcdev) - AI agent tooling for Stacks.
+
+
+
+***
+
+### Testing & Simulation
+
+* [**Rendezvous**](https://stacks-network.github.io/rendezvous/) - A smart contract fuzzer for Clarity.
+
+***
+
+### Wallet & Auth
+
+* [**Stacks Connect**](https://github.com/stx-labs/connect) **\[StacksLabs]** – A protocol-agnostic wallet integration library that enables apps to securely connect with multiple Stacks wallets without reinventing the onboarding flow.
+
+
+
+Community & Experimental
+
+* [**Sign-In with Stacks**](https://github.com/pradel/sign-in-with-stacks/) - A library for creating and verifying Sign-In with Stacks messages.
+* [**sBTC Pay**](https://github.com/STX-CITY/sbtc-pay) - A complete "Stripe for sBTC" payment gateway that enables businesses to easily accept Bitcoin payments via sBTC on Stacks blockchain.
+* [**Bolt Protocol**](https://github.com/ronoel/bolt-protocol) - Bolt Protocol is a next-generation framework designed to enable near-instant transactions on the Bitcoin network and enable users to pay fees directly in sBTC.
+
+
+
+***
+
+### Monitoring & Analytics
+
+* [**Explorer**](https://github.com/stx-labs/explorer) **\[StacksLabs] -** Explore transactions and accounts on the Stacks blockchain. Clone any contract and experiment in your browser with the Explorer sandbox.
+* [**Platform**](https://www.hiro.so/platform) **\[Hiro]** – Manage API keys, Chainhooks, and analyze onchain data streams in one command center. Also houses ready-to-use starter templates for different use case applications.
+
+
+
+Community & Experimental
+
+* [**STXER**](https://stxer.xyz/) - Community built explorer, debugger and simulator for Stacks transactions.
+
+
+
+***
+
+### Docs & Education
+
+* [**Hiro Docs**](https://docs.hiro.so/) **\[Hiro]** - Official Hiro developer documentation website.
+* [**Stacks Docs**](https://docs.stacks.co/) **\[StacksLabs]** - Official Stacks developer documentation website.
+* [**SIPs**](https://github.com/stacksgov/sips) - Community-submitted Stacks Improvement Proposals (SIPs).
+
+### Core
+
+* [**Stacks Core**](https://github.com/stacks-network/stacks-core) **\[StacksLabs]** - Reference implementation of the Stacks blockchain in Rust.
+* [**Stacks Blockchain Docker**](https://github.com/stacks-network/stacks-blockchain-docker) **\[StacksLabs]** - Run your own Stacks Blockchain node with Docker.
+
+
+
+Community & Experimental
+
+* [**Stacks-Monitoring**](https://github.com/alexlmiller/stacks-monitoring) - Observability stack for Stacks blockchain nodes and signers - dashboards, alerts, and log processing.
+
+
+
+***
+
+If you’ve built a Stacks devtool you’d like included, reach out to us via GitHub or Discord with a brief description and link, and we’ll review it for addition to this devtools list.
diff --git a/docs/build/stacks.js/accounts-and-addresses.md b/docs/build/stacks.js/accounts-and-addresses.md
new file mode 100644
index 0000000000..8fdb78fbdd
--- /dev/null
+++ b/docs/build/stacks.js/accounts-and-addresses.md
@@ -0,0 +1,182 @@
+# Accounts & Addresses
+
+Stacks uses the concept of an "account" to represent a user's identity on the blockchain. An account is identified by a unique address derived from the account's public key.
+
+## Address formats
+
+Stacks addresses use different prefixes to indicate the network they belong to, making it easy to distinguish between mainnet and testnet addresses.
+
+```ts
+// Mainnet address starts with 'SP'
+const mainnetAddress = 'SP3FGQ8Z7JY9BWYZ5WM53E0M9NK7WHJF0691NZ159';
+
+// Testnet address starts with 'ST'
+const testnetAddress = 'ST2F4BK4GZH6YFBNHYDDGN4T1RKBA7DA1BJZPJEJJ';
+```
+
+The address format ensures that tokens on testnet cannot be accidentally sent to mainnet addresses and vice versa.
+
+## Getting an address
+
+There are several ways to obtain a Stacks address depending on your use case and what cryptographic material you have available.
+
+{% stepper %}
+{% step %}
+#### Using Stacks Connect
+
+When building user-facing applications, you'll typically get addresses from users who connect their wallets through Stacks Connect.
+
+```ts
+import { connect, getLocalStorage, request } from '@stacks/connect';
+
+async function handleWalletConnection() {
+ // Connect to wallet
+ const response = await connect();
+
+ // Get stored addresses
+ const data = getLocalStorage();
+ const stxAddresses = data.addresses.stx;
+
+ if (stxAddresses && stxAddresses.length > 0) {
+ const address = stxAddresses[0].address;
+ console.log('STX Address:', address);
+ // 'SP1MXSZF4NFC8JQ1TTYGEC2WADMC7Y3GHVZYRX6RF'
+ }
+
+ // Get detailed account info if needed
+ const accounts = await request('stx_getAccounts');
+ console.log('Account details:', accounts.addresses[0]);
+}
+```
+
+Stacks Connect stores the connected addresses in local storage, allowing your app to persist the connection across page reloads.
+{% endstep %}
+
+{% step %}
+#### Using a seed phrase
+
+For programmatic wallet generation or when restoring accounts from backup, you can derive addresses from a seed phrase (also known as a mnemonic).
+
+```ts
+import { generateWallet, generateSecretKey } from '@stacks/wallet-sdk';
+
+async function createWalletFromSeed() {
+ // Generate a new 24-word seed phrase
+ const secretKey = generateSecretKey();
+
+ // Or use an existing seed phrase
+ // const secretKey = 'already owned seed phrase ...';
+
+ const wallet = await generateWallet({
+ secretKey,
+ password: 'optional-encryption-password',
+ });
+
+ // Get the first account's address
+ const account = wallet.accounts[0];
+ const mainnetAddress = account.address;
+
+ console.log('Address:', mainnetAddress);
+ console.log('Private key:', account.stxPrivateKey);
+}
+```
+
+Each wallet can contain multiple accounts, all derived from the same seed phrase using different derivation paths.
+{% endstep %}
+
+{% step %}
+#### Using a private key
+
+If you already have a private key, you can directly derive the corresponding address without going through the wallet generation process.
+
+```ts
+import { privateKeyToAddress, TransactionVersion } from '@stacks/transactions';
+
+function getAddressFromPrivateKey() {
+ // Compressed private key (64 or 66 characters)
+ const privateKey = 'your-private-key-here';
+
+ // For mainnet
+ const mainnetAddress = privateKeyToAddress(
+ privateKey,
+ TransactionVersion.Mainnet
+ );
+
+ // For testnet
+ const testnetAddress = privateKeyToAddress(
+ privateKey,
+ TransactionVersion.Testnet
+ );
+
+ console.log('Mainnet:', mainnetAddress);
+ console.log('Testnet:', testnetAddress);
+}
+```
+
+The same private key will generate different addresses for mainnet and testnet due to the network-specific version bytes.
+{% endstep %}
+
+{% step %}
+#### Using a public key
+
+When you only have access to a public key (for example, in a watch-only wallet scenario), you can still derive the corresponding address.
+
+```ts
+import { publicKeyToAddress, TransactionVersion } from '@stacks/transactions';
+
+function getAddressFromPublicKey() {
+ // Compressed public key (66 characters starting with 02 or 03)
+ const publicKey = '03b3e0a76b292b2c83fc0ac14ae6160d0438ebe94e14bbb7d0ded3c217f3d29ba7';
+
+ // For mainnet
+ const mainnetAddress = publicKeyToAddress(
+ publicKey,
+ TransactionVersion.Mainnet
+ );
+
+ // For testnet
+ const testnetAddress = publicKeyToAddress(
+ publicKey,
+ TransactionVersion.Testnet
+ );
+
+ console.log('Mainnet:', mainnetAddress);
+ // 'SP1MXSZF4NFC8JQ1TTYGEC2WADMC7Y3GHVZYRX6RF'
+}
+```
+
+This is useful for creating watch-only wallets or verifying addresses without access to private keys.
+{% endstep %}
+{% endstepper %}
+
+## Address validation
+
+Before sending transactions, it's important to validate that addresses are properly formatted.
+
+```ts
+import { validateStacksAddress } from '@stacks/transactions';
+
+function isValidAddress(address: string): boolean {
+ try {
+ // Check if it's a valid mainnet address
+ if (address.startsWith('SP')) {
+ return validateStacksAddress(address);
+ }
+
+ // Check if it's a valid testnet address
+ if (address.startsWith('ST')) {
+ return validateStacksAddress(address);
+ }
+
+ return false;
+ } catch (error) {
+ return false;
+ }
+}
+
+// Examples
+console.log(isValidAddress('SP3FGQ8Z7JY9BWYZ5WM53E0M9NK7WHJF0691NZ159')); // true
+console.log(isValidAddress('invalid-address')); // false
+```
+
+Always validate addresses before using them in transactions to prevent loss of funds due to typos or formatting errors.
diff --git a/docs/build/stacks.js/address-validation.md b/docs/build/stacks.js/address-validation.md
new file mode 100644
index 0000000000..5cdc1b5b1a
--- /dev/null
+++ b/docs/build/stacks.js/address-validation.md
@@ -0,0 +1,585 @@
+# Address Validation
+
+Validate and format Stacks addresses and principals.
+
+## Overview
+
+Stacks addresses follow specific formats that differ between mainnet and testnet. Proper validation ensures your application handles addresses correctly, preventing loss of funds and improving user experience. This guide covers address validation, formatting, and conversion utilities.
+
+## Basic address validation
+
+Validate Stacks addresses:
+
+{% code title="basic-validation.ts" %}
+```ts
+import {
+ validateStacksAddress,
+ validateContractName
+} from '@stacks/transactions';
+
+// Validate standard addresses
+const isValidMainnet = validateStacksAddress('SP2J6Y09JMFWWZCT4VJX0BA5W7A9HZP5EX96Y6VZY');
+console.log('Valid mainnet:', isValidMainnet); // true
+
+const isValidTestnet = validateStacksAddress('ST2JHG361ZXG51QTKY2NQCVBPPRRE2KZB1HR05NNC');
+console.log('Valid testnet:', isValidTestnet); // true
+
+const isInvalid = validateStacksAddress('invalid-address');
+console.log('Valid:', isInvalid); // false
+
+// Validate contract names
+const validContract = validateContractName('my-contract');
+console.log('Valid contract name:', validContract); // true
+
+const invalidContract = validateContractName('My Contract!');
+console.log('Valid contract name:', invalidContract); // false
+```
+{% endcode %}
+
+## Address types and detection
+
+Identify address types and networks:
+
+{% code title="address-info.ts" %}
+```ts
+import {
+ getAddressFromPrivateKey,
+ getAddressFromPublicKey,
+ TransactionVersion
+} from '@stacks/transactions';
+
+// Detect address type from prefix
+function getAddressInfo(address: string): {
+ type: 'standard' | 'contract' | 'multisig' | 'invalid';
+ network: 'mainnet' | 'testnet' | 'unknown';
+} {
+ if (!validateStacksAddress(address)) {
+ return { type: 'invalid', network: 'unknown' };
+ }
+
+ // Mainnet prefixes
+ if (address.startsWith('SP')) {
+ return { type: 'standard', network: 'mainnet' };
+ } else if (address.startsWith('SM')) {
+ return { type: 'multisig', network: 'mainnet' };
+ }
+
+ // Testnet prefixes
+ else if (address.startsWith('ST')) {
+ return { type: 'standard', network: 'testnet' };
+ } else if (address.startsWith('SN')) {
+ return { type: 'multisig', network: 'testnet' };
+ }
+
+ // Contract address (contains .)
+ if (address.includes('.')) {
+ const [principal] = address.split('.');
+ const info = getAddressInfo(principal);
+ return { ...info, type: 'contract' };
+ }
+
+ return { type: 'invalid', network: 'unknown' };
+}
+
+// Usage
+const info = getAddressInfo('SP2J6Y09JMFWWZCT4VJX0BA5W7A9HZP5EX96Y6VZY.my-contract');
+console.log(info); // { type: 'contract', network: 'mainnet' }
+```
+{% endcode %}
+
+## Address generation
+
+Generate addresses from keys:
+
+{% code title="address-generation.ts" %}
+```ts
+import {
+ makeRandomPrivKey,
+ getPublicKey,
+ getAddressFromPrivateKey,
+ getAddressFromPublicKey,
+ TransactionVersion,
+ AddressHashMode
+} from '@stacks/transactions';
+
+// Generate new random address
+function generateNewAddress(network: 'mainnet' | 'testnet') {
+ const privateKey = makeRandomPrivKey();
+ const publicKey = getPublicKey(privateKey);
+
+ const version = network === 'mainnet'
+ ? TransactionVersion.Mainnet
+ : TransactionVersion.Testnet;
+
+ const address = getAddressFromPrivateKey(privateKey, version);
+
+ return {
+ privateKey,
+ publicKey,
+ address,
+ };
+}
+
+// Generate address from existing private key
+function getAddressFromKey(privateKey: string, network: 'mainnet' | 'testnet') {
+ const version = network === 'mainnet'
+ ? TransactionVersion.Mainnet
+ : TransactionVersion.Testnet;
+
+ return getAddressFromPrivateKey(privateKey, version);
+}
+
+// Generate multisig address
+function generateMultisigAddress(
+ publicKeys: string[],
+ signaturesRequired: number,
+ network: 'mainnet' | 'testnet'
+) {
+ const version = network === 'mainnet'
+ ? TransactionVersion.Mainnet
+ : TransactionVersion.Testnet;
+
+ const hashMode = AddressHashMode.SerializeP2SH;
+
+ // Implementation depends on multisig setup
+ // This is a simplified example
+ return getAddressFromPublicKey(
+ publicKeys[0], // Simplified - real implementation needs all keys
+ version,
+ hashMode
+ );
+}
+```
+{% endcode %}
+
+## Contract address handling
+
+Work with contract principals:
+
+{% code title="contract-address.ts" %}
+```ts
+// Parse contract address components
+function parseContractAddress(contractAddress: string): {
+ principal: string;
+ contractName: string;
+ isValid: boolean;
+} {
+ const parts = contractAddress.split('.');
+
+ if (parts.length !== 2) {
+ return { principal: '', contractName: '', isValid: false };
+ }
+
+ const [principal, contractName] = parts;
+
+ const isValid = validateStacksAddress(principal) &&
+ validateContractName(contractName);
+
+ return { principal, contractName, isValid };
+}
+
+// Build contract address
+function buildContractAddress(principal: string, contractName: string): string {
+ if (!validateStacksAddress(principal)) {
+ throw new Error('Invalid principal address');
+ }
+
+ if (!validateContractName(contractName)) {
+ throw new Error('Invalid contract name');
+ }
+
+ return `${principal}.${contractName}`;
+}
+
+// Validate full contract identifier
+function validateContractAddress(address: string): boolean {
+ const { isValid } = parseContractAddress(address);
+ return isValid;
+}
+
+// Usage
+const parsed = parseContractAddress('SP2J6Y09JMFWWZCT4VJX0BA5W7A9HZP5EX96Y6VZY.my-token');
+console.log(parsed);
+// { principal: 'SP2J6...', contractName: 'my-token', isValid: true }
+```
+{% endcode %}
+
+## Address conversion utilities
+
+Convert between formats and networks:
+
+{% code title="conversion-utils.ts" %}
+```ts
+import { c32addressDecode, c32address } from 'c32check';
+
+// Convert between testnet and mainnet addresses
+function convertAddressNetwork(
+ address: string,
+ toNetwork: 'mainnet' | 'testnet'
+): string {
+ try {
+ // Decode the address
+ const decoded = c32addressDecode(address);
+
+ // Determine new version
+ let newVersion: number;
+ if (toNetwork === 'mainnet') {
+ newVersion = decoded[0] === 26 ? 22 : 20; // Multi-sig or standard
+ } else {
+ newVersion = decoded[0] === 22 ? 26 : 21; // Multi-sig or standard
+ }
+
+ // Re-encode with new version
+ const newAddress = c32address(newVersion, decoded[1]);
+ return newAddress;
+ } catch (error) {
+ throw new Error('Invalid address format');
+ }
+}
+
+// Extract address hash
+function getAddressHash(address: string): string {
+ const decoded = c32addressDecode(address);
+ return Buffer.from(decoded[1]).toString('hex');
+}
+
+// Check if addresses are same (ignoring network)
+function isSameAddress(addr1: string, addr2: string): boolean {
+ try {
+ const hash1 = getAddressHash(addr1);
+ const hash2 = getAddressHash(addr2);
+ return hash1 === hash2;
+ } catch {
+ return false;
+ }
+}
+```
+{% endcode %}
+
+## Advanced validation patterns
+
+### Comprehensive address validator
+
+Create a robust validation system:
+
+{% code title="address-validator.ts" %}
+```ts
+class AddressValidator {
+ private cache = new Map();
+
+ validate(address: string, options?: {
+ network?: 'mainnet' | 'testnet';
+ allowContracts?: boolean;
+ allowMultisig?: boolean;
+ }): { valid: boolean; reason?: string } {
+ // Check cache
+ const cacheKey = `${address}-${JSON.stringify(options)}`;
+ if (this.cache.has(cacheKey)) {
+ return { valid: this.cache.get(cacheKey)! };
+ }
+
+ // Basic validation
+ if (!validateStacksAddress(address)) {
+ return { valid: false, reason: 'Invalid address format' };
+ }
+
+ const info = getAddressInfo(address);
+
+ // Check network if specified
+ if (options?.network && info.network !== options.network) {
+ return {
+ valid: false,
+ reason: `Address is for ${info.network}, expected ${options.network}`
+ };
+ }
+
+ // Check contract addresses
+ if (info.type === 'contract' && !options?.allowContracts) {
+ return { valid: false, reason: 'Contract addresses not allowed' };
+ }
+
+ // Check multisig
+ if (info.type === 'multisig' && !options?.allowMultisig) {
+ return { valid: false, reason: 'Multisig addresses not allowed' };
+ }
+
+ // Cache result
+ this.cache.set(cacheKey, true);
+
+ return { valid: true };
+ }
+
+ validateBatch(addresses: string[], options?: any): Map {
+ const results = new Map();
+
+ for (const address of addresses) {
+ const { valid } = this.validate(address, options);
+ results.set(address, valid);
+ }
+
+ return results;
+ }
+}
+```
+{% endcode %}
+
+### Address formatting
+
+Format addresses for display:
+
+{% code title="format-address.tsx" %}
+```ts
+function formatAddress(
+ address: string,
+ options?: {
+ truncate?: boolean;
+ length?: number;
+ separator?: string;
+ }
+): string {
+ if (!validateStacksAddress(address)) {
+ return 'Invalid Address';
+ }
+
+ if (options?.truncate) {
+ const length = options.length || 8;
+ const start = address.slice(0, length);
+ const end = address.slice(-length);
+ const separator = options.separator || '...';
+ return `${start}${separator}${end}`;
+ }
+
+ return address;
+}
+
+// Format for display with copy functionality
+function AddressDisplay({ address }: { address: string }) {
+ const [copied, setCopied] = useState(false);
+
+ const formatted = formatAddress(address, {
+ truncate: true,
+ length: 6
+ });
+
+ const copyToClipboard = () => {
+ navigator.clipboard.writeText(address);
+ setCopied(true);
+ setTimeout(() => setCopied(false), 2000);
+ };
+
+ return (
+
+ {formatted}
+ {copied && ✓ Copied }
+
+ );
+}
+```
+{% endcode %}
+
+## Input validation hooks
+
+React hooks for address inputs:
+
+{% code title="useAddressInput.tsx" %}
+```ts
+import { useState, useCallback } from 'react';
+
+function useAddressInput(options?: {
+ network?: 'mainnet' | 'testnet';
+ allowContracts?: boolean;
+}) {
+ const [value, setValue] = useState('');
+ const [error, setError] = useState(null);
+ const [isValid, setIsValid] = useState(false);
+
+ const validate = useCallback((address: string) => {
+ if (!address) {
+ setError(null);
+ setIsValid(false);
+ return;
+ }
+
+ const validator = new AddressValidator();
+ const result = validator.validate(address, options);
+
+ setError(result.reason || null);
+ setIsValid(result.valid);
+ }, [options]);
+
+ const handleChange = useCallback((newValue: string) => {
+ setValue(newValue);
+ validate(newValue);
+ }, [validate]);
+
+ return {
+ value,
+ error,
+ isValid,
+ setValue: handleChange,
+ validate,
+ };
+}
+
+// Usage in component
+function AddressInput() {
+ const address = useAddressInput({
+ network: 'mainnet',
+ allowContracts: false
+ });
+
+ return (
+
+ address.setValue(e.target.value)}
+ placeholder="Enter Stacks address"
+ className={address.error ? 'error' : ''}
+ />
+ {address.error && (
+ {address.error}
+ )}
+
+ );
+}
+```
+{% endcode %}
+
+## Security considerations
+
+Implement secure address handling:
+
+{% code title="security.ts" %}
+```ts
+// Sanitize user input
+function sanitizeAddress(input: string): string {
+ // Remove whitespace and common separators
+ return input.trim().replace(/[\s\-_]/g, '');
+}
+
+// Verify address ownership
+async function verifyAddressOwnership(
+ address: string,
+ signature: string,
+ message: string
+): Promise {
+ try {
+ // Verify the signature matches the address
+ const verified = verifyMessageSignature({
+ message,
+ signature,
+ publicKey: await getPublicKeyFromAddress(address),
+ });
+
+ return verified;
+ } catch {
+ return false;
+ }
+}
+
+// Validate address for specific use case
+function validateRecipientAddress(
+ address: string,
+ options: {
+ blockList?: string[];
+ allowList?: string[];
+ requireMainnet?: boolean;
+ }
+): { valid: boolean; reason?: string } {
+ // Check blocklist
+ if (options.blockList?.includes(address)) {
+ return { valid: false, reason: 'Address is blocked' };
+ }
+
+ // Check allowlist
+ if (options.allowList && !options.allowList.includes(address)) {
+ return { valid: false, reason: 'Address not in allowlist' };
+ }
+
+ // Check network
+ const info = getAddressInfo(address);
+ if (options.requireMainnet && info.network !== 'mainnet') {
+ return { valid: false, reason: 'Mainnet address required' };
+ }
+
+ return { valid: true };
+}
+```
+{% endcode %}
+
+## Testing utilities
+
+Test address validation:
+
+{% code title="address-validation.test.ts" %}
+```ts
+import { describe, it, expect } from 'vitest';
+
+describe('Address validation', () => {
+ const validAddresses = [
+ 'SP2J6Y09JMFWWZCT4VJX0BA5W7A9HZP5EX96Y6VZY',
+ 'ST2JHG361ZXG51QTKY2NQCVBPPRRE2KZB1HR05NNC',
+ 'SP2J6Y09JMFWWZCT4VJX0BA5W7A9HZP5EX96Y6VZY.my-contract',
+ ];
+
+ const invalidAddresses = [
+ 'invalid',
+ 'SP2J6Y09JMFWWZCT4VJX0BA5W7A9HZP5EX96Y6VZ', // Too short
+ 'XP2J6Y09JMFWWZCT4VJX0BA5W7A9HZP5EX96Y6VZY', // Wrong prefix
+ 'SP2J6Y09JMFWWZCT4VJX0BA5W7A9HZP5EX96Y6VZY.', // Missing contract
+ ];
+
+ validAddresses.forEach(address => {
+ it(`should validate ${address}`, () => {
+ expect(validateStacksAddress(address)).toBe(true);
+ });
+ });
+
+ invalidAddresses.forEach(address => {
+ it(`should reject ${address}`, () => {
+ expect(validateStacksAddress(address)).toBe(false);
+ });
+ });
+});
+```
+{% endcode %}
+
+## Best practices
+
+* Always validate user input: Never trust addresses from users
+* Check network compatibility: Ensure addresses match your network
+* Handle edge cases: Contract addresses, multisig, etc.
+* Cache validation results: Avoid redundant validation
+* Provide clear error messages: Help users fix invalid inputs
+
+## Common mistakes
+
+Not checking network type:
+
+{% code title="bad-vs-good-network.ts" %}
+```ts
+// Bad: Accepting any valid address
+const isValid = validateStacksAddress(userInput);
+
+// Good: Checking network matches
+const info = getAddressInfo(userInput);
+if (info.network !== 'mainnet') {
+ throw new Error('Please use a mainnet address');
+}
+```
+{% endcode %}
+
+Assuming address format:
+
+{% code title="bad-vs-good-parse.ts" %}
+```ts
+// Bad: Assuming standard address
+const [principal, contract] = address.split('.');
+
+// Good: Proper validation
+const parsed = parseContractAddress(address);
+if (!parsed.isValid) {
+ throw new Error('Invalid contract address');
+}
+```
+{% endcode %}
diff --git a/docs/build/stacks.js/build-transactions.md b/docs/build/stacks.js/build-transactions.md
new file mode 100644
index 0000000000..f384996e91
--- /dev/null
+++ b/docs/build/stacks.js/build-transactions.md
@@ -0,0 +1,259 @@
+# Build Transactions
+
+Learn how to build transactions programmatically for complete control over blockchain interactions.
+
+## Objectives
+
+* Build signed transactions for immediate broadcast
+* Create unsigned transactions for multi-signature workflows
+* Implement sponsored transactions to pay fees for users
+
+## Transaction types
+
+Stacks supports five primary transaction types, each serving a specific purpose.
+
+```ts
+// STX Transfer - Send native tokens
+const stxTransfer = await makeSTXTokenTransfer(options);
+
+// Contract Deployment - Deploy Clarity contracts
+const deployment = await makeContractDeploy(options);
+
+// Contract Call - Execute contract functions
+const contractCall = await makeContractCall(options);
+
+// Each transaction type accepts similar base options:
+interface TransactionOptions {
+ senderKey: string; // Private key for signing
+ network: string; // 'mainnet' or 'testnet'
+ fee?: bigint; // Manual fee in microSTX
+ nonce?: bigint; // Manual nonce
+ anchorMode?: AnchorMode; // Block anchoring strategy
+}
+```
+
+## Building signed transactions
+
+Signed transactions are ready to broadcast immediately. The private key signs during creation.
+
+{% stepper %}
+{% step %}
+#### STX token transfer
+
+```ts
+import { makeSTXTokenTransfer, broadcastTransaction } from '@stacks/transactions';
+
+const transaction = await makeSTXTokenTransfer({
+ recipient: 'ST2CY5V39NHDPWSXMW9QDT3HC3GD6Q6XX4CFRK9AG',
+ amount: 1000000n, // 1 STX = 1,000,000 microSTX
+ senderKey: 'your-private-key-hex',
+ network: 'testnet',
+ memo: 'Payment for services', // Optional memo (max 34 bytes)
+});
+
+const result = await broadcastTransaction({ transaction });
+console.log('Transaction ID:', result.txid);
+```
+{% endstep %}
+
+{% step %}
+#### Smart contract deployment
+
+```ts
+import { makeContractDeploy, ClarityVersion } from '@stacks/transactions';
+
+const contractCode = `
+(define-public (say-hello)
+ (ok "Hello, Stacks!"))
+`;
+
+const transaction = await makeContractDeploy({
+ contractName: 'hello-world',
+ codeBody: contractCode,
+ senderKey: 'your-private-key-hex',
+ network: 'testnet',
+ clarityVersion: ClarityVersion.Clarity3,
+});
+
+const result = await broadcastTransaction({ transaction });
+```
+{% endstep %}
+
+{% step %}
+#### Contract function calls
+
+```ts
+import { makeContractCall, Cl } from '@stacks/transactions';
+
+const transaction = await makeContractCall({
+ contractAddress: 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM',
+ contractName: 'counter',
+ functionName: 'increment',
+ functionArgs: [Cl.uint(1)],
+ senderKey: 'your-private-key-hex',
+ network: 'testnet',
+});
+```
+{% endstep %}
+{% endstepper %}
+
+## Unsigned transactions
+
+Create unsigned transactions for multi-signature workflows or offline signing.
+
+```ts
+import { makeUnsignedSTXTokenTransfer, TransactionSigner } from '@stacks/transactions';
+import { publicKeyFromPrivate } from '@stacks/encryption';
+
+// Create unsigned transaction
+const publicKey = publicKeyFromPrivate('your-private-key');
+
+const unsignedTx = await makeUnsignedSTXTokenTransfer({
+ recipient: 'ST2CY5V39NHDPWSXMW9QDT3HC3GD6Q6XX4CFRK9AG',
+ amount: 1000000n,
+ publicKey,
+ network: 'testnet',
+});
+
+// Sign separately
+const signer = new TransactionSigner(unsignedTx);
+signer.signOrigin('your-private-key');
+
+const signedTx = signer.transaction;
+```
+
+## Sponsored transactions
+
+Let one account pay fees for another account's transaction.
+
+```ts
+// User creates sponsored transaction
+const userTx = await makeContractCall({
+ contractAddress: 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM',
+ contractName: 'my-contract',
+ functionName: 'transfer',
+ functionArgs: [Cl.principal('ST2CY5V39NHDPWSXMW9QDT3HC3GD6Q6XX4CFRK9AG')],
+ senderKey: 'user-private-key',
+ sponsored: true,
+ fee: 0n, // User doesn't pay
+ network: 'testnet',
+});
+
+// Sponsor completes and pays
+import { sponsorTransaction } from '@stacks/transactions';
+
+const sponsoredTx = await sponsorTransaction({
+ transaction: userTx,
+ sponsorPrivateKey: 'sponsor-private-key',
+ fee: 2000n, // Sponsor pays the fee
+ network: 'testnet',
+});
+
+const result = await broadcastTransaction({ transaction: sponsoredTx });
+```
+
+## Multi-signature transactions
+
+Require multiple signatures for enhanced security.
+
+```ts
+// Create multi-sig transaction (2-of-3)
+const publicKeys = [publicKey1, publicKey2, publicKey3];
+
+const multiSigTx = await makeUnsignedSTXTokenTransfer({
+ recipient: 'ST2CY5V39NHDPWSXMW9QDT3HC3GD6Q6XX4CFRK9AG',
+ amount: 5000000n,
+ numSignatures: 2, // Require 2 of 3
+ publicKeys,
+ network: 'testnet',
+});
+
+// Collect signatures
+const signer = new TransactionSigner(multiSigTx);
+signer.signOrigin(privateKey1); // First signature
+signer.appendOrigin(privateKey2); // Second signature
+
+const signedTx = signer.transaction;
+```
+
+## Working with Clarity values
+
+Use the `Cl` helper for type-safe contract arguments.
+
+```ts
+import { Cl } from '@stacks/transactions';
+
+const functionArgs = [
+ // Primitives
+ Cl.uint(42),
+ Cl.int(-10),
+ Cl.bool(true),
+ Cl.stringUtf8('Hello 世界'),
+ Cl.stringAscii('Hello World'),
+
+ // Principals
+ Cl.standardPrincipal('ST2CY5V39NHDPWSXMW9QDT3HC3GD6Q6XX4CFRK9AG'),
+ Cl.contractPrincipal('ST123...', 'my-contract'),
+
+ // Composites
+ Cl.list([Cl.uint(1), Cl.uint(2), Cl.uint(3)]),
+ Cl.tuple({
+ name: Cl.stringUtf8('Alice'),
+ age: Cl.uint(30)
+ }),
+
+ // Optionals and responses
+ Cl.some(Cl.uint(42)),
+ Cl.none(),
+ Cl.ok(Cl.uint(200)),
+ Cl.err(Cl.uint(404))
+];
+```
+
+## Post-conditions
+
+Add safety constraints to protect users from unexpected transfers.
+
+```ts
+import { Pc, PostConditionMode } from '@stacks/transactions';
+
+const transaction = await makeContractCall({
+ // ... other options
+ postConditions: [
+ // Sender must send exactly 1 STX
+ Pc.principal('ST1ADDRESS...')
+ .willSendEq(1000000n)
+ .ustx(),
+
+ // Contract must transfer tokens
+ Pc.principal('ST2CONTRACT...')
+ .willSendGte(100n)
+ .ft('ST2CONTRACT.token-contract', 'my-token')
+ ],
+ postConditionMode: PostConditionMode.Deny, // Strict mode
+});
+```
+
+## Fee estimation
+
+Get accurate fee estimates before broadcasting.
+
+```ts
+import { estimateFee } from '@stacks/transactions';
+
+// Build transaction first
+const tx = await makeSTXTokenTransfer({
+ recipient: 'ST2CY5V39NHDPWSXMW9QDT3HC3GD6Q6XX4CFRK9AG',
+ amount: 1000000n,
+ senderKey: privateKey,
+ network: 'testnet',
+ fee: 1n, // Minimal fee for estimation
+});
+
+// Estimate appropriate fee
+const feeRate = await estimateFee(tx);
+tx.setFee(feeRate);
+
+// Now broadcast with accurate fee
+const result = await broadcastTransaction({ transaction: tx });
+```
diff --git a/docs/build/stacks.js/contract-calls.md b/docs/build/stacks.js/contract-calls.md
new file mode 100644
index 0000000000..6fb3b0cc07
--- /dev/null
+++ b/docs/build/stacks.js/contract-calls.md
@@ -0,0 +1,229 @@
+# Contract Calls
+
+Contract calls allow you to execute state-changing functions in smart contracts. Unlike read-only calls, these create transactions that must be signed and broadcast to the network.
+
+## Basic contract call
+
+Execute a simple contract function by creating a transaction with the required parameters.
+
+```ts
+import {
+ makeContractCall,
+ broadcastTransaction,
+ AnchorMode
+} from '@stacks/transactions';
+
+async function callContract() {
+ const txOptions = {
+ contractAddress: 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM',
+ contractName: 'my-contract',
+ functionName: 'transfer',
+ functionArgs: [],
+ senderKey: 'your-private-key',
+ network: 'testnet',
+ anchorMode: AnchorMode.Any,
+ };
+
+ const transaction = await makeContractCall(txOptions);
+ const broadcastResponse = await broadcastTransaction({ transaction });
+
+ console.log('Transaction ID:', broadcastResponse.txid);
+}
+```
+
+The `makeContractCall` function creates a transaction that will execute the specified function when confirmed on-chain.
+
+## Passing function arguments
+
+Most contract functions require arguments. Use Clarity value constructors to match the expected parameter types.
+
+```ts
+import {
+ Cl,
+ makeContractCall,
+} from '@stacks/transactions';
+
+const functionArgs = [
+ Cl.principal('ST2CY5V39NHDPWSXMW9QDT3HC3GD6Q6XX4CFRK9AG'), // recipient
+ Cl.uint(1000000), // amount
+ Cl.buffer(Buffer.from('Transfer memo', 'utf-8')), // memo
+];
+
+const txOptions = {
+ contractAddress: 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM',
+ contractName: 'sip-010-token',
+ functionName: 'transfer',
+ functionArgs,
+ senderKey: 'your-private-key',
+ network: "testnet",
+};
+
+const transaction = await makeContractCall(txOptions);
+const result = await broadcastTransaction({ transaction });
+console.log('Transaction ID:', result.txid);
+```
+
+Each Clarity type has a corresponding constructor function that ensures proper encoding for the blockchain.
+
+### Complex argument types
+
+```ts
+// Tuple arguments
+const userInfo = Cl.tuple({
+ name: Cl.string('Alice'),
+ age: Cl.uint(30),
+ active: Cl.bool(true),
+});
+
+// List arguments
+const addresses = Cl.list([
+ Cl.principal('ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM'),
+ Cl.principal('ST2CY5V39NHDPWSXMW9QDT3HC3GD6Q6XX4CFRK9AG'),
+]);
+```
+
+Optional and response values have dedicated constructors for proper type safety.
+
+```ts
+// Optional values
+const optionalValue = Cl.some(Cl.uint(42)); // (some 42)
+const noValue = Cl.none(); // none
+
+// Response values
+const successResponse = Cl.ok(Cl.uint(100));
+const errorResponse = Cl.err(Cl.uint(404));
+```
+
+## Contract call with STX transfer
+
+Some contracts require STX to be sent along with the function call, such as when minting NFTs or paying for services.
+
+```ts
+async function mintNFT() {
+ const mintPrice = 1000000; // 1 STX
+
+ const txOptions = {
+ contractAddress: 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM',
+ contractName: 'nft-collection',
+ functionName: 'mint',
+ functionArgs: [],
+ senderKey: 'your-private-key',
+ network: new StacksTestnet(),
+ anchorMode: AnchorMode.Any,
+ // Attach STX to the contract call
+ amount: mintPrice,
+ };
+
+ const transaction = await makeContractCall(txOptions);
+ return broadcastTransaction(transaction, network);
+}
+```
+
+## Handling contract responses
+
+Process transaction results and contract responses:
+
+```ts
+async function executeAndMonitor() {
+ // Execute contract call
+ const transaction = await makeContractCall({
+ contractAddress: 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM',
+ contractName: 'my-contract',
+ functionName: 'process',
+ functionArgs: [uintCV(100)],
+ senderKey: 'your-private-key',
+ network: new StacksTestnet(),
+ anchorMode: AnchorMode.Any,
+ });
+
+ const broadcastResponse = await broadcastTransaction(transaction, network);
+ const txId = broadcastResponse.txid;
+
+ // Wait for confirmation
+ const txInfo = await waitForConfirmation(txId, network);
+
+ // Check transaction result
+ if (txInfo.tx_status === 'success') {
+ console.log('Contract returned:', txInfo.tx_result);
+ // Parse the result based on expected return type
+ } else {
+ console.error('Transaction failed:', txInfo.tx_result);
+ }
+}
+
+async function waitForConfirmation(txId: string, network: StacksNetwork) {
+ let attempts = 0;
+ const maxAttempts = 30;
+
+ while (attempts < maxAttempts) {
+ const response = await fetch(
+ `${network.coreApiUrl}/extended/v1/tx/${txId}`
+ );
+ const txInfo = await response.json();
+
+ if (txInfo.tx_status === 'success' || txInfo.tx_status === 'abort_by_response') {
+ return txInfo;
+ }
+
+ await new Promise(resolve => setTimeout(resolve, 10000));
+ attempts++;
+ }
+
+ throw new Error('Transaction confirmation timeout');
+}
+```
+
+## Multi-step contract interactions
+
+{% stepper %}
+{% step %}
+#### Approve spending
+
+First, create and broadcast an approval transaction.
+
+```ts
+const approveTx = await makeContractCall({
+ contractAddress: 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM',
+ contractName: 'token',
+ functionName: 'approve',
+ functionArgs: [
+ standardPrincipalCV('ST2CY5V39NHDPWSXMW9QDT3HC3GD6Q6XX4CFRK9AG'),
+ uintCV(1000000),
+ ],
+ senderKey: 'your-private-key',
+ network: new StacksTestnet(),
+ anchorMode: AnchorMode.Any,
+});
+
+const approveResult = await broadcastTransaction(approveTx, network);
+await waitForConfirmation(approveResult.txid, network);
+```
+
+This step ensures the spender is authorized before subsequent actions.
+{% endstep %}
+
+{% step %}
+#### Execute swap after approval
+
+After the approval is confirmed, execute the swap transaction.
+
+```ts
+const swapTx = await makeContractCall({
+ contractAddress: 'ST2CY5V39NHDPWSXMW9QDT3HC3GD6Q6XX4CFRK9AG',
+ contractName: 'dex',
+ functionName: 'swap-tokens',
+ functionArgs: [
+ standardPrincipalCV('ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM'),
+ uintCV(1000000),
+ ],
+ senderKey: 'your-private-key',
+ network: new StacksTestnet(),
+ anchorMode: AnchorMode.Any,
+});
+
+return broadcastTransaction(swapTx, network);
+```
+
+This step performs the token swap that depends on the prior approval.
+{% endstep %}
+{% endstepper %}
diff --git a/docs/build/stacks.js/contract-deployment.md b/docs/build/stacks.js/contract-deployment.md
new file mode 100644
index 0000000000..57bb015df5
--- /dev/null
+++ b/docs/build/stacks.js/contract-deployment.md
@@ -0,0 +1,46 @@
+# Contract Deployment
+
+Deploy smart contracts to the Stacks blockchain.
+
+## Overview
+
+Contract deployment creates new smart contracts on the blockchain. Stacks.js provides tools to compile, deploy, and verify Clarity contracts programmatically. Deployments can be simple single contracts or complex multi-contract systems with dependencies.
+
+## Basic contract deployment
+
+Deploy a simple smart contract:
+
+{% code title="deploy.ts" %}
+```ts
+import {
+ makeContractDeploy,
+ broadcastTransaction,
+ AnchorMode
+} from '@stacks/transactions';
+import { STACKS_TESTNET } from '@stacks/network';
+import { readFileSync } from 'fs';
+
+async function deployContract() {
+ const network = new StacksTestnet();
+
+ // Read contract source code
+ const contractSource = readFileSync('./contracts/my-contract.clar', 'utf-8');
+
+ const txOptions = {
+ contractName: 'my-contract',
+ codeBody: contractSource,
+ senderKey: 'your-private-key',
+ network,
+ anchorMode: AnchorMode.Any,
+ fee: 10000, // Higher fee for deployment
+ };
+
+ const transaction = await makeContractDeploy(txOptions);
+ const broadcastResponse = await broadcastTransaction(transaction, network);
+
+ console.log('Contract deployed!');
+ console.log('Transaction ID:', broadcastResponse.txid);
+ console.log('Contract address:', `${senderAddress}.${txOptions.contractName}`);
+}
+```
+{% endcode %}
diff --git a/docs/build/stacks.js/encoding-and-decoding.md b/docs/build/stacks.js/encoding-and-decoding.md
new file mode 100644
index 0000000000..c2b1db8c39
--- /dev/null
+++ b/docs/build/stacks.js/encoding-and-decoding.md
@@ -0,0 +1,557 @@
+# Encoding & Decoding
+
+Convert between Clarity values and JavaScript types.
+
+## Overview
+
+Stacks uses Clarity values (CVs) to represent data in smart contracts. When building applications, you'll need to encode JavaScript values into CVs for contract calls and decode CVs back to JavaScript for display. This guide covers all CV types and conversion patterns.
+
+## Basic type conversions
+
+### Integers
+
+Convert between JavaScript numbers and Clarity integers:
+
+{% code title="integers.ts" %}
+```ts
+import {
+ intCV,
+ uintCV,
+ cvToValue,
+ cvToJSON
+} from '@stacks/transactions';
+
+// Encoding
+const positiveInt = uintCV(42); // u42
+const negativeInt = intCV(-100); // -100
+const largeUint = uintCV(1000000); // u1000000
+
+// Decoding
+const jsValue = cvToValue(positiveInt); // 42
+const jsonValue = cvToJSON(positiveInt); // { type: 'uint', value: '42' }
+
+// Working with BigInt for large numbers
+const bigNumber = uintCV(BigInt('123456789012345678901234567890'));
+const decoded = cvToValue(bigNumber); // '123456789012345678901234567890'
+```
+{% endcode %}
+
+### Booleans
+
+Simple true/false values:
+
+{% code title="booleans.ts" %}
+```ts
+import { trueCV, falseCV, boolCV } from '@stacks/transactions';
+
+// Encoding
+const clarityTrue = trueCV(); // true
+const clarityFalse = falseCV(); // false
+const fromBoolean = boolCV(true); // true
+
+// Decoding
+const jsBoolean = cvToValue(clarityTrue); // true
+```
+{% endcode %}
+
+### Strings
+
+Handle ASCII and UTF-8 strings:
+
+{% code title="strings.ts" %}
+```ts
+import {
+ stringAsciiCV,
+ stringUtf8CV,
+ cvToString
+} from '@stacks/transactions';
+
+// ASCII strings (limited character set)
+const asciiString = stringAsciiCV('Hello World');
+const asciiDecoded = cvToValue(asciiString); // 'Hello World'
+
+// UTF-8 strings (full Unicode support)
+const utf8String = stringUtf8CV('Hello 世界! 🌍');
+const utf8Decoded = cvToValue(utf8String); // 'Hello 世界! 🌍'
+
+// Direct string extraction
+const directString = cvToString(utf8String); // 'Hello 世界! 🌍'
+```
+{% endcode %}
+
+### Principals
+
+Encode Stacks addresses and contract principals:
+
+{% code title="principals.ts" %}
+```ts
+import {
+ standardPrincipalCV,
+ contractPrincipalCV,
+ cvToValue
+} from '@stacks/transactions';
+
+// Standard principal (user address)
+const userPrincipal = standardPrincipalCV('SP2J6Y09JMFWWZCT4VJX0BA5W7A9HZP5EX96Y6VZY');
+
+// Contract principal
+const contractPrincipal = contractPrincipalCV(
+ 'SP2J6Y09JMFWWZCT4VJX0BA5W7A9HZP5EX96Y6VZY',
+ 'my-contract'
+);
+
+// Decoding
+const address = cvToValue(userPrincipal);
+// 'SP2J6Y09JMFWWZCT4VJX0BA5W7A9HZP5EX96Y6VZY'
+
+const contract = cvToValue(contractPrincipal);
+// 'SP2J6Y09JMFWWZCT4VJX0BA5W7A9HZP5EX96Y6VZY.my-contract'
+```
+{% endcode %}
+
+## Complex type handling
+
+### Buffers
+
+Work with binary data:
+
+{% code title="buffers.ts" %}
+```ts
+import {
+ bufferCV,
+ bufferCVFromString,
+ cvToValue
+} from '@stacks/transactions';
+
+// From hex string
+const hexBuffer = bufferCV(Buffer.from('deadbeef', 'hex'));
+
+// From UTF-8 string
+const stringBuffer = bufferCVFromString('Hello Buffer');
+
+// From byte array
+const byteBuffer = bufferCV(new Uint8Array([1, 2, 3, 4]));
+
+// Decoding returns hex string
+const decoded = cvToValue(hexBuffer); // '0xdeadbeef'
+
+// Get raw buffer
+const rawBuffer = hexBuffer.buffer; // Buffer instance
+```
+{% endcode %}
+
+### Optional values
+
+Handle Clarity's optional type:
+
+{% code title="optional.ts" %}
+```ts
+import {
+ someCV,
+ noneCV,
+ cvToValue
+} from '@stacks/transactions';
+
+// Some value (contains a value)
+const someValue = someCV(uintCV(42)); // (some u42)
+const someString = someCV(stringUtf8CV('hi')); // (some u"hi")
+
+// None value (no value)
+const noneValue = noneCV(); // none
+
+// Decoding
+const decodedSome = cvToValue(someValue); // 42
+const decodedNone = cvToValue(noneValue); // null
+
+// Check optional type
+if (someValue.type === ClarityType.OptionalSome) {
+ const innerValue = cvToValue(someValue.value);
+}
+```
+{% endcode %}
+
+### Response values
+
+Handle contract response types:
+
+{% code title="response.ts" %}
+```ts
+import {
+ responseOkCV,
+ responseErrorCV,
+ cvToValue
+} from '@stacks/transactions';
+
+// Success response
+const okResponse = responseOkCV(uintCV(100)); // (ok u100)
+const okString = responseOkCV(stringUtf8CV('Success')); // (ok u"Success")
+
+// Error response
+const errorResponse = responseErrorCV(uintCV(404)); // (err u404)
+const errorMsg = responseErrorCV(stringUtf8CV('Not found')); // (err u"Not found")
+
+// Decoding and checking
+const result = okResponse;
+if (result.type === ClarityType.ResponseOk) {
+ console.log('Success:', cvToValue(result.value));
+} else {
+ console.log('Error:', cvToValue(result.value));
+}
+```
+{% endcode %}
+
+### Tuples
+
+Create and decode structured data:
+
+{% code title="tuple.ts" %}
+```ts
+import {
+ tupleCV,
+ cvToValue,
+ cvToJSON
+} from '@stacks/transactions';
+
+// Create tuple
+const userInfo = tupleCV({
+ id: uintCV(1),
+ name: stringUtf8CV('Alice'),
+ balance: uintCV(1000000),
+ active: trueCV(),
+ metadata: tupleCV({
+ created: uintCV(Date.now()),
+ tags: listCV([stringAsciiCV('user'), stringAsciiCV('premium')])
+ })
+});
+
+// Decode to JavaScript object
+const decoded = cvToValue(userInfo);
+// {
+// id: 1,
+// name: 'Alice',
+// balance: 1000000,
+// active: true,
+// metadata: {
+// created: 1234567890,
+// tags: ['user', 'premium']
+// }
+// }
+
+// Access tuple fields
+const nameCV = userInfo.data.name;
+const name = cvToValue(nameCV); // 'Alice'
+```
+{% endcode %}
+
+### Lists
+
+Work with arrays of values:
+
+{% code title="lists.ts" %}
+```ts
+import {
+ listCV,
+ cvToValue
+} from '@stacks/transactions';
+
+// List of same type
+const numbers = listCV([uintCV(1), uintCV(2), uintCV(3)]);
+const strings = listCV([
+ stringUtf8CV('apple'),
+ stringUtf8CV('banana'),
+ stringUtf8CV('cherry')
+]);
+
+// List of tuples (common pattern)
+const users = listCV([
+ tupleCV({ id: uintCV(1), name: stringUtf8CV('Alice') }),
+ tupleCV({ id: uintCV(2), name: stringUtf8CV('Bob') }),
+]);
+
+// Decoding
+const decodedNumbers = cvToValue(numbers); // [1, 2, 3]
+const decodedUsers = cvToValue(users);
+// [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }]
+
+// Iterate over list
+numbers.list.forEach((cv, index) => {
+ console.log(`Item ${index}:`, cvToValue(cv));
+});
+```
+{% endcode %}
+
+## Advanced encoding patterns
+
+### Dynamic type encoding
+
+Build encoders for runtime values:
+
+{% code title="dynamic-encoder.ts" %}
+```ts
+function encodeValue(value: any): ClarityValue {
+ if (typeof value === 'number') {
+ return value >= 0 ? uintCV(value) : intCV(value);
+ } else if (typeof value === 'string') {
+ // Check if valid ASCII
+ if (/^[\x00-\x7F]*$/.test(value)) {
+ return stringAsciiCV(value);
+ }
+ return stringUtf8CV(value);
+ } else if (typeof value === 'boolean') {
+ return boolCV(value);
+ } else if (value === null || value === undefined) {
+ return noneCV();
+ } else if (Array.isArray(value)) {
+ return listCV(value.map(encodeValue));
+ } else if (typeof value === 'object') {
+ const tupleData: { [key: string]: ClarityValue } = {};
+ for (const [key, val] of Object.entries(value)) {
+ tupleData[key] = encodeValue(val);
+ }
+ return tupleCV(tupleData);
+ }
+
+ throw new Error(`Cannot encode value: ${value}`);
+}
+
+// Usage
+const encoded = encodeValue({
+ name: 'Alice',
+ age: 30,
+ tags: ['user', 'admin'],
+ active: true
+});
+```
+{% endcode %}
+
+### Type-safe decoding
+
+Create decoders with type validation:
+
+{% code title="decode-user.ts" %}
+```ts
+interface UserData {
+ id: number;
+ name: string;
+ balance: number;
+ active: boolean;
+}
+
+function decodeUser(cv: ClarityValue): UserData {
+ if (cv.type !== ClarityType.Tuple) {
+ throw new Error('Expected tuple');
+ }
+
+ const data = cv.data;
+
+ // Validate and extract each field
+ if (!data.id || data.id.type !== ClarityType.UInt) {
+ throw new Error('Invalid id field');
+ }
+
+ if (!data.name || (
+ data.name.type !== ClarityType.StringASCII &&
+ data.name.type !== ClarityType.StringUTF8
+ )) {
+ throw new Error('Invalid name field');
+ }
+
+ return {
+ id: Number(cvToValue(data.id)),
+ name: cvToString(data.name),
+ balance: Number(cvToValue(data.balance)),
+ active: cvToValue(data.active) as boolean,
+ };
+}
+```
+{% endcode %}
+
+### Batch encoding utilities
+
+Encode multiple values efficiently:
+
+{% code title="clarity-encoder.ts" %}
+```ts
+class ClarityEncoder {
+ static encodeArray(
+ items: T[],
+ encoder: (item: T) => ClarityValue
+ ): ClarityValue {
+ return listCV(items.map(encoder));
+ }
+
+ static encodeTuple>(
+ obj: T,
+ schema: { [K in keyof T]: (value: T[K]) => ClarityValue }
+ ): TupleCV {
+ const tupleData: { [key: string]: ClarityValue } = {};
+
+ for (const [key, encoder] of Object.entries(schema)) {
+ tupleData[key] = encoder(obj[key as keyof T]);
+ }
+
+ return tupleCV(tupleData);
+ }
+
+ static encodeOptional(
+ value: T | null | undefined,
+ encoder: (value: T) => ClarityValue
+ ): OptionalCV {
+ if (value === null || value === undefined) {
+ return noneCV();
+ }
+ return someCV(encoder(value));
+ }
+}
+
+// Usage
+const users = [
+ { id: 1, name: 'Alice', balance: 1000 },
+ { id: 2, name: 'Bob', balance: 2000 },
+];
+
+const encoded = ClarityEncoder.encodeArray(users, user =>
+ ClarityEncoder.encodeTuple(user, {
+ id: (id) => uintCV(id),
+ name: (name) => stringUtf8CV(name),
+ balance: (balance) => uintCV(balance),
+ })
+);
+```
+{% endcode %}
+
+## Serialization and deserialization
+
+Work with serialized Clarity values:
+
+{% code title="serialization.ts" %}
+```ts
+import {
+ serializeCV,
+ deserializeCV,
+ cvToHex,
+ hexToCV
+} from '@stacks/transactions';
+
+// Serialize to buffer
+const cv = tupleCV({ amount: uintCV(1000), memo: stringUtf8CV('Payment') });
+const serialized = serializeCV(cv); // Buffer
+
+// Convert to hex for storage/transport
+const hex = cvToHex(cv); // '0x0c00000002046d656d6f...'
+
+// Deserialize from hex
+const deserialized = hexToCV(hex);
+const value = cvToValue(deserialized); // { amount: 1000, memo: 'Payment' }
+
+// Work with raw buffers
+const buffer = Buffer.from(hex, 'hex');
+const fromBuffer = deserializeCV(buffer);
+```
+{% endcode %}
+
+## Common conversion patterns
+
+### Contract call arguments
+
+Prepare arguments for contract calls:
+
+{% code title="prepare-args.ts" %}
+```ts
+function prepareTransferArgs(
+ recipient: string,
+ amount: number,
+ memo?: string
+): ClarityValue[] {
+ const args = [
+ standardPrincipalCV(recipient),
+ uintCV(amount),
+ ];
+
+ if (memo) {
+ args.push(someCV(stringUtf8CV(memo)));
+ } else {
+ args.push(noneCV());
+ }
+
+ return args;
+}
+
+// Usage in contract call
+const functionArgs = prepareTransferArgs(
+ 'SP2J6Y09JMFWWZCT4VJX0BA5W7A9HZP5EX96Y6VZY',
+ 1000000,
+ 'Monthly payment'
+);
+```
+{% endcode %}
+
+### Response handling
+
+Process contract responses:
+
+{% code title="handle-response.ts" %}
+```ts
+function handleContractResponse(response: ClarityValue): {
+ success: boolean;
+ data: any;
+ error?: string;
+} {
+ if (response.type === ClarityType.ResponseOk) {
+ return {
+ success: true,
+ data: cvToValue(response.value),
+ };
+ } else if (response.type === ClarityType.ResponseErr) {
+ const errorValue = cvToValue(response.value);
+ return {
+ success: false,
+ data: null,
+ error: typeof errorValue === 'string' ? errorValue : `Error: ${errorValue}`,
+ };
+ }
+
+ throw new Error('Invalid response type');
+}
+```
+{% endcode %}
+
+## Best practices
+
+{% hint style="info" %}
+* Validate types: Always check CV types before decoding
+* Handle edge cases: Consider null, undefined, and empty values
+* Use appropriate string types: ASCII for simple text, UTF-8 for international
+* Preserve precision: Use BigInt for large numbers
+* Type narrowing: Use TypeScript type guards for safety
+{% endhint %}
+
+## Common mistakes
+
+
+
+String type confusion
+
+```ts
+// Bad: Using ASCII for Unicode
+const bad = stringAsciiCV('Hello 世界'); // Will throw error
+
+// Good: Use UTF-8 for Unicode
+const good = stringUtf8CV('Hello 世界');
+```
+
+
+
+
+
+Number overflow
+
+```ts
+// Bad: JavaScript number too large
+const bad = uintCV(Number.MAX_SAFE_INTEGER + 1); // Precision loss
+
+// Good: Use BigInt
+const good = uintCV(BigInt('9007199254740992'));
+```
+
+
diff --git a/docs/build/stacks.js/network-configuration.md b/docs/build/stacks.js/network-configuration.md
new file mode 100644
index 0000000000..eba1caae70
--- /dev/null
+++ b/docs/build/stacks.js/network-configuration.md
@@ -0,0 +1,544 @@
+# Network Configuration
+
+Configure and customize Stacks network connections.
+
+## Overview
+
+Stacks.js supports multiple networks—mainnet for production, testnet for development, and custom networks for local testing. Proper network configuration ensures your app connects to the right blockchain instance with optimal settings.
+
+## Basic network setup
+
+Configure standard networks:
+
+```ts
+import {
+ StacksMainnet,
+ StacksTestnet,
+ StacksMocknet
+} from '@stacks/network';
+
+// Production network
+const mainnet = new StacksMainnet();
+console.log('Mainnet API:', mainnet.coreApiUrl);
+// https://api.hiro.so
+
+// Test network
+const testnet = new StacksTestnet();
+console.log('Testnet API:', testnet.coreApiUrl);
+// https://api.testnet.hiro.so
+
+// Local development network
+const mocknet = new StacksMocknet();
+console.log('Mocknet API:', mocknet.coreApiUrl);
+// http://localhost:3999
+```
+
+## Custom network configuration
+
+Create networks with custom endpoints:
+
+```ts
+import { StacksNetwork } from '@stacks/network';
+
+// Custom mainnet configuration
+const customMainnet = new StacksMainnet({
+ url: 'https://my-custom-node.com',
+ fetchFn: fetch, // Custom fetch implementation
+});
+
+// Custom testnet with specific endpoints
+const customTestnet = new StacksTestnet({
+ url: 'https://my-testnet-node.com:3999',
+});
+
+// Fully custom network
+class CustomNetwork extends StacksNetwork {
+ constructor() {
+ super({
+ url: 'https://custom-stacks-node.com',
+ networkType: 'mainnet', // or 'testnet', 'mocknet'
+ });
+ }
+
+ // Override methods as needed
+ getBroadcastApiUrl() {
+ return `${this.coreApiUrl}/custom/broadcast`;
+ }
+}
+```
+
+## Environment-based configuration
+
+Manage networks across environments:
+
+```ts
+// config/network.ts
+import {
+ StacksNetwork,
+ StacksMainnet,
+ StacksTestnet,
+ StacksMocknet
+} from '@stacks/network';
+
+interface NetworkConfig {
+ network: StacksNetwork;
+ apiUrl: string;
+ wsUrl?: string;
+ explorerUrl: string;
+ faucetUrl?: string;
+}
+
+const configs: Record = {
+ production: {
+ network: new StacksMainnet(),
+ apiUrl: 'https://api.hiro.so',
+ wsUrl: 'wss://api.hiro.so',
+ explorerUrl: 'https://explorer.hiro.so',
+ },
+ staging: {
+ network: new StacksTestnet(),
+ apiUrl: 'https://api.testnet.hiro.so',
+ wsUrl: 'wss://api.testnet.hiro.so',
+ explorerUrl: 'https://explorer.hiro.so/?chain=testnet',
+ faucetUrl: 'https://api.testnet.hiro.so/extended/v1/faucets/stx',
+ },
+ development: {
+ network: new StacksMocknet(),
+ apiUrl: 'http://localhost:3999',
+ explorerUrl: 'http://localhost:8000',
+ },
+};
+
+export function getNetworkConfig(): NetworkConfig {
+ const env = process.env.NODE_ENV || 'development';
+ return configs[env];
+}
+
+// Usage
+const { network, apiUrl } = getNetworkConfig();
+```
+
+## Network detection and validation
+
+Detect and validate network connections:
+
+```ts
+async function detectNetwork(url: string): Promise<'mainnet' | 'testnet' | 'unknown'> {
+ try {
+ const response = await fetch(`${url}/v2/info`);
+ const info = await response.json();
+
+ // Check network ID
+ if (info.network_id === 1) {
+ return 'mainnet';
+ } else if (info.network_id === 2147483648) {
+ return 'testnet';
+ }
+
+ return 'unknown';
+ } catch (error) {
+ console.error('Failed to detect network:', error);
+ return 'unknown';
+ }
+}
+
+// Validate network matches expectation
+async function validateNetwork(
+ network: StacksNetwork,
+ expected: 'mainnet' | 'testnet'
+): Promise {
+ const detected = await detectNetwork(network.coreApiUrl);
+
+ if (detected !== expected) {
+ console.warn(`Network mismatch! Expected ${expected}, got ${detected}`);
+ return false;
+ }
+
+ return true;
+}
+```
+
+## Advanced network features
+
+### Custom headers and authentication
+
+Add authentication or custom headers:
+
+```ts
+class AuthenticatedNetwork extends StacksMainnet {
+ private apiKey: string;
+
+ constructor(apiKey: string) {
+ super();
+ this.apiKey = apiKey;
+ }
+
+ createFetchFn(): FetchFn {
+ return (url: string, init?: RequestInit) => {
+ const headers = {
+ ...init?.headers,
+ 'x-api-key': this.apiKey,
+ 'x-client-version': '1.0.0',
+ };
+
+ return fetch(url, { ...init, headers });
+ };
+ }
+}
+
+// Usage
+const network = new AuthenticatedNetwork(process.env.API_KEY!);
+```
+
+### Request retry and timeout
+
+Implement resilient network requests:
+
+```ts
+class ResilientNetwork extends StacksTestnet {
+ private maxRetries = 3;
+ private timeout = 30000; // 30 seconds
+
+ createFetchFn(): FetchFn {
+ return async (url: string, init?: RequestInit) => {
+ for (let attempt = 0; attempt < this.maxRetries; attempt++) {
+ try {
+ const controller = new AbortController();
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
+
+ const response = await fetch(url, {
+ ...init,
+ signal: controller.signal,
+ });
+
+ clearTimeout(timeoutId);
+
+ if (!response.ok && attempt < this.maxRetries - 1) {
+ // Retry on server errors
+ if (response.status >= 500) {
+ await this.delay(1000 * Math.pow(2, attempt));
+ continue;
+ }
+ }
+
+ return response;
+ } catch (error) {
+ if (attempt === this.maxRetries - 1) throw error;
+ await this.delay(1000 * Math.pow(2, attempt));
+ }
+ }
+
+ throw new Error('Max retries exceeded');
+ };
+ }
+
+ private delay(ms: number): Promise {
+ return new Promise(resolve => setTimeout(resolve, ms));
+ }
+}
+```
+
+## Network-specific configurations
+
+### Configure by chain ID
+
+Set up network based on chain identifier:
+
+```ts
+function getNetworkByChainId(chainId: number): StacksNetwork {
+ switch (chainId) {
+ case 1: // Mainnet
+ return new StacksMainnet();
+ case 2147483648: // Testnet
+ return new StacksTestnet();
+ default:
+ throw new Error(`Unknown chain ID: ${chainId}`);
+ }
+}
+
+// Dynamic network from wallet
+async function getNetworkFromWallet(): Promise {
+ const userData = userSession.loadUserData();
+ const address = userData.profile.stxAddress.testnet;
+
+ // Determine network from address prefix
+ if (address.startsWith('SP') || address.startsWith('SM')) {
+ return new StacksMainnet();
+ } else if (address.startsWith('ST') || address.startsWith('SN')) {
+ return new StacksTestnet();
+ }
+
+ throw new Error('Unable to determine network from address');
+}
+```
+
+### Multi-network support
+
+Support multiple networks simultaneously:
+
+```ts
+class NetworkManager {
+ private networks: Map = new Map();
+ private currentNetwork: string = 'testnet';
+
+ constructor() {
+ this.networks.set('mainnet', new StacksMainnet());
+ this.networks.set('testnet', new StacksTestnet());
+ this.networks.set('devnet', new StacksMocknet());
+ }
+
+ getNetwork(name?: string): StacksNetwork {
+ const networkName = name || this.currentNetwork;
+ const network = this.networks.get(networkName);
+
+ if (!network) {
+ throw new Error(`Unknown network: ${networkName}`);
+ }
+
+ return network;
+ }
+
+ setCurrentNetwork(name: string): void {
+ if (!this.networks.has(name)) {
+ throw new Error(`Unknown network: ${name}`);
+ }
+ this.currentNetwork = name;
+ }
+
+ addCustomNetwork(name: string, url: string): void {
+ const network = new StacksNetwork({ url });
+ this.networks.set(name, network);
+ }
+}
+
+// Usage
+const manager = new NetworkManager();
+const mainnet = manager.getNetwork('mainnet');
+manager.setCurrentNetwork('mainnet');
+```
+
+## Network connection monitoring
+
+Monitor network health and status:
+
+```ts
+class NetworkMonitor {
+ private network: StacksNetwork;
+ private isHealthy = true;
+ private listeners: Set<(healthy: boolean) => void> = new Set();
+
+ constructor(network: StacksNetwork) {
+ this.network = network;
+ this.startMonitoring();
+ }
+
+ private async startMonitoring() {
+ setInterval(async () => {
+ try {
+ const response = await fetch(
+ `${this.network.coreApiUrl}/v2/info`,
+ { signal: AbortSignal.timeout(5000) }
+ );
+
+ const wasHealthy = this.isHealthy;
+ this.isHealthy = response.ok;
+
+ if (wasHealthy !== this.isHealthy) {
+ this.notifyListeners();
+ }
+ } catch (error) {
+ const wasHealthy = this.isHealthy;
+ this.isHealthy = false;
+
+ if (wasHealthy) {
+ this.notifyListeners();
+ }
+ }
+ }, 30000); // Check every 30 seconds
+ }
+
+ onHealthChange(callback: (healthy: boolean) => void): () => void {
+ this.listeners.add(callback);
+ return () => this.listeners.delete(callback);
+ }
+
+ private notifyListeners() {
+ this.listeners.forEach(callback => callback(this.isHealthy));
+ }
+
+ async waitForHealth(timeout = 60000): Promise {
+ const start = Date.now();
+
+ while (!this.isHealthy && Date.now() - start < timeout) {
+ await new Promise(resolve => setTimeout(resolve, 1000));
+ }
+
+ if (!this.isHealthy) {
+ throw new Error('Network unhealthy after timeout');
+ }
+ }
+}
+```
+
+## WebSocket configuration
+
+Set up real-time connections:
+
+```ts
+interface WebSocketConfig {
+ url: string;
+ reconnectInterval: number;
+ maxReconnectAttempts: number;
+}
+
+class StacksWebSocketClient {
+ private ws: WebSocket | null = null;
+ private config: WebSocketConfig;
+ private reconnectAttempts = 0;
+
+ constructor(network: StacksNetwork) {
+ this.config = {
+ url: this.getWebSocketUrl(network),
+ reconnectInterval: 5000,
+ maxReconnectAttempts: 10,
+ };
+ }
+
+ private getWebSocketUrl(network: StacksNetwork): string {
+ const apiUrl = network.coreApiUrl;
+ return apiUrl.replace('https://', 'wss://').replace('http://', 'ws://');
+ }
+
+ connect(): void {
+ this.ws = new WebSocket(this.config.url);
+
+ this.ws.onopen = () => {
+ console.log('WebSocket connected');
+ this.reconnectAttempts = 0;
+ };
+
+ this.ws.onclose = () => {
+ this.handleReconnect();
+ };
+
+ this.ws.onerror = (error) => {
+ console.error('WebSocket error:', error);
+ };
+ }
+
+ private handleReconnect(): void {
+ if (this.reconnectAttempts < this.config.maxReconnectAttempts) {
+ setTimeout(() => {
+ this.reconnectAttempts++;
+ this.connect();
+ }, this.config.reconnectInterval);
+ }
+ }
+
+ subscribe(event: string, callback: (data: any) => void): void {
+ if (!this.ws) throw new Error('WebSocket not connected');
+
+ this.ws.send(JSON.stringify({
+ method: 'subscribe',
+ params: { event }
+ }));
+
+ this.ws.onmessage = (message) => {
+ const data = JSON.parse(message.data);
+ if (data.event === event) {
+ callback(data);
+ }
+ };
+ }
+}
+```
+
+## Testing with different networks
+
+Set up tests across networks:
+
+```ts
+import { describe, it, beforeEach } from 'vitest';
+
+describe('Cross-network tests', () => {
+ const networks = [
+ { name: 'mainnet', network: new StacksMainnet() },
+ { name: 'testnet', network: new StacksTestnet() },
+ ];
+
+ networks.forEach(({ name, network }) => {
+ describe(`${name} tests`, () => {
+ it('should connect to network', async () => {
+ const response = await fetch(`${network.coreApiUrl}/v2/info`);
+ expect(response.ok).toBe(true);
+ });
+
+ it('should have correct chain ID', async () => {
+ const response = await fetch(`${network.coreApiUrl}/v2/info`);
+ const info = await response.json();
+
+ if (name === 'mainnet') {
+ expect(info.network_id).toBe(1);
+ } else {
+ expect(info.network_id).toBe(2147483648);
+ }
+ });
+ });
+ });
+});
+```
+
+## Best practices
+
+* Use environment variables: Never hardcode network URLs
+* Implement retry logic: Networks can be temporarily unavailable
+* Monitor connection health: Detect and handle network issues
+* Cache network info: Reduce redundant API calls
+* Validate network type: Ensure you're on the expected network
+
+## Common issues
+
+
+
+CORS errors
+
+```ts
+// Configure proxy for development
+const devNetwork = new StacksTestnet({
+ url: '/api', // Proxy through your dev server
+});
+
+// Or use CORS-enabled endpoints
+const corsNetwork = new StacksTestnet({
+ url: 'https://api.testnet.hiro.so',
+});
+```
+
+
+
+
+
+Timeout handling
+
+```ts
+// Add timeout to all requests
+class TimeoutNetwork extends StacksMainnet {
+ async fetchWithTimeout(url: string, timeout = 30000): Promise {
+ const controller = new AbortController();
+ const id = setTimeout(() => controller.abort(), timeout);
+
+ try {
+ const response = await fetch(url, {
+ signal: controller.signal,
+ });
+ clearTimeout(id);
+ return response;
+ } catch (error) {
+ clearTimeout(id);
+ throw new Error(`Request timeout: ${url}`);
+ }
+ }
+}
+```
+
+
diff --git a/docs/build/stacks.js/networks.md b/docs/build/stacks.js/networks.md
new file mode 100644
index 0000000000..c2faabd293
--- /dev/null
+++ b/docs/build/stacks.js/networks.md
@@ -0,0 +1,44 @@
+# Networks
+
+Typically, we speak of `mainnet` and `testnet` as the networks of Stacks. Most wallets are configured to `mainnet` by default—this is the production environment, the actual blockchain that holds real STX tokens.
+
+As the name suggests, `testnet` is a public network for testing. It's a separate blockchain state that holds test tokens, which have no value.
+
+For completeness we also mention `devnet`. This isn't "one" network, but how developers refer to ephemeral local networks used for testing. It is the same as `testnet`, but for local development. [Learn more](../../build/clarinet/local-blockchain-development.md).
+
+## Setting the network
+
+Most Stacks.js functions accept a `network` parameter or an optional last argument.
+
+The `network` type is a string, and can be one of:
+
+* `'mainnet'` (default)
+* `'testnet'`
+* `'devnet'`
+* `'mocknet'` (alias of `devnet`)
+
+### Examples
+
+Network in transaction signing:
+
+{% code title="transaction.ts" %}
+```ts
+const tx = makeSTXTokenTransfer({
+ // ...
+ network: 'testnet',
+});
+```
+{% endcode %}
+
+Network in address derivation:
+
+{% code title="address.ts" %}
+```ts
+const address = privateKeyToAddress(privateKey, 'devnet');
+// ST3NBRSFKX28FQ2ZJ1MAKX58HKHSDGNV5N7R21XCP
+```
+{% endcode %}
+
+{% hint style="info" %}
+For more advanced workflows, pass a custom network configuration object. See the `@stacks/network` package for details.
+{% endhint %}
diff --git a/docs/build/stacks.js/overview.md b/docs/build/stacks.js/overview.md
new file mode 100644
index 0000000000..6b41402101
--- /dev/null
+++ b/docs/build/stacks.js/overview.md
@@ -0,0 +1,84 @@
+# Overview
+
+source: Hiro blog
+
+## Overview
+
+Stacks.js is a collection of JavaScript libraries that enable you to build web applications on the Stacks blockchain. From wallet authentication to smart contract interactions.
+
+{% hint style="success" %}
+For the latest releases and versions of Stacks.js packages, check out its open-source repo [here](https://github.com/stx-labs/stacks.js).
+{% endhint %}
+
+## Key features
+
+* **Transaction construction** - Build and broadcast all transaction types with type-safe APIs
+* **Smart contract interaction** - Deploy contracts and call functions with automatic encoding
+* **Wallet integration** - Connect to Leather, Xverse, and other Stacks wallets seamlessly
+* **Post-conditions** - Protect users with built-in asset transfer validations
+
+## Installation
+
+Stacks.js is separated into focused packages published under the `@stacks` scope. Install only what you need:
+
+{% tabs %}
+{% tab title="Transactions" %}
+{% code title="terminal" %}
+```bash
+npm install @stacks/transactions
+```
+{% endcode %}
+{% endtab %}
+
+{% tab title="Wallet Connections" %}
+{% code title="terminal" %}
+```bash
+npm install @stacks/connect
+```
+{% endcode %}
+{% endtab %}
+
+{% tab title="Network Config" %}
+{% code title="terminal" %}
+```bash
+npm install @stacks/network
+```
+{% endcode %}
+{% endtab %}
+
+{% tab title="Common Utils" %}
+{% code title="terminal" %}
+```bash
+npm install @stacks/common
+```
+{% endcode %}
+{% endtab %}
+{% endtabs %}
+
+Other available packages include:
+
+* `@stacks/api`
+* `@stacks/auth`
+* `@stacks/encryption`
+* `@stacks/network`
+* `@stacks/stacking`
+* `@stacks/transactions`
+* `@stacks/bns`
+* `@stacks/common`
+* `@stacks/profile`
+* `@stacks/storage`
+* `@stacks/wallet-sdk`
+
+***
+
+{% hint style="info" %}
+Need help building with Stacks.js?
+
+Reach out to us on the **#stacks-js** channel on [Discord](https://stacks.chat/) under the Developer Tools section.
+{% endhint %}
+
+***
+
+### Additional Resources
+
+* \[[stacks.js.org](https://stacks.js.org/)] For a complete list of definitions on types, methods, classes, & etc.
diff --git a/docs/build/stacks.js/private-keys.md b/docs/build/stacks.js/private-keys.md
new file mode 100644
index 0000000000..11122b87a9
--- /dev/null
+++ b/docs/build/stacks.js/private-keys.md
@@ -0,0 +1,184 @@
+# Private Keys
+
+Stacks applications can work with two different account types: web wallets (like Hiro Wallet or Xverse) that users control, or local accounts you manage the private keys directly.
+
+## Web wallets (user-controlled)
+
+Most users interact with Stacks apps through web wallets, where the wallet handles all private key management and transaction signing.
+
+```ts
+import { connect } from '@stacks/connect';
+
+// Users connect their wallet
+const response = await connect();
+console.log('Connected addresses:', response.addresses);
+
+// The wallet handles all cryptographic operations
+// when signing transactions or messages
+```
+
+Use web wallets when building user-facing applications where users should maintain control of their keys.
+
+## Local accounts (application-controlled)
+
+Local accounts give your application direct control over private keys, enabling programmatic transaction signing without user interaction.
+
+```ts
+import { makeSTXTokenTransfer } from '@stacks/transactions';
+
+// Your application controls the private key
+const privateKey = 'your-private-key-here';
+
+const txOptions = {
+ recipient: 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM',
+ amount: 1000000n,
+ senderKey: privateKey, // Direct private key usage
+ network: 'testnet',
+};
+
+const transaction = await makeSTXTokenTransfer(txOptions);
+// Transaction is signed programmatically
+```
+
+Use local accounts for backend services, automated systems, or development tools that need to sign transactions without user interaction.
+
+## Working with private keys
+
+When building applications that use local accounts, you'll need to generate and manage private keys securely.
+
+### Generating random private keys
+
+Create a new private key for one-time use or testing purposes.
+
+```ts
+import { randomPrivateKey } from '@stacks/transactions';
+
+function generateNewAccount() {
+ const privateKey = randomPrivateKey();
+ console.log('Private key:', privateKey);
+ // 'f5a31c1268a1e37d4edaa05c7d11183c5fbf...'
+
+ // IMPORTANT: Store this securely!
+ // Anyone with this key can control the account
+ return privateKey;
+}
+```
+
+{% hint style="warning" %}
+Private keys in Stacks are 256-bit numbers, typically represented as 64-character hexadecimal strings. Anyone with the private key can control the account—store keys securely.
+{% endhint %}
+
+## Private key formats
+
+Stacks.js supports multiple private key formats for different use cases.
+
+```ts
+import { PrivateKey } from '@stacks/transactions';
+
+// Hex string format (most common)
+const hexKey = 'f5a31c1268a1e37d4edaa05c7d11183c5fbf...';
+
+// Compressed format with suffix
+const compressedKey = 'f5a31c1268a1e37d4edaa05c7d11183c5fbf...01';
+
+// Create from raw bytes
+const bytes = new Uint8Array(32); // 32 bytes = 256 bits
+crypto.getRandomValues(bytes);
+const privateKeyFromBytes = PrivateKey.fromBytes(bytes);
+```
+
+The compressed format includes a suffix byte (01) that indicates the key should use compressed public key encoding.
+
+## Wallet generation with seed phrases
+
+For better security and recoverability, use hierarchical deterministic (HD) wallets based on seed phrases.
+
+{% stepper %}
+{% step %}
+#### Generate a seed phrase
+
+Create a new 24-word mnemonic seed phrase that can regenerate all wallet accounts.
+
+```ts
+import { generateSecretKey } from '@stacks/wallet-sdk';
+
+function createNewWallet() {
+ const secretKey = generateSecretKey();
+ console.log('Seed phrase:', secretKey);
+ // "warrior volume sport ... figure cake since"
+
+ // Users should write this down and store it securely
+ // This phrase can regenerate all accounts in the wallet
+ return secretKey;
+}
+```
+
+{% hint style="warning" %}
+Seed phrases provide a human-readable backup that can restore an entire wallet hierarchy. Users should write this down and store it securely.
+{% endhint %}
+{% endstep %}
+
+{% step %}
+#### Create wallet from seed phrase
+
+Generate a complete wallet structure from a seed phrase, including multiple accounts.
+
+```ts
+import { generateWallet, generateSecretKey } from '@stacks/wallet-sdk';
+
+async function setupWallet() {
+ // Use existing seed phrase or generate new one
+ const seedPhrase = generateSecretKey();
+
+ const wallet = await generateWallet({
+ secretKey: seedPhrase,
+ password: 'optional-encryption-password',
+ });
+
+ // Access the first account
+ const account = wallet.accounts[0];
+ console.log('STX address:', account.address);
+ console.log('STX private key:', account.stxPrivateKey);
+ console.log('Data private key:', account.dataPrivateKey);
+
+ return wallet;
+}
+```
+
+Each wallet can contain multiple accounts, all derived from the same seed phrase but with different private keys.
+{% endstep %}
+
+{% step %}
+#### Managing multiple accounts
+
+HD wallets support multiple accounts from a single seed phrase, useful for organizing funds or separating concerns.
+
+```ts
+import { generateNewAccount, generateWallet, generateSecretKey } from '@stacks/wallet-sdk';
+
+async function createMultipleAccounts() {
+ const seedPhrase = generateSecretKey();
+
+ let wallet = await generateWallet({
+ secretKey: seedPhrase,
+ password: 'my-password',
+ });
+
+ console.log('Accounts:', wallet.accounts.length); // 1 (default)
+
+ // Add more accounts
+ wallet = generateNewAccount(wallet);
+ wallet = generateNewAccount(wallet);
+
+ console.log('Accounts:', wallet.accounts.length); // 3
+
+ // Each account has its own keys and address
+ wallet.accounts.forEach((account, index) => {
+ console.log(`Account ${index}:`, account.address);
+ });
+}
+```
+
+All accounts can be regenerated from the original seed phrase, making backup simple while maintaining separate addresses.
+{% endstep %}
+{% endstepper %}
diff --git a/docs/build/stacks.js/react-native-integration.md b/docs/build/stacks.js/react-native-integration.md
new file mode 100644
index 0000000000..45dfe7671b
--- /dev/null
+++ b/docs/build/stacks.js/react-native-integration.md
@@ -0,0 +1,289 @@
+# React Native Integration
+
+Stacks.js can be integrated into React Native applications to bring blockchain functionality to mobile devices. This tutorial walks you through setting up a React Native project with Expo and configuring it to work with Stacks.js libraries.
+
+## Objectives
+
+* Set up an Expo project configured for Stacks.js
+* Install and configure necessary polyfills for React Native
+* Generate wallets and sign transactions in a mobile app
+* Handle React Native's JavaScript environment limitations
+* Build a working Stacks mobile application
+
+## Prerequisites
+
+* Node.js and npm installed on your development machine
+* Basic knowledge of React Native and Expo
+* Familiarity with Stacks.js concepts
+* iOS or Android device or simulator for testing
+
+## Set up the Expo project
+
+Start by creating a new Expo project. The latest version of Expo provides the best compatibility with Stacks.js polyfills.
+
+```bash
+npx create-expo-app@latest my-stacks-app
+cd my-stacks-app
+```
+
+The boilerplate project includes everything needed to start building. Test the initial setup by running the development server.
+
+```bash
+npm start
+```
+
+Connect your mobile device using the Expo Go app and scan the QR code to verify the base project works correctly.
+
+## Install necessary dependencies
+
+React Native's JavaScript environment lacks certain Node.js and browser APIs that Stacks.js requires. Install the core Stacks libraries along with necessary polyfills.
+
+```bash
+npm install @stacks/transactions @stacks/wallet-sdk
+```
+
+Install the polyfill dependencies as dev dependencies to handle missing APIs.
+
+```bash
+npm install --save-dev buffer process react-native-get-random-values \
+ text-encoding readable-stream crypto-browserify @peculiar/webcrypto
+```
+
+These polyfills provide:
+
+* `buffer` and `process` for Node.js globals
+* `react-native-get-random-values` for crypto random values
+* `text-encoding` for `TextEncoder` and `TextDecoder`
+* `crypto-browserify` and `@peculiar/webcrypto` for cryptographic functions
+
+## Configure Metro bundler
+
+Metro bundler needs configuration to properly resolve Node.js modules. Create a custom Metro configuration file.
+
+```bash
+npx expo customize metro.config.js
+```
+
+Update `metro.config.js` to map Node.js modules to their React Native-compatible versions.
+
+```ts
+const { getDefaultConfig } = require('expo/metro-config');
+
+const config = getDefaultConfig(__dirname);
+
+config.resolver.extraNodeModules = {
+ stream: require.resolve('readable-stream'),
+ crypto: require.resolve('crypto-browserify'),
+};
+
+module.exports = config;
+```
+
+This configuration ensures that when Stacks.js requests Node.js modules, Metro provides the appropriate polyfills.
+
+## Set up global polyfills
+
+Create a polyfill system to make browser and Node.js APIs available in React Native. This requires modifying the app's entry point.
+
+### Create the polyfill file
+
+Create `polyfill.js` to initialize the required global objects.
+
+```ts
+import { Buffer } from 'buffer/';
+import process from 'process';
+import 'react-native-get-random-values';
+import { TextDecoder, TextEncoder } from 'text-encoding';
+
+global.process = process;
+global.Buffer = Buffer;
+global.TextEncoder = TextEncoder;
+global.TextDecoder = TextDecoder;
+```
+
+### Create a custom entry point
+
+Create `index.js` so the app loads polyfills before the UI renders.
+
+```ts
+import './polyfill';
+import { Crypto } from '@peculiar/webcrypto';
+
+Object.assign(global.crypto, new Crypto());
+
+import 'expo-router/entry';
+```
+
+{% hint style="warning" %}
+Runtime initialization errors: Polyfills must be loaded in separate files as shown. Loading them in the same file can cause runtime initialization errors.
+{% endhint %}
+
+### Update package.json
+
+Point the app to use the new entry point.
+
+```json
+{
+ "main": "index.js"
+}
+```
+
+## Implement Stacks functionality
+
+With the environment configured, you can now use Stacks.js in your React Native components. Update the main screen to demonstrate wallet generation and transaction signing.
+
+### Import Stacks.js modules
+
+Edit `app/(tabs)/index.tsx` to import the necessary Stacks.js functions.
+
+```ts
+import {
+ TransactionVersion,
+ getAddressFromPrivateKey,
+ makeSTXTokenTransfer,
+} from '@stacks/transactions';
+import { Wallet, generateSecretKey, generateWallet } from '@stacks/wallet-sdk';
+import { useState } from 'react';
+import { Button } from 'react-native';
+```
+
+### Set up component state
+
+Create state variables to manage wallet data and user feedback.
+
+```ts
+export default function HomeScreen() {
+ const [mnemonic, setMnemonic] = useState('Press button to generate');
+ const [wallet, setWallet] = useState(null);
+ const [log, setLog] = useState('');
+
+ // Component implementation continues...
+}
+```
+
+### Generate a wallet and sign a transaction
+
+Implement the core functionality to create a wallet and sign a transaction.
+
+```ts
+const generate = async () => {
+ try {
+ const mnemonic = generateSecretKey();
+ setMnemonic(mnemonic);
+
+ const wallet = await generateWallet({
+ secretKey: mnemonic,
+ password: '',
+ });
+ setWallet(wallet);
+
+ const txOptions = {
+ amount: 1000,
+ anchorMode: 'any' as const,
+ recipient: 'SP3W993D3BRDYB284CY3SBFDEGTC5XEDJPDEA21CN',
+ senderKey: wallet.accounts[0].stxPrivateKey,
+ fee: 300,
+ network: 'testnet' as const,
+ nonce: 0,
+ };
+
+ const transaction = await makeSTXTokenTransfer(txOptions);
+ setLog('Transaction signed successfully');
+ } catch (error) {
+ setLog(`Error: ${error.message}`);
+ }
+};
+```
+
+### Build the user interface
+
+Show wallet information and trigger wallet generation from the UI.
+
+```ts
+return (
+
+ Stacks Wallet Demo
+
+
+ Seed Phrase
+ {mnemonic}
+
+
+
+ {wallet && (
+
+ Wallet Address
+
+ {getAddressFromPrivateKey(
+ wallet.accounts[0].stxPrivateKey,
+ TransactionVersion.Testnet
+ )}
+
+
+ )}
+
+ {log && (
+
+ Status
+ {log}
+
+ )}
+
+);
+```
+
+## Test your implementation
+
+Run the app to verify everything works correctly.
+
+```bash
+npm start
+```
+
+{% stepper %}
+{% step %}
+#### Generate new wallet
+
+Press "Generate New Wallet". A new seed phrase appears.
+{% endstep %}
+
+{% step %}
+#### Wallet address
+
+After generation, the wallet address displays below.
+{% endstep %}
+
+{% step %}
+#### Sign transaction
+
+A transaction is signed (not broadcast) using the generated wallet.
+{% endstep %}
+
+{% step %}
+#### Confirm success
+
+A success message confirms signing.
+{% endstep %}
+{% endstepper %}
+
+{% hint style="info" %}
+Secure storage: For production apps, never display seed phrases directly. Use secure storage libraries such as `react-native-keychain` or `expo-secure-store`.
+{% endhint %}
+
+## Try it out
+
+Extend the basic implementation with additional features.
+
+```ts
+// Challenge: Add a function to check STX balance
+const checkBalance = async (address: string) => {
+ // Implement balance checking
+ // Hint: You'll need to use @stacks/blockchain-api-client
+};
+
+// Challenge: Implement transaction broadcasting
+const broadcastTransaction = async (transaction: StacksTransaction) => {
+ // Implement broadcasting logic
+ // Remember to handle network selection
+};
+```
diff --git a/docs/build/stacks.js/read-only-calls.md b/docs/build/stacks.js/read-only-calls.md
new file mode 100644
index 0000000000..9ab34cedc4
--- /dev/null
+++ b/docs/build/stacks.js/read-only-calls.md
@@ -0,0 +1,106 @@
+# Read Only Calls
+
+Read-only function calls allow you to query data from smart contracts without creating a transaction. These calls are free, instant, and don't require wallet interaction.
+
+## Basic read-only call
+
+Call a read-only function to get contract data without any transaction fees:
+
+```ts
+import { fetchCallReadOnlyFunction, cvToValue } from '@stacks/transactions';
+
+const contractAddress = 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM';
+const contractName = 'my-contract';
+const functionName = 'get-balance';
+
+const response = await fetchCallReadOnlyFunction({
+ contractAddress,
+ contractName,
+ functionName,
+ functionArgs: [],
+ senderAddress: 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM',
+});
+
+const balance = cvToValue(response);
+console.log('Balance:', balance);
+```
+
+## Passing function arguments
+
+Most read-only functions require arguments. Use Clarity value builders to construct the appropriate types:
+
+```ts
+import {
+ fetchCallReadOnlyFunction,
+ principalCV,
+ uintCV,
+ stringUtf8CV
+} from '@stacks/transactions';
+
+const functionArgs = [
+ principalCV('ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM'),
+ stringUtf8CV('admin')
+];
+
+const response = await fetchCallReadOnlyFunction({
+ contractAddress: 'ST2CY5V39NHDPWSXMW9QDT3HC3GD6Q6XX4CFRK9AG',
+ contractName: 'access-control',
+ functionName: 'has-role',
+ functionArgs,
+ senderAddress: 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM',
+});
+
+const hasRole = cvToValue(response);
+console.log('Has admin role:', hasRole);
+```
+
+## Handling response types
+
+Read-only functions can return response types (ok/err). Check the response type to handle both success and error cases:
+
+```ts
+import {
+ fetchCallReadOnlyFunction,
+ cvToJSON,
+ ResponseOkCV,
+ ResponseErrorCV
+} from '@stacks/transactions';
+
+const response = await fetchCallReadOnlyFunction({
+ contractAddress: 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM',
+ contractName: 'sip-010-token',
+ functionName: 'get-token-info',
+ functionArgs: [],
+ senderAddress: 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM',
+});
+
+if (response.type === 'ok') {
+ const tokenInfo = cvToJSON(response.value);
+ console.log('Token info:', tokenInfo);
+ // {
+ // name: "My Token",
+ // symbol: "MTK",
+ // decimals: 6,
+ // totalSupply: "1000000000000"
+ // }
+} else {
+ console.error('Error:', cvToValue(response.value));
+}
+```
+
+## Using custom network
+
+Specify a custom network URL for testnet or custom node connections:
+
+```ts
+import { fetchCallReadOnlyFunction } from '@stacks/transactions';
+
+const response = await fetchCallReadOnlyFunction({
+ contractAddress: 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM',
+ contractName: 'my-contract',
+ functionName: 'get-data',
+ functionArgs: [],
+ senderAddress: 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM',
+ network: 'testnet', // or custom URL like 'http://localhost:3999'
+});
+```
diff --git a/docs/build/stacks.js/unit-conversion.md b/docs/build/stacks.js/unit-conversion.md
new file mode 100644
index 0000000000..34d35d6bfb
--- /dev/null
+++ b/docs/build/stacks.js/unit-conversion.md
@@ -0,0 +1,226 @@
+# Unit Conversion
+
+Learn how to convert between different unit denominations in Stacks. The blockchain uses microSTX as its base unit, where 1 STX = 1,000,000 microSTX. Proper unit conversion is essential for displaying amounts to users and processing transactions.
+
+## Basic conversions
+
+Convert between STX and microSTX using simple conversion functions.
+
+{% code title="basic-conversions.ts" %}
+```ts
+// Convert STX to microSTX
+function stxToMicroStx(stx: number | string): bigint {
+ const stxAmount = typeof stx === 'string' ? parseFloat(stx) : stx;
+ return BigInt(Math.floor(stxAmount * 1_000_000));
+}
+
+// Convert microSTX to STX
+function microStxToStx(microStx: number | bigint | string): string {
+ const amount = BigInt(microStx);
+ const stx = Number(amount) / 1_000_000;
+ return stx.toFixed(6).replace(/\.?0+$/, '');
+}
+
+// Usage examples
+const microStx = stxToMicroStx(1.5); // 1500000n
+const stx = microStxToStx(1500000); // "1.5"
+```
+{% endcode %}
+
+## Precision-safe handling
+
+Handle large numbers without precision loss using BigInt operations.
+
+{% code title="precision-safe.ts" %}
+```ts
+class StxConverter {
+ static readonly MICROSTX_PER_STX = 1_000_000n;
+
+ static toMicroStx(amount: string | number, decimals = 6): bigint {
+ const amountStr = amount.toString();
+ const [whole, decimal = ''] = amountStr.split('.');
+ const paddedDecimal = decimal.padEnd(decimals, '0').slice(0, decimals);
+ return BigInt(whole + paddedDecimal);
+ }
+
+ static toStx(microStx: bigint | string | number): string {
+ const amount = BigInt(microStx);
+ const isNegative = amount < 0n;
+ const absoluteAmount = isNegative ? -amount : amount;
+
+ const str = absoluteAmount.toString().padStart(7, '0');
+ const whole = str.slice(0, -6) || '0';
+ const decimal = str.slice(-6);
+
+ let result = `${whole}.${decimal}`.replace(/\.?0+$/, '');
+ return isNegative ? `-${result}` : result;
+ }
+}
+
+// Precise conversion examples
+const precise1 = StxConverter.toMicroStx('123.456789'); // 123456789n
+const precise2 = StxConverter.toStx(123456789n); // "123.456789"
+```
+{% endcode %}
+
+## Token conversions
+
+Handle tokens with different decimal places using a flexible converter class.
+
+{% code title="token-converter.ts" %}
+```ts
+interface TokenInfo {
+ decimals: number;
+ symbol: string;
+ name: string;
+}
+
+class TokenConverter {
+ constructor(private tokenInfo: TokenInfo) {}
+
+ toSmallestUnit(amount: string | number): bigint {
+ if (typeof amount === 'string') {
+ const [whole, decimal = ''] = amount.split('.');
+ const paddedDecimal = decimal
+ .padEnd(this.tokenInfo.decimals, '0')
+ .slice(0, this.tokenInfo.decimals);
+ return BigInt(whole + paddedDecimal);
+ }
+
+ const multiplier = 10n ** BigInt(this.tokenInfo.decimals);
+ return BigInt(Math.floor(amount * Number(multiplier)));
+ }
+
+ fromSmallestUnit(amount: bigint | string): string {
+ const value = BigInt(amount);
+ const divisor = 10n ** BigInt(this.tokenInfo.decimals);
+ const whole = value / divisor;
+ const remainder = value % divisor;
+
+ if (remainder === 0n) return whole.toString();
+
+ const decimal = remainder
+ .toString()
+ .padStart(this.tokenInfo.decimals, '0')
+ .replace(/0+$/, '');
+
+ return `${whole}.${decimal}`;
+ }
+}
+
+// Different token examples
+const usdc = new TokenConverter({ decimals: 6, symbol: 'USDC', name: 'USD Coin' });
+const btc = new TokenConverter({ decimals: 8, symbol: 'BTC', name: 'Bitcoin' });
+
+const usdcAmount = usdc.toSmallestUnit('100.50'); // 100500000n
+const btcAmount = btc.toSmallestUnit('0.00123456'); // 123456n
+```
+{% endcode %}
+
+## Display formatting
+
+Format amounts for user interfaces with localization support.
+
+{% code title="stx-formatter.ts" %}
+```ts
+class StxFormatter {
+ static format(microStx: bigint, options?: {
+ decimals?: number;
+ locale?: string;
+ symbol?: boolean;
+ }): string {
+ const stx = StxConverter.toStx(microStx);
+ const number = parseFloat(stx);
+
+ const formatted = new Intl.NumberFormat(options?.locale || 'en-US', {
+ minimumFractionDigits: 0,
+ maximumFractionDigits: options?.decimals ?? 6,
+ }).format(number);
+
+ return options?.symbol ? `${formatted} STX` : formatted;
+ }
+
+ static compact(microStx: bigint): string {
+ const stx = Number(StxConverter.toStx(microStx));
+
+ if (stx >= 1_000_000) {
+ return `${(stx / 1_000_000).toFixed(2)}M STX`;
+ } else if (stx >= 1_000) {
+ return `${(stx / 1_000).toFixed(2)}K STX`;
+ }
+
+ return this.format(microStx, { decimals: 6, symbol: true });
+ }
+}
+
+// Formatting examples
+const formatted = StxFormatter.format(123456789n, {
+ decimals: 2,
+ symbol: true
+}); // "123.46 STX"
+
+const compact = StxFormatter.compact(1234567890000n); // "1.23K STX"
+```
+{% endcode %}
+
+## Input validation
+
+Validate and sanitize user input for amount fields.
+
+{% code title="amount-input.ts" %}
+```ts
+class AmountInput {
+ static validate(input: string, options?: {
+ decimals?: number;
+ min?: string;
+ max?: string;
+ }): { valid: boolean; error?: string } {
+ // Check format
+ if (!/^\d*\.?\d*$/.test(input)) {
+ return { valid: false, error: 'Invalid number format' };
+ }
+
+ // Check decimal places
+ const parts = input.split('.');
+ if (parts[1] && parts[1].length > (options?.decimals || 6)) {
+ return { valid: false, error: `Maximum ${options?.decimals || 6} decimal places` };
+ }
+
+ // Check range
+ if (options?.min) {
+ const value = parseFloat(input);
+ if (value < parseFloat(options.min)) {
+ return { valid: false, error: `Minimum amount is ${options.min}` };
+ }
+ }
+
+ return { valid: true };
+ }
+
+ static sanitize(input: string, decimals = 6): string {
+ let sanitized = input.replace(/[^\d.]/g, '');
+ const parts = sanitized.split('.');
+
+ if (parts.length > 2) {
+ sanitized = parts[0] + '.' + parts.slice(1).join('');
+ }
+
+ if (parts[1] && parts[1].length > decimals) {
+ sanitized = parts[0] + '.' + parts[1].slice(0, decimals);
+ }
+
+ return sanitized;
+ }
+}
+
+// Validation examples
+const result1 = AmountInput.validate('123.456', {
+ decimals: 6,
+ min: '0.000001'
+}); // { valid: true }
+
+const result2 = AmountInput.validate('123.4567890', {
+ decimals: 6
+}); // { valid: false, error: 'Maximum 6 decimal places' }
+```
+{% endcode %}
diff --git a/docs/build/whats-new/latest-updates.md b/docs/build/whats-new/latest-updates.md
new file mode 100644
index 0000000000..90986906e2
--- /dev/null
+++ b/docs/build/whats-new/latest-updates.md
@@ -0,0 +1,359 @@
+---
+description: Check out the latest Stacks developer updates
+---
+
+# Latest Updates
+
+### Stacks Miners — Please Update ASAP!
+
+_December 12, 2025_
+
+This release activates the new read-count tenure extensions from SIP-034, a highly anticipated upgrade for builders across the ecosystem.
+
+It also includes several important bug fixes, making this an update you don’t want to delay.
+
+
+
+Details
+
+For the latest release: [https://github.com/stacks-network/stacks-core/releases/tag/3.3.0.0.2](https://github.com/stacks-network/stacks-core/releases/tag/3.3.0.0.2)
+
+#### Details on what was updated
+
+**Added**
+
+* Fixed an issue where `event.committed` was always equal to `true` in the block replay RPC endpoint
+* Added `result_hex` and `post_condition_aborted` to the block replay RPC endpoint
+* Added `--epoch ` flag to `clarity-cli` commands to specify the epoch context for evaluation.
+* Support read-count tenure extends
+* Added `read_count_idle_timeout_secs` config option to set the amount of seconds of idle time must pass before a read-count tenure extend is allowed (defaults to 20 seconds)
+* Send a read-count tenure extend timestamp in the block responses
+* Approve a block with a read-count tenure extend when the appropriate amount of idle time has passed
+
+**Fixed**
+
+* Correctly produce the receipt for the `costs-4` contract, which was deployed on epoch 3.3 activation. Users who consume node events and want to fill in the missing receipt (e.g. the Hiro API) will need to revert their chainstate to before the 3.3 activation and then resume sync to receive the previously missing event.
+
+
+
+***
+
+### Upgrade to Dual Stacking contracts
+
+_December 10, 2025_
+
+Dual Stacking contracts will be **upgraded on Dec 15**. This upgrade enables more flexible reward parameters and allows users to view their sBTC holdings and corresponding rewards within the Dual Stacking app.
+
+
+
+Details
+
+#### tl;dr
+
+* If you enrolled in Dual Stacking you'll be moved over automatically with no action needed.
+* If you did not enroll in the web app but were receiving Dual Stacking rewards through a participating app, you need to enroll on the web app.
+
+To check your enrollment status go to [app.stacks.co](https://app.stacks.co/).
+
+The contract will upgrade from `.dual-stacking-v1` to `.dual-stacking-v2_0_2` .
+
+
+
+***
+
+### Deploy in Clarinet using encrypted mnemonics
+
+_December 9, 2025_
+
+`clarinet 3.11.0` contains support for encrypted mnemonics. This feature gives users the option to encrypt the mnemonic seed phrase in their deployment files, so if a user's machine is compromised by a filesystem reading vulnerability, the seed phrase is not leaked to the attacker.
+
+
+
+Details
+
+To use this feature, a user must first run `clarinet deployments encrypt`, which will prompt the user for the seed phrase and a password, then print the encrypted mnemonic to the console. The user can then put the resulting ciphertext into their deployment config file using the key `encrypted_mnemonic`. The next time the user runs `clarinet deployments apply`, they will be prompted for the password, and the mnemonic will be decrypted for use in that session.
+
+For example, if your `settings/Mainnet.toml` file looks like this:
+
+{% code title="settings/Mainnet.toml" %}
+```toml
+[network]
+name = "mainnet"
+stacks_node_rpc_address = "https://api.hiro.so"
+deployment_fee_rate = 10
+
+[accounts.deployer]
+mnemonic = "twice kind fence tip hidden tilt action fragile skin nothing glory cousin green tomorrow spring wrist shed math olympic multiply hip blue scout claw"
+```
+{% endcode %}
+
+You would then run:
+
+{% code title="terminal" %}
+```
+user@host package % clarinet deployments encrypt
+Enter mnemonic to encrypt:
+twice kind fence tip hidden tilt action fragile skin nothing glory cousin green tomorrow spring wrist shed math olympic multiply hip blue scout claw
+Enter password:
+
+encrypted_mnemonic = ""
+```
+{% endcode %}
+
+You would then replace the `mnemonic` field in your settings file with the `encrypted_mnemonic` output above:
+
+{% code title="settings/Mainnet.toml" %}
+```toml
+[accounts.deployer]
+encrypted_mnemonic = "47hYHSp4gtoBabz4X8cByJtRbvD3tBemS1zZJTkxYh2LJ7cVAHY6z74Td8bF5Dcsdpv45gDELPwfBP8Mfk64Q8TsBJNU9sf5hWMrTKPtr5h9abSdmxu4m2BewbUCi4o8znn42nAd7yphcb345YCrYLJFqFC7k9LqXvxgbQxUiFpWeyTVJPkGFa3aiQ8G5uhrv7pLCer4kRmXsmXbBvEqwEQLG7eM3TUMzUP79mHqJ1HGe2XWn"
+```
+{% endcode %}
+
+Then the next time you deploy your package, you will be prompted for the password:
+
+{% code title="terminal" %}
+```
+user@host package % clarinet deployments apply --mainnet
+
+Enter password to decrypt mnemonic for account deployer:
+```
+{% endcode %}
+
+
+
+***
+
+### New Tutorials section
+
+_December 7, 2025_
+
+The new [Tutorials](https://app.gitbook.com/s/skGYu79qDNfITOqDNU3s/) section is now live on the Stacks docs!
+
+First up: the beloved [Bitcoin Primer](https://app.gitbook.com/s/skGYu79qDNfITOqDNU3s/bitcoin-primer) by Kenny Rogers.
+
+We’re building a collection of the best full, end-to-end tutorials in the Stacks ecosystem. If you want to contribute a complete end-to-end tutorial related to developing on Stacks, let us know!
+
+***
+
+### Clarity 4 is now LIVE!
+
+_November 18, 2025_
+
+SIP-033 and SIP-034 have officially activated at Bitcoin block 923222 – bringing Clarity 4 live on Stacks, the smart contract layer secured by Bitcoin.
+
+This upgrade introduces Version 4 of the Clarity smart contract language, marking a major step forward for the Stacks ecosystem. For users, it delivers safer, smarter contracts with enhanced built-in protections.
+
+For builders, it unlocks five powerful new functions that make developing secure, flexible, and Bitcoin-native DeFi applications easier than ever.
+
+
+
+Details
+
+### What Clarity 4 Means for Bitcoin Builders
+
+#### 1. On-chain Contract Verification
+
+Developers can now fetch the hash of another contract’s code body.
+
+[`contract-hash?`](https://docs.stacks.co/reference/clarity/functions#contract-hash)
+
+This makes it possible for one contract to verify that another follows a specific template before interacting with it – a major step toward safer, more trustless bridges and marketplaces that can support a wider range of assets.
+
+#### 2. Allowing Contracts to Set Post-Conditions
+
+New functions allow contracts to set post-conditions that protect their assets.
+
+[`restrict-assets?`](https://docs.stacks.co/reference/clarity/functions#restrict-assets)
+
+This means a contract can safely call external contracts (such as traits) and automatically roll back any changes if the executed code moves assets beyond what’s allowed.
+
+#### 3. Convert Simple Values into ASCII Strings
+
+Clarity 4 adds a function to convert simple values like booleans or principals into ASCII strings.
+
+[`to-ascii?`](https://docs.stacks.co/reference/clarity/functions#to-ascii)
+
+This makes it easier to generate readable, string-based messages – a useful tool for developers building cross-chain features and integrations.
+
+#### 4. Get the Timestamp of the Current Block
+
+A new keyword lets developers retrieve the timestamp of the current block.
+
+[`stacks-block-time`](https://docs.stacks.co/reference/clarity/keywords#stacks-block-time)
+
+This addition enables time-based logic in smart contracts – an essential capability for building features like yield schedules, lockups, or expiration conditions in DeFi applications.
+
+#### 5. Native Passkey Integration
+
+Clarity 4 introduces a new function enabling on-chain verification of secp256r1 signatures.
+
+[`secp256r1-verify`](https://docs.stacks.co/reference/clarity/functions#secp256r1-verify)
+
+This lays the groundwork for passkey-based authentication, opening the door to features like hardware-secured wallets and biometric transaction signing.
+
+#### 6. Dimension-specific Tenure Extensions
+
+The SIP-033 vote also included technical rider SIP-034, which introduces dimension-specific tenure extensions. Signers can approve resets to one budget dimension (e.g., read-count) without resetting the others, allowing high-throughput workloads even when the cost model is pessimistic.
+
+### Why This Matters for Bitcoin
+
+Clarity 4 strengthens Stacks' position as Bitcoin's liquidity layer by giving developers the tools to build more sophisticated Bitcoin DeFi applications – all secured by Bitcoin through Stacks' Proof of Transfer mechanism.
+
+Whether you're building Bitcoin lending protocols, yield products with sBTC, or the next generation of BTCFi applications, Clarity 4 delivers the security and functionality Bitcoin capital markets demand.
+
+Check out [the full SIP-033](https://github.com/stacksgov/sips/pull/218) & [SIP-034](https://github.com/314159265359879/sips/blob/9b45bf07b6d284c40ea3454b4b1bfcaeb0438683/sips/sip-034/sip-034.md) specifications.
+
+***
+
+#### Additional Resources
+
+* \[[Hiro Youtube](https://youtu.be/oJgacfc7YVk?si=b72bNicdS8NjUpml)] A Dev N' Tell with Brice on new Clarity 4 features
+
+
+
+***
+
+### Clarinet was migrated to Stacks Labs
+
+_November 5, 2025_
+
+You may have noticed that the Clarinet repository now belongs to the stx-labs organization.
+
+With the **3.9.0** release, a few other things have changed:
+
+* The NPM packages are now published under the `@stacks` organization.
+* The Clarity VSCode extension is now published under the Stacks Labs organization.
+
+
+
+Details
+
+### tl;dr
+
+Checklist:\
+✅ Update NPM packages:
+
+* `"@stacks/clarinet-sdk": "^3.10.0"`
+* `"vitest-environment-clarinet": "3.0.2"`\
+ ✅ Replace all imports of `@hiroystems/clarinet-sdk` to `@stacks/clarinet-sdk`\
+ ✅ Optionally, update Vitest to v4 and **update vitest config**
+
+***
+
+### How to migrate?
+
+#### VSCode
+
+In VSCode (or similar variants such as Cursor), you'll have to uninstall the Hiro Systems "Clarity" extension in favor of the new "Clarity - Stacks Labs" extension published by Stacks Labs. The name of the extension will eventually revert to "Clarity" at some point, once the Hiro one is deprecated. You can also see it in the [online marketplace](https://marketplace.visualstudio.com/items?itemName=StacksLabs.clarity-stacks) - feel free to leave a 5 ⭐ review if you enjoy Clarinet!
+
+#### NPM
+
+New Clarinet projects created with 3.9.0 will automatically use the `@stacks/` NPM package.
+
+However, older projects require a few manual updates to be migrated.
+
+#### `package.json`
+
+In your package.json, replace `@hirosystems/clarinet-sdk` with the `@stacks` one, and upgrade `vitest-environement-clarinet` to version 3.0.1. Your dependencies should look like that.
+
+Optionally, you can upgrade to Vitest@4, more on that below
+
+```
+ "dependencies": {
+ "@stacks/clarinet-sdk": "^3.10.0",
+ "@stacks/transactions": "^7.3.0",
+ "@types/node": "24.10.0",
+ "chokidar-cli": "3.0.0",
+ "vitest": "^4.0.7",
+ "vitest-environment-clarinet": "3.0.2"
+ }
+```
+
+#### `tsconfig.json`
+
+In the tsconfig.json, you need to update the `"includes"` config like so, so that is using `@stacks/clarinet-sdk`
+
+```
+ "include": ["node_modules/@stacks/clarinet-sdk/vitest-helpers/src", "tests"]
+```
+
+#### `vitest.config.ts` (or `.js`)
+
+Your Vitest config has to import `@stacks/clarinet-sdk/vitest`.
+
+Double check that you import `defineConfig` from `"vitest/config"` and not `"vite"`.
+
+```
+import { defineConfig } from "vitest/config";
+import {
+ vitestSetupFilePath,
+ getClarinetVitestsArgv,
+} from "@stacks/clarinet-sdk/vitest";
+```
+
+If you upgraded to Vitest v4, a few other changes are needed in `defineConfig`:
+
+```
+...
+
+export default defineConfig({
+ test: {
+ // use vitest-environment-clarinet
+ environment: "clarinet",
+ pool: "forks",
+ // clarinet handles test isolation by resetting the simnet between tests
+ isolate: false,
+ maxWorkers: 1,
+ setupFiles: [
+ vitestSetupFilePath,
+ // custom setup files can be added here
+ ],
+ environmentOptions: {
+ clarinet: {
+ ...getClarinetVitestsArgv(),
+ // add or override options
+ },
+ },
+ },
+});
+```
+
+#### Docker image
+
+The Clarinet Docker image has been moved from Docker Hub to GitHub Container Registry (ghcr). It can be used like so:
+
+```
+jobs:
+ sanity-checks:
+ runs-on: ubuntu-latest
+ container: ghcr.io/stx-labs/clarinet:latest
+ steps:
+ - uses: actions/checkout@v4
+ - name: Check Clarity contracts check
+ run: clarinet check --use-on-disk-deployment-plan
+ - name: Check Clarity contracts format
+ run: clarinet fmt --check
+```
+
+#### Double check
+
+Search for all occurrences of `@hirosystems/clarinet-sdk` in your project; they'll likely need to be updated to `@stacks/clarinet-sdk`.
+
+{% hint style="success" %}
+If you're using third-party tools like Rendezvous or Clarigen, they now both support `@stacks/clarinet-sdk`.
+{% endhint %}
+
+***
+
+### See it in action
+
+See how the clarity-starter project was updated in this PR:\
+[stx-labs/clarity-starter#17](https://github.com/stx-labs/clarity-starter/pull/17)
+
+### Conclusion
+
+We understand that these types of breaking changes can be frustrating. Although it's not ideal, we need it to move forward.
+
+If you experience any issues with the migrations, reach out to us in the `#clarinet` channel on Discord or reply to this discussion.
+
+
diff --git a/docs/contribute/README.md b/docs/contribute/README.md
new file mode 100644
index 0000000000..53a04b8288
--- /dev/null
+++ b/docs/contribute/README.md
@@ -0,0 +1,29 @@
+# Contribute
+
+### Contribute to Stacks Core
+
+There is a [detailed contribution guide](https://github.com/stacks-network/stacks-core/blob/master/CONTRIBUTING.md) that lives in the Stacks core GitHub repository that is the best place to get started contributing to Stacks.
+
+### Contribute to these Docs
+
+The Stacks docs are built using GitBook with a two-way sync with the [docs repository on GitHub](https://github.com/stacks-network/docs).
+
+Because of this two-way sync, you can contribute to the documentation in one of two ways:
+
+{% stepper %}
+{% step %}
+### Fork the repo and create a PR
+
+You can fork the docs repo, add your change, and then create a PR to be merged into the main docs.
+{% endstep %}
+
+{% step %}
+### Create an issue
+
+You can create an issue, and someone that works on the docs will take a look and implement it if it is a necessary change.
+{% endstep %}
+{% endstepper %}
+
+What kinds of changes are we looking for?
+
+If you see a typo, a missing tutorial, an unclear explanation, or really anything else you think could improve the quality of the documentation, please feel free to open an issue or create a pull request.
diff --git a/docs/contribute/SUMMARY.md b/docs/contribute/SUMMARY.md
new file mode 100644
index 0000000000..de25e5d9b1
--- /dev/null
+++ b/docs/contribute/SUMMARY.md
@@ -0,0 +1,3 @@
+# Table of contents
+
+* [Contribute](README.md)
diff --git a/docs/learn/.gitbook.yaml b/docs/learn/.gitbook.yaml
new file mode 100644
index 0000000000..515d276164
--- /dev/null
+++ b/docs/learn/.gitbook.yaml
@@ -0,0 +1,61 @@
+root: ./
+
+redirects:
+ # stacks-101 redirects
+ concepts/stacks-101/what-is-stacks: stacks-101/what-is-stacks.md
+ concepts/stacks-101/bitcoin-connection: stacks-101/bitcoin-connection.md
+ concepts/stacks-101/proof-of-transfer: stacks-101/proof-of-transfer.md
+ concepts/stacks-101/stacks-among-other-layers: stacks-101/stacks-among-other-layers.md
+ concepts/stacks-101/financial-incentive-and-security-budget: stacks-101/financial-incentive-and-security-budget.md
+
+ # block-production redirects
+ concepts/block-production/bitcoin-finality: block-production/bitcoin-finality.md
+ concepts/block-production/bitcoin-reorgs: block-production/bitcoin-reorgs.md
+ concepts/block-production/mining: block-production/mining.md
+ concepts/block-production/stackers-and-signing: block-production/signing.md
+ concepts/block-production/stacking: block-production/stacking.md
+
+ # clarity redirects
+ concepts/clarity/decidability: clarity/decidability.md
+ concepts/clarity/overview: clarity/overview.md
+
+ # network-fundamentals redirects
+ concepts/network-fundamentals/accounts: network-fundamentals/accounts.md
+ concepts/network-fundamentals/authentication: network-fundamentals/authentication.md
+ concepts/network-fundamentals/bitcoin-name-system: network-fundamentals/bitcoin-name-system.md
+ concepts/network-fundamentals/mainnet-and-testnets: network-fundamentals/mainnet-and-testnets.md
+ concepts/network-fundamentals/network: network-fundamentals/network-basics.md
+ concepts/network-fundamentals/sips: network-fundamentals/sips.md
+ concepts/network-fundamentals/technical-specifications/audits: network-fundamentals/technical-specifications/audits.md
+
+ # transactions redirects
+ concepts/transactions/post-conditions: transactions/post-conditions.md
+ concepts/transactions/transactions: transactions/how-transactions-work.md
+
+ # sbtc redirects
+ concepts/sbtc/core-features: sbtc/core-features.md
+ concepts/sbtc/emily: sbtc/emily-api.md
+ concepts/sbtc/peg-wallet-utxo: sbtc/peg-wallet-utxo.md
+ concepts/sbtc/sbtc-audits: sbtc/sbtc-audits.md
+ concepts/sbtc/sbtc-faq: sbtc/sbtc-faq.md
+
+ # sbtc auxiliary-features redirects
+ concepts/sbtc/auxiliary-features/fee-sponsorship: sbtc/auxiliary-features/transaction-fee-sponsorship.md
+ concepts/sbtc/auxiliary-features/signer-wallet-rotation: sbtc/auxiliary-features/signer-wallet-rotation.md
+
+ # sbtc clarity-contracts redirects
+ concepts/sbtc/clarity-contracts/sbtc-bootstrap-signers: sbtc/clarity-contracts/sbtc-bootstrap-signers.md
+ concepts/sbtc/clarity-contracts/sbtc-deposit: sbtc/clarity-contracts/sbtc-deposit.md
+ concepts/sbtc/clarity-contracts/sbtc-registry: sbtc/clarity-contracts/sbtc-registry.md
+ concepts/sbtc/clarity-contracts/sbtc-signers: sbtc/clarity-contracts/sbtc-signers.md
+ concepts/sbtc/clarity-contracts/sbtc-token: sbtc/clarity-contracts/sbtc-token.md
+ concepts/sbtc/clarity-contracts/sbtc-withdrawal: sbtc/clarity-contracts/sbtc-withdrawal.md
+
+ # sbtc operations redirects
+ concepts/sbtc/operations/deposit-withdrawal-times: sbtc/sbtc-operations/deposit-vs-withdrawal-times.md
+ concepts/sbtc/operations/deposit: sbtc/sbtc-operations/deposit.md
+ concepts/sbtc/operations/withdrawal: sbtc/sbtc-operations/withdrawal.md
+
+ # sbtc walkthroughs redirects
+ concepts/sbtc/walkthroughs/sbtc-transaction-lifecycle: sbtc/walkthroughs/sbtc-transaction-walkthrough.md
+ concepts/sbtc/walkthroughs/signer-process: sbtc/walkthroughs/signer-process-walkthrough.md
diff --git a/docs/learn/.gitbook/assets/AD_4nXdlY8MKm4IEls6XieRtpunfge6KTNSw2HT_o9iD8FgIL3RCJuzKa781Ft oXNCEn_rIqMqu0_hqD5 GPrF9cT6rFXdnA1BASFoU3Uy6VgR2ARfp 0FnLgrM7GH7hdx Ia2m_DpdonZmlwqTMd1sQe0XqgX4 b/docs/learn/.gitbook/assets/AD_4nXdlY8MKm4IEls6XieRtpunfge6KTNSw2HT_o9iD8FgIL3RCJuzKa781Ft oXNCEn_rIqMqu0_hqD5 GPrF9cT6rFXdnA1BASFoU3Uy6VgR2ARfp 0FnLgrM7GH7hdx Ia2m_DpdonZmlwqTMd1sQe0XqgX4
new file mode 100644
index 0000000000..3f022d11c4
Binary files /dev/null and b/docs/learn/.gitbook/assets/AD_4nXdlY8MKm4IEls6XieRtpunfge6KTNSw2HT_o9iD8FgIL3RCJuzKa781Ft oXNCEn_rIqMqu0_hqD5 GPrF9cT6rFXdnA1BASFoU3Uy6VgR2ARfp 0FnLgrM7GH7hdx Ia2m_DpdonZmlwqTMd1sQe0XqgX4 differ
diff --git a/docs/learn/.gitbook/assets/Blockstack_Desktop_Wallet_Pentest_Report_11-12-2020 (1).pdf b/docs/learn/.gitbook/assets/Blockstack_Desktop_Wallet_Pentest_Report_11-12-2020 (1).pdf
new file mode 100644
index 0000000000..72b6b717bf
Binary files /dev/null and b/docs/learn/.gitbook/assets/Blockstack_Desktop_Wallet_Pentest_Report_11-12-2020 (1).pdf differ
diff --git a/docs/learn/.gitbook/assets/Blockstack_Desktop_Wallet_Pentest_Report_11-12-2020.pdf b/docs/learn/.gitbook/assets/Blockstack_Desktop_Wallet_Pentest_Report_11-12-2020.pdf
new file mode 100644
index 0000000000..72b6b717bf
Binary files /dev/null and b/docs/learn/.gitbook/assets/Blockstack_Desktop_Wallet_Pentest_Report_11-12-2020.pdf differ
diff --git a/docs/learn/.gitbook/assets/Clarity Alliance - sBTC (1).pdf b/docs/learn/.gitbook/assets/Clarity Alliance - sBTC (1).pdf
new file mode 100644
index 0000000000..46fb8bb7ca
Binary files /dev/null and b/docs/learn/.gitbook/assets/Clarity Alliance - sBTC (1).pdf differ
diff --git a/docs/learn/.gitbook/assets/Clarity Alliance - sBTC Rewards Program.pdf b/docs/learn/.gitbook/assets/Clarity Alliance - sBTC Rewards Program.pdf
new file mode 100644
index 0000000000..3fab1ee354
Binary files /dev/null and b/docs/learn/.gitbook/assets/Clarity Alliance - sBTC Rewards Program.pdf differ
diff --git a/docs/learn/.gitbook/assets/Clarity Alliance - sBTC.pdf b/docs/learn/.gitbook/assets/Clarity Alliance - sBTC.pdf
new file mode 100644
index 0000000000..46fb8bb7ca
Binary files /dev/null and b/docs/learn/.gitbook/assets/Clarity Alliance - sBTC.pdf differ
diff --git a/docs/learn/.gitbook/assets/CoinFabrik - Stacks LibSigner (1).pdf b/docs/learn/.gitbook/assets/CoinFabrik - Stacks LibSigner (1).pdf
new file mode 100644
index 0000000000..6e1a11c272
Binary files /dev/null and b/docs/learn/.gitbook/assets/CoinFabrik - Stacks LibSigner (1).pdf differ
diff --git a/docs/learn/.gitbook/assets/CoinFabrik - Stacks LibSigner.pdf b/docs/learn/.gitbook/assets/CoinFabrik - Stacks LibSigner.pdf
new file mode 100644
index 0000000000..6e1a11c272
Binary files /dev/null and b/docs/learn/.gitbook/assets/CoinFabrik - Stacks LibSigner.pdf differ
diff --git a/docs/learn/.gitbook/assets/CoinFabrik - Stacks Signer Audit (1).pdf b/docs/learn/.gitbook/assets/CoinFabrik - Stacks Signer Audit (1).pdf
new file mode 100644
index 0000000000..4a733d4e4f
Binary files /dev/null and b/docs/learn/.gitbook/assets/CoinFabrik - Stacks Signer Audit (1).pdf differ
diff --git a/docs/learn/.gitbook/assets/CoinFabrik - Stacks Signer Audit.pdf b/docs/learn/.gitbook/assets/CoinFabrik - Stacks Signer Audit.pdf
new file mode 100644
index 0000000000..4a733d4e4f
Binary files /dev/null and b/docs/learn/.gitbook/assets/CoinFabrik - Stacks Signer Audit.pdf differ
diff --git a/docs/learn/.gitbook/assets/CoinFabrik_Signer Binary (1).pdf b/docs/learn/.gitbook/assets/CoinFabrik_Signer Binary (1).pdf
new file mode 100644
index 0000000000..dc059e72dc
Binary files /dev/null and b/docs/learn/.gitbook/assets/CoinFabrik_Signer Binary (1).pdf differ
diff --git a/docs/learn/.gitbook/assets/CoinFabrik_Signer Binary.pdf b/docs/learn/.gitbook/assets/CoinFabrik_Signer Binary.pdf
new file mode 100644
index 0000000000..dc059e72dc
Binary files /dev/null and b/docs/learn/.gitbook/assets/CoinFabrik_Signer Binary.pdf differ
diff --git a/docs/learn/.gitbook/assets/CoinFabrik_StackerDB (1).pdf b/docs/learn/.gitbook/assets/CoinFabrik_StackerDB (1).pdf
new file mode 100644
index 0000000000..b0e846fba3
Binary files /dev/null and b/docs/learn/.gitbook/assets/CoinFabrik_StackerDB (1).pdf differ
diff --git a/docs/learn/.gitbook/assets/CoinFabrik_StackerDB.pdf b/docs/learn/.gitbook/assets/CoinFabrik_StackerDB.pdf
new file mode 100644
index 0000000000..b0e846fba3
Binary files /dev/null and b/docs/learn/.gitbook/assets/CoinFabrik_StackerDB.pdf differ
diff --git a/docs/learn/.gitbook/assets/CoinFabrik_WSTS (1).pdf b/docs/learn/.gitbook/assets/CoinFabrik_WSTS (1).pdf
new file mode 100644
index 0000000000..1b73a0857e
Binary files /dev/null and b/docs/learn/.gitbook/assets/CoinFabrik_WSTS (1).pdf differ
diff --git a/docs/learn/.gitbook/assets/CoinFabrik_WSTS.pdf b/docs/learn/.gitbook/assets/CoinFabrik_WSTS.pdf
new file mode 100644
index 0000000000..1b73a0857e
Binary files /dev/null and b/docs/learn/.gitbook/assets/CoinFabrik_WSTS.pdf differ
diff --git a/docs/learn/.gitbook/assets/Coinfabrik - Stacks PoX (1).pdf b/docs/learn/.gitbook/assets/Coinfabrik - Stacks PoX (1).pdf
new file mode 100644
index 0000000000..e9678769ea
Binary files /dev/null and b/docs/learn/.gitbook/assets/Coinfabrik - Stacks PoX (1).pdf differ
diff --git a/docs/learn/.gitbook/assets/Coinfabrik - Stacks PoX.pdf b/docs/learn/.gitbook/assets/Coinfabrik - Stacks PoX.pdf
new file mode 100644
index 0000000000..e9678769ea
Binary files /dev/null and b/docs/learn/.gitbook/assets/Coinfabrik - Stacks PoX.pdf differ
diff --git a/docs/learn/.gitbook/assets/Frame 316125325.jpg b/docs/learn/.gitbook/assets/Frame 316125325.jpg
new file mode 100644
index 0000000000..884cae9020
Binary files /dev/null and b/docs/learn/.gitbook/assets/Frame 316125325.jpg differ
diff --git a/docs/learn/.gitbook/assets/Frame 316125960.jpg b/docs/learn/.gitbook/assets/Frame 316125960.jpg
new file mode 100644
index 0000000000..5d63e59df0
Binary files /dev/null and b/docs/learn/.gitbook/assets/Frame 316125960.jpg differ
diff --git a/docs/learn/.gitbook/assets/Frame 316126243.jpg b/docs/learn/.gitbook/assets/Frame 316126243.jpg
new file mode 100644
index 0000000000..c5e96dfcbd
Binary files /dev/null and b/docs/learn/.gitbook/assets/Frame 316126243.jpg differ
diff --git a/docs/learn/.gitbook/assets/Frame 316126254.jpg b/docs/learn/.gitbook/assets/Frame 316126254.jpg
new file mode 100644
index 0000000000..dfb22d9988
Binary files /dev/null and b/docs/learn/.gitbook/assets/Frame 316126254.jpg differ
diff --git a/docs/learn/.gitbook/assets/Frame 316126255.jpg b/docs/learn/.gitbook/assets/Frame 316126255.jpg
new file mode 100644
index 0000000000..2d78244848
Binary files /dev/null and b/docs/learn/.gitbook/assets/Frame 316126255.jpg differ
diff --git a/docs/learn/.gitbook/assets/Frame 316126258.jpg b/docs/learn/.gitbook/assets/Frame 316126258.jpg
new file mode 100644
index 0000000000..273720c216
Binary files /dev/null and b/docs/learn/.gitbook/assets/Frame 316126258.jpg differ
diff --git a/docs/learn/.gitbook/assets/Frame 316126264.jpg b/docs/learn/.gitbook/assets/Frame 316126264.jpg
new file mode 100644
index 0000000000..8edeb3144e
Binary files /dev/null and b/docs/learn/.gitbook/assets/Frame 316126264.jpg differ
diff --git a/docs/learn/.gitbook/assets/Frame 316126408.png b/docs/learn/.gitbook/assets/Frame 316126408.png
new file mode 100644
index 0000000000..7225362af3
Binary files /dev/null and b/docs/learn/.gitbook/assets/Frame 316126408.png differ
diff --git a/docs/learn/.gitbook/assets/Frame 316126414.png b/docs/learn/.gitbook/assets/Frame 316126414.png
new file mode 100644
index 0000000000..4ff1cd4193
Binary files /dev/null and b/docs/learn/.gitbook/assets/Frame 316126414.png differ
diff --git a/docs/learn/.gitbook/assets/Group 316124776.png b/docs/learn/.gitbook/assets/Group 316124776.png
new file mode 100644
index 0000000000..352540fc4d
Binary files /dev/null and b/docs/learn/.gitbook/assets/Group 316124776.png differ
diff --git a/docs/learn/.gitbook/assets/Group 316124777 (1).png b/docs/learn/.gitbook/assets/Group 316124777 (1).png
new file mode 100644
index 0000000000..07b169772b
Binary files /dev/null and b/docs/learn/.gitbook/assets/Group 316124777 (1).png differ
diff --git a/docs/learn/.gitbook/assets/Group 316124777 (2).png b/docs/learn/.gitbook/assets/Group 316124777 (2).png
new file mode 100644
index 0000000000..b203a65e29
Binary files /dev/null and b/docs/learn/.gitbook/assets/Group 316124777 (2).png differ
diff --git a/docs/learn/.gitbook/assets/Group 316124778 (1)-with-fordefi.png b/docs/learn/.gitbook/assets/Group 316124778 (1)-with-fordefi.png
new file mode 100644
index 0000000000..5bfe3c487a
Binary files /dev/null and b/docs/learn/.gitbook/assets/Group 316124778 (1)-with-fordefi.png differ
diff --git a/docs/learn/.gitbook/assets/Group 316124778 (2)-with-fordefi.png b/docs/learn/.gitbook/assets/Group 316124778 (2)-with-fordefi.png
new file mode 100644
index 0000000000..9b806f1b58
Binary files /dev/null and b/docs/learn/.gitbook/assets/Group 316124778 (2)-with-fordefi.png differ
diff --git a/docs/learn/.gitbook/assets/Group 316124778 (3)-with-fordefi.png b/docs/learn/.gitbook/assets/Group 316124778 (3)-with-fordefi.png
new file mode 100644
index 0000000000..3319d3c070
Binary files /dev/null and b/docs/learn/.gitbook/assets/Group 316124778 (3)-with-fordefi.png differ
diff --git a/docs/learn/.gitbook/assets/Group 316124778 (4)-with-fordefi.png b/docs/learn/.gitbook/assets/Group 316124778 (4)-with-fordefi.png
new file mode 100644
index 0000000000..86eb052ce8
Binary files /dev/null and b/docs/learn/.gitbook/assets/Group 316124778 (4)-with-fordefi.png differ
diff --git a/docs/learn/.gitbook/assets/Group 316124779-with-asigna.png b/docs/learn/.gitbook/assets/Group 316124779-with-asigna.png
new file mode 100644
index 0000000000..72f2b66bcc
Binary files /dev/null and b/docs/learn/.gitbook/assets/Group 316124779-with-asigna.png differ
diff --git a/docs/learn/.gitbook/assets/Group 316124780 (1)-with-asigna.png b/docs/learn/.gitbook/assets/Group 316124780 (1)-with-asigna.png
new file mode 100644
index 0000000000..660e948434
Binary files /dev/null and b/docs/learn/.gitbook/assets/Group 316124780 (1)-with-asigna.png differ
diff --git a/docs/learn/.gitbook/assets/Group 316124780-with-asigna.png b/docs/learn/.gitbook/assets/Group 316124780-with-asigna.png
new file mode 100644
index 0000000000..d06a74bc72
Binary files /dev/null and b/docs/learn/.gitbook/assets/Group 316124780-with-asigna.png differ
diff --git a/docs/learn/.gitbook/assets/Group 316124781.png b/docs/learn/.gitbook/assets/Group 316124781.png
new file mode 100644
index 0000000000..ec89052ddb
Binary files /dev/null and b/docs/learn/.gitbook/assets/Group 316124781.png differ
diff --git a/docs/learn/.gitbook/assets/Group 316124782.png b/docs/learn/.gitbook/assets/Group 316124782.png
new file mode 100644
index 0000000000..3d7305b5c3
Binary files /dev/null and b/docs/learn/.gitbook/assets/Group 316124782.png differ
diff --git a/docs/learn/.gitbook/assets/Group 316124783 (1).png b/docs/learn/.gitbook/assets/Group 316124783 (1).png
new file mode 100644
index 0000000000..3dbb1bbb70
Binary files /dev/null and b/docs/learn/.gitbook/assets/Group 316124783 (1).png differ
diff --git a/docs/learn/.gitbook/assets/Group 316124783.png b/docs/learn/.gitbook/assets/Group 316124783.png
new file mode 100644
index 0000000000..17b1bfe101
Binary files /dev/null and b/docs/learn/.gitbook/assets/Group 316124783.png differ
diff --git a/docs/learn/.gitbook/assets/Group 316124848.png b/docs/learn/.gitbook/assets/Group 316124848.png
new file mode 100644
index 0000000000..6dbb8304c6
Binary files /dev/null and b/docs/learn/.gitbook/assets/Group 316124848.png differ
diff --git a/docs/learn/.gitbook/assets/NCC_Group_Stacks_Blockchain_Audit_Report_2020-11-23_v1.0 (1).pdf b/docs/learn/.gitbook/assets/NCC_Group_Stacks_Blockchain_Audit_Report_2020-11-23_v1.0 (1).pdf
new file mode 100644
index 0000000000..bed4f3bd8b
Binary files /dev/null and b/docs/learn/.gitbook/assets/NCC_Group_Stacks_Blockchain_Audit_Report_2020-11-23_v1.0 (1).pdf differ
diff --git a/docs/learn/.gitbook/assets/NCC_Group_Stacks_Blockchain_Audit_Report_2020-11-23_v1.0.pdf b/docs/learn/.gitbook/assets/NCC_Group_Stacks_Blockchain_Audit_Report_2020-11-23_v1.0.pdf
new file mode 100644
index 0000000000..bed4f3bd8b
Binary files /dev/null and b/docs/learn/.gitbook/assets/NCC_Group_Stacks_Blockchain_Audit_Report_2020-11-23_v1.0.pdf differ
diff --git a/docs/learn/.gitbook/assets/NCC_Group_Stacks_Wallet_Report_2020-11-17_v1.0 (1).pdf b/docs/learn/.gitbook/assets/NCC_Group_Stacks_Wallet_Report_2020-11-17_v1.0 (1).pdf
new file mode 100644
index 0000000000..cd00d448fa
Binary files /dev/null and b/docs/learn/.gitbook/assets/NCC_Group_Stacks_Wallet_Report_2020-11-17_v1.0 (1).pdf differ
diff --git a/docs/learn/.gitbook/assets/NCC_Group_Stacks_Wallet_Report_2020-11-17_v1.0.pdf b/docs/learn/.gitbook/assets/NCC_Group_Stacks_Wallet_Report_2020-11-17_v1.0.pdf
new file mode 100644
index 0000000000..cd00d448fa
Binary files /dev/null and b/docs/learn/.gitbook/assets/NCC_Group_Stacks_Wallet_Report_2020-11-17_v1.0.pdf differ
diff --git a/docs/learn/.gitbook/assets/OG Image.png b/docs/learn/.gitbook/assets/OG Image.png
new file mode 100644
index 0000000000..56afba2426
Binary files /dev/null and b/docs/learn/.gitbook/assets/OG Image.png differ
diff --git a/docs/learn/.gitbook/assets/Ottersec - WSTS (1).pdf b/docs/learn/.gitbook/assets/Ottersec - WSTS (1).pdf
new file mode 100644
index 0000000000..b3929dbb39
Binary files /dev/null and b/docs/learn/.gitbook/assets/Ottersec - WSTS (1).pdf differ
diff --git a/docs/learn/.gitbook/assets/Ottersec - WSTS.pdf b/docs/learn/.gitbook/assets/Ottersec - WSTS.pdf
new file mode 100644
index 0000000000..b3929dbb39
Binary files /dev/null and b/docs/learn/.gitbook/assets/Ottersec - WSTS.pdf differ
diff --git a/docs/learn/.gitbook/assets/Ottersec - sBTC Withdrawal (1).pdf b/docs/learn/.gitbook/assets/Ottersec - sBTC Withdrawal (1).pdf
new file mode 100644
index 0000000000..b093ed87bf
Binary files /dev/null and b/docs/learn/.gitbook/assets/Ottersec - sBTC Withdrawal (1).pdf differ
diff --git a/docs/learn/.gitbook/assets/Ottersec - sBTC Withdrawal.pdf b/docs/learn/.gitbook/assets/Ottersec - sBTC Withdrawal.pdf
new file mode 100644
index 0000000000..b093ed87bf
Binary files /dev/null and b/docs/learn/.gitbook/assets/Ottersec - sBTC Withdrawal.pdf differ
diff --git a/docs/learn/.gitbook/assets/Quantstamp_Network State Machine (1).pdf b/docs/learn/.gitbook/assets/Quantstamp_Network State Machine (1).pdf
new file mode 100644
index 0000000000..150723b091
Binary files /dev/null and b/docs/learn/.gitbook/assets/Quantstamp_Network State Machine (1).pdf differ
diff --git a/docs/learn/.gitbook/assets/Quantstamp_Network State Machine.pdf b/docs/learn/.gitbook/assets/Quantstamp_Network State Machine.pdf
new file mode 100644
index 0000000000..150723b091
Binary files /dev/null and b/docs/learn/.gitbook/assets/Quantstamp_Network State Machine.pdf differ
diff --git a/docs/learn/.gitbook/assets/Screenshot 2025-10-11 at 3.45.40 PM.png b/docs/learn/.gitbook/assets/Screenshot 2025-10-11 at 3.45.40 PM.png
new file mode 100644
index 0000000000..2532146af2
Binary files /dev/null and b/docs/learn/.gitbook/assets/Screenshot 2025-10-11 at 3.45.40 PM.png differ
diff --git a/docs/learn/.gitbook/assets/Stacks_graphic - 64.png b/docs/learn/.gitbook/assets/Stacks_graphic - 64.png
new file mode 100644
index 0000000000..a7c9ba02c9
Binary files /dev/null and b/docs/learn/.gitbook/assets/Stacks_graphic - 64.png differ
diff --git a/docs/learn/.gitbook/assets/Stacks_graphic - 65.png b/docs/learn/.gitbook/assets/Stacks_graphic - 65.png
new file mode 100644
index 0000000000..25aefa1fa3
Binary files /dev/null and b/docs/learn/.gitbook/assets/Stacks_graphic - 65.png differ
diff --git a/docs/learn/.gitbook/assets/Stacks_graphic - 67.png b/docs/learn/.gitbook/assets/Stacks_graphic - 67.png
new file mode 100644
index 0000000000..a98d35c6c3
Binary files /dev/null and b/docs/learn/.gitbook/assets/Stacks_graphic - 67.png differ
diff --git a/docs/learn/.gitbook/assets/Stacks_graphic - 80.png b/docs/learn/.gitbook/assets/Stacks_graphic - 80.png
new file mode 100644
index 0000000000..4bfe536ede
Binary files /dev/null and b/docs/learn/.gitbook/assets/Stacks_graphic - 80.png differ
diff --git a/docs/learn/.gitbook/assets/bitcoin-layer-2s.jpg b/docs/learn/.gitbook/assets/bitcoin-layer-2s.jpg
new file mode 100644
index 0000000000..052e7f91c7
Binary files /dev/null and b/docs/learn/.gitbook/assets/bitcoin-layer-2s.jpg differ
diff --git a/docs/learn/.gitbook/assets/bitcoin-stacks-address-connection.jpeg b/docs/learn/.gitbook/assets/bitcoin-stacks-address-connection.jpeg
new file mode 100644
index 0000000000..fad7d40b84
Binary files /dev/null and b/docs/learn/.gitbook/assets/bitcoin-stacks-address-connection.jpeg differ
diff --git a/docs/learn/.gitbook/assets/bitcoin-stacks-dark.png b/docs/learn/.gitbook/assets/bitcoin-stacks-dark.png
new file mode 100644
index 0000000000..62f6c1ce89
Binary files /dev/null and b/docs/learn/.gitbook/assets/bitcoin-stacks-dark.png differ
diff --git a/docs/learn/.gitbook/assets/bitcoin-stacks.png b/docs/learn/.gitbook/assets/bitcoin-stacks.png
new file mode 100644
index 0000000000..ce4cf04fbb
Binary files /dev/null and b/docs/learn/.gitbook/assets/bitcoin-stacks.png differ
diff --git a/docs/learn/.gitbook/assets/bridging-cover.jpg b/docs/learn/.gitbook/assets/bridging-cover.jpg
new file mode 100644
index 0000000000..6ecbb9fffb
Binary files /dev/null and b/docs/learn/.gitbook/assets/bridging-cover.jpg differ
diff --git a/docs/learn/.gitbook/assets/dual-stacking.png b/docs/learn/.gitbook/assets/dual-stacking.png
new file mode 100644
index 0000000000..3913714b42
Binary files /dev/null and b/docs/learn/.gitbook/assets/dual-stacking.png differ
diff --git a/docs/learn/.gitbook/assets/handling-principal-formats.jpeg b/docs/learn/.gitbook/assets/handling-principal-formats.jpeg
new file mode 100644
index 0000000000..c4e676b87e
Binary files /dev/null and b/docs/learn/.gitbook/assets/handling-principal-formats.jpeg differ
diff --git a/docs/learn/.gitbook/assets/image (1) (1) (1) (1) (1).png b/docs/learn/.gitbook/assets/image (1) (1) (1) (1) (1).png
new file mode 100644
index 0000000000..38bbfbae84
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (1) (1) (1) (1) (1).png differ
diff --git a/docs/learn/.gitbook/assets/image (1) (1) (1) (1).png b/docs/learn/.gitbook/assets/image (1) (1) (1) (1).png
new file mode 100644
index 0000000000..21e1c72fe3
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (1) (1) (1) (1).png differ
diff --git a/docs/learn/.gitbook/assets/image (1) (1) (1).png b/docs/learn/.gitbook/assets/image (1) (1) (1).png
new file mode 100644
index 0000000000..77d893cfa5
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (1) (1) (1).png differ
diff --git a/docs/learn/.gitbook/assets/image (1) (1).png b/docs/learn/.gitbook/assets/image (1) (1).png
new file mode 100644
index 0000000000..d79336d2e2
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (1) (1).png differ
diff --git a/docs/learn/.gitbook/assets/image (1).png b/docs/learn/.gitbook/assets/image (1).png
new file mode 100644
index 0000000000..3a3b31caab
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (1).png differ
diff --git a/docs/learn/.gitbook/assets/image (10)-sbtc-bridge.png b/docs/learn/.gitbook/assets/image (10)-sbtc-bridge.png
new file mode 100644
index 0000000000..8177a76839
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (10)-sbtc-bridge.png differ
diff --git a/docs/learn/.gitbook/assets/image (10).png b/docs/learn/.gitbook/assets/image (10).png
new file mode 100644
index 0000000000..47111d002c
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (10).png differ
diff --git a/docs/learn/.gitbook/assets/image (11)-sbtc-bridge.png b/docs/learn/.gitbook/assets/image (11)-sbtc-bridge.png
new file mode 100644
index 0000000000..ac78447329
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (11)-sbtc-bridge.png differ
diff --git a/docs/learn/.gitbook/assets/image (11).png b/docs/learn/.gitbook/assets/image (11).png
new file mode 100644
index 0000000000..3716767855
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (11).png differ
diff --git a/docs/learn/.gitbook/assets/image (12)-sbtc-bridge.png b/docs/learn/.gitbook/assets/image (12)-sbtc-bridge.png
new file mode 100644
index 0000000000..9210b58c1a
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (12)-sbtc-bridge.png differ
diff --git a/docs/learn/.gitbook/assets/image (12).png b/docs/learn/.gitbook/assets/image (12).png
new file mode 100644
index 0000000000..16dc0b816b
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (12).png differ
diff --git a/docs/learn/.gitbook/assets/image (13)-sbtc-bridge.png b/docs/learn/.gitbook/assets/image (13)-sbtc-bridge.png
new file mode 100644
index 0000000000..715ec833fe
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (13)-sbtc-bridge.png differ
diff --git a/docs/learn/.gitbook/assets/image (13).png b/docs/learn/.gitbook/assets/image (13).png
new file mode 100644
index 0000000000..020878ff7d
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (13).png differ
diff --git a/docs/learn/.gitbook/assets/image (14)-sbtc-bridge.png b/docs/learn/.gitbook/assets/image (14)-sbtc-bridge.png
new file mode 100644
index 0000000000..514951c8b0
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (14)-sbtc-bridge.png differ
diff --git a/docs/learn/.gitbook/assets/image (14).png b/docs/learn/.gitbook/assets/image (14).png
new file mode 100644
index 0000000000..341e6adaba
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (14).png differ
diff --git a/docs/learn/.gitbook/assets/image (15).png b/docs/learn/.gitbook/assets/image (15).png
new file mode 100644
index 0000000000..26036ee1fa
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (15).png differ
diff --git a/docs/learn/.gitbook/assets/image (16).png b/docs/learn/.gitbook/assets/image (16).png
new file mode 100644
index 0000000000..1df8dcc9ca
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (16).png differ
diff --git a/docs/learn/.gitbook/assets/image (17).png b/docs/learn/.gitbook/assets/image (17).png
new file mode 100644
index 0000000000..26b4e9ac6c
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (17).png differ
diff --git a/docs/learn/.gitbook/assets/image (18).png b/docs/learn/.gitbook/assets/image (18).png
new file mode 100644
index 0000000000..462a9ff6b7
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (18).png differ
diff --git a/docs/learn/.gitbook/assets/image (19).png b/docs/learn/.gitbook/assets/image (19).png
new file mode 100644
index 0000000000..afa91fa7dd
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (19).png differ
diff --git a/docs/learn/.gitbook/assets/image (2) (1) (1) (1).png b/docs/learn/.gitbook/assets/image (2) (1) (1) (1).png
new file mode 100644
index 0000000000..402906fc4f
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (2) (1) (1) (1).png differ
diff --git a/docs/learn/.gitbook/assets/image (2) (1) (1).png b/docs/learn/.gitbook/assets/image (2) (1) (1).png
new file mode 100644
index 0000000000..62a239656a
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (2) (1) (1).png differ
diff --git a/docs/learn/.gitbook/assets/image (2) (1).png b/docs/learn/.gitbook/assets/image (2) (1).png
new file mode 100644
index 0000000000..4286197b58
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (2) (1).png differ
diff --git a/docs/learn/.gitbook/assets/image (2).png b/docs/learn/.gitbook/assets/image (2).png
new file mode 100644
index 0000000000..4ecdf41820
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (2).png differ
diff --git a/docs/learn/.gitbook/assets/image (20).png b/docs/learn/.gitbook/assets/image (20).png
new file mode 100644
index 0000000000..56cb1a4122
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (20).png differ
diff --git a/docs/learn/.gitbook/assets/image (21).png b/docs/learn/.gitbook/assets/image (21).png
new file mode 100644
index 0000000000..4b4b6fb18a
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (21).png differ
diff --git a/docs/learn/.gitbook/assets/image (22).png b/docs/learn/.gitbook/assets/image (22).png
new file mode 100644
index 0000000000..a2f699bc2a
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (22).png differ
diff --git a/docs/learn/.gitbook/assets/image (23).png b/docs/learn/.gitbook/assets/image (23).png
new file mode 100644
index 0000000000..4b4a055139
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (23).png differ
diff --git a/docs/learn/.gitbook/assets/image (24).png b/docs/learn/.gitbook/assets/image (24).png
new file mode 100644
index 0000000000..0f140b843b
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (24).png differ
diff --git a/docs/learn/.gitbook/assets/image (25).png b/docs/learn/.gitbook/assets/image (25).png
new file mode 100644
index 0000000000..5b26b1c9eb
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (25).png differ
diff --git a/docs/learn/.gitbook/assets/image (26).png b/docs/learn/.gitbook/assets/image (26).png
new file mode 100644
index 0000000000..c269977a82
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (26).png differ
diff --git a/docs/learn/.gitbook/assets/image (27).png b/docs/learn/.gitbook/assets/image (27).png
new file mode 100644
index 0000000000..6b3929bea8
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (27).png differ
diff --git a/docs/learn/.gitbook/assets/image (28).png b/docs/learn/.gitbook/assets/image (28).png
new file mode 100644
index 0000000000..287069d054
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (28).png differ
diff --git a/docs/learn/.gitbook/assets/image (29).png b/docs/learn/.gitbook/assets/image (29).png
new file mode 100644
index 0000000000..559c3cfed5
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (29).png differ
diff --git a/docs/learn/.gitbook/assets/image (3) (1) (1) (1).png b/docs/learn/.gitbook/assets/image (3) (1) (1) (1).png
new file mode 100644
index 0000000000..96676a53a7
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (3) (1) (1) (1).png differ
diff --git a/docs/learn/.gitbook/assets/image (3) (1) (1).png b/docs/learn/.gitbook/assets/image (3) (1) (1).png
new file mode 100644
index 0000000000..140a81590c
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (3) (1) (1).png differ
diff --git a/docs/learn/.gitbook/assets/image (3) (1).png b/docs/learn/.gitbook/assets/image (3) (1).png
new file mode 100644
index 0000000000..9577dcdcd0
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (3) (1).png differ
diff --git a/docs/learn/.gitbook/assets/image (3).png b/docs/learn/.gitbook/assets/image (3).png
new file mode 100644
index 0000000000..e697c990dd
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (3).png differ
diff --git a/docs/learn/.gitbook/assets/image (30).png b/docs/learn/.gitbook/assets/image (30).png
new file mode 100644
index 0000000000..f2d2070af7
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (30).png differ
diff --git a/docs/learn/.gitbook/assets/image (4) (1) (1).png b/docs/learn/.gitbook/assets/image (4) (1) (1).png
new file mode 100644
index 0000000000..412a18b787
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (4) (1) (1).png differ
diff --git a/docs/learn/.gitbook/assets/image (4) (1).png b/docs/learn/.gitbook/assets/image (4) (1).png
new file mode 100644
index 0000000000..214e707d20
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (4) (1).png differ
diff --git a/docs/learn/.gitbook/assets/image (4).png b/docs/learn/.gitbook/assets/image (4).png
new file mode 100644
index 0000000000..983ff96f52
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (4).png differ
diff --git a/docs/learn/.gitbook/assets/image (5) (1) (1).png b/docs/learn/.gitbook/assets/image (5) (1) (1).png
new file mode 100644
index 0000000000..b908551494
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (5) (1) (1).png differ
diff --git a/docs/learn/.gitbook/assets/image (5) (1).png b/docs/learn/.gitbook/assets/image (5) (1).png
new file mode 100644
index 0000000000..2848b17066
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (5) (1).png differ
diff --git a/docs/learn/.gitbook/assets/image (5).png b/docs/learn/.gitbook/assets/image (5).png
new file mode 100644
index 0000000000..8af2350646
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (5).png differ
diff --git a/docs/learn/.gitbook/assets/image (6) (1) (1).png b/docs/learn/.gitbook/assets/image (6) (1) (1).png
new file mode 100644
index 0000000000..b5725bb6dc
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (6) (1) (1).png differ
diff --git a/docs/learn/.gitbook/assets/image (6) (1).png b/docs/learn/.gitbook/assets/image (6) (1).png
new file mode 100644
index 0000000000..8b68423c9f
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (6) (1).png differ
diff --git a/docs/learn/.gitbook/assets/image (6).png b/docs/learn/.gitbook/assets/image (6).png
new file mode 100644
index 0000000000..a230f629d0
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (6).png differ
diff --git a/docs/learn/.gitbook/assets/image (7) (1).png b/docs/learn/.gitbook/assets/image (7) (1).png
new file mode 100644
index 0000000000..572743764d
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (7) (1).png differ
diff --git a/docs/learn/.gitbook/assets/image (7).png b/docs/learn/.gitbook/assets/image (7).png
new file mode 100644
index 0000000000..3eb1afc483
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (7).png differ
diff --git a/docs/learn/.gitbook/assets/image (8) (1).png b/docs/learn/.gitbook/assets/image (8) (1).png
new file mode 100644
index 0000000000..5e2e14ea39
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (8) (1).png differ
diff --git a/docs/learn/.gitbook/assets/image (8).png b/docs/learn/.gitbook/assets/image (8).png
new file mode 100644
index 0000000000..27ae573acc
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (8).png differ
diff --git a/docs/learn/.gitbook/assets/image (9)-sbtc-bridge.png b/docs/learn/.gitbook/assets/image (9)-sbtc-bridge.png
new file mode 100644
index 0000000000..8f6083d420
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (9)-sbtc-bridge.png differ
diff --git a/docs/learn/.gitbook/assets/image (9).png b/docs/learn/.gitbook/assets/image (9).png
new file mode 100644
index 0000000000..bc81eabb22
Binary files /dev/null and b/docs/learn/.gitbook/assets/image (9).png differ
diff --git a/docs/learn/.gitbook/assets/image 11-with-fordefi.png b/docs/learn/.gitbook/assets/image 11-with-fordefi.png
new file mode 100644
index 0000000000..01595e7d39
Binary files /dev/null and b/docs/learn/.gitbook/assets/image 11-with-fordefi.png differ
diff --git a/docs/learn/.gitbook/assets/image 16-with-fordefi.png b/docs/learn/.gitbook/assets/image 16-with-fordefi.png
new file mode 100644
index 0000000000..099e6b71c7
Binary files /dev/null and b/docs/learn/.gitbook/assets/image 16-with-fordefi.png differ
diff --git a/docs/learn/.gitbook/assets/image 2-with-fordefi.png b/docs/learn/.gitbook/assets/image 2-with-fordefi.png
new file mode 100644
index 0000000000..b9cb30d7a1
Binary files /dev/null and b/docs/learn/.gitbook/assets/image 2-with-fordefi.png differ
diff --git a/docs/learn/.gitbook/assets/image 22-with-fordefi.png b/docs/learn/.gitbook/assets/image 22-with-fordefi.png
new file mode 100644
index 0000000000..ff2615e114
Binary files /dev/null and b/docs/learn/.gitbook/assets/image 22-with-fordefi.png differ
diff --git a/docs/learn/.gitbook/assets/image 3-with-fordefi.png b/docs/learn/.gitbook/assets/image 3-with-fordefi.png
new file mode 100644
index 0000000000..6d0423b88b
Binary files /dev/null and b/docs/learn/.gitbook/assets/image 3-with-fordefi.png differ
diff --git a/docs/learn/.gitbook/assets/image 33 (1)-with-asigna.png b/docs/learn/.gitbook/assets/image 33 (1)-with-asigna.png
new file mode 100644
index 0000000000..c61a905f63
Binary files /dev/null and b/docs/learn/.gitbook/assets/image 33 (1)-with-asigna.png differ
diff --git a/docs/learn/.gitbook/assets/image 35-with-asigna.png b/docs/learn/.gitbook/assets/image 35-with-asigna.png
new file mode 100644
index 0000000000..e37f5211d0
Binary files /dev/null and b/docs/learn/.gitbook/assets/image 35-with-asigna.png differ
diff --git a/docs/learn/.gitbook/assets/image 36-with-asigna.png b/docs/learn/.gitbook/assets/image 36-with-asigna.png
new file mode 100644
index 0000000000..45a57ac76a
Binary files /dev/null and b/docs/learn/.gitbook/assets/image 36-with-asigna.png differ
diff --git a/docs/learn/.gitbook/assets/image 37-with-asigna.png b/docs/learn/.gitbook/assets/image 37-with-asigna.png
new file mode 100644
index 0000000000..748ca88995
Binary files /dev/null and b/docs/learn/.gitbook/assets/image 37-with-asigna.png differ
diff --git a/docs/learn/.gitbook/assets/image 38-with-asigna.png b/docs/learn/.gitbook/assets/image 38-with-asigna.png
new file mode 100644
index 0000000000..b676da7c7e
Binary files /dev/null and b/docs/learn/.gitbook/assets/image 38-with-asigna.png differ
diff --git a/docs/learn/.gitbook/assets/image 4-with-fordefi.png b/docs/learn/.gitbook/assets/image 4-with-fordefi.png
new file mode 100644
index 0000000000..3842a7c913
Binary files /dev/null and b/docs/learn/.gitbook/assets/image 4-with-fordefi.png differ
diff --git a/docs/learn/.gitbook/assets/image 42 (1)-with-asigna.png b/docs/learn/.gitbook/assets/image 42 (1)-with-asigna.png
new file mode 100644
index 0000000000..16b82a5480
Binary files /dev/null and b/docs/learn/.gitbook/assets/image 42 (1)-with-asigna.png differ
diff --git a/docs/learn/.gitbook/assets/image 43 (1)-with-asigna.png b/docs/learn/.gitbook/assets/image 43 (1)-with-asigna.png
new file mode 100644
index 0000000000..8e5cfbc05e
Binary files /dev/null and b/docs/learn/.gitbook/assets/image 43 (1)-with-asigna.png differ
diff --git a/docs/learn/.gitbook/assets/image 44-with-asigna.png b/docs/learn/.gitbook/assets/image 44-with-asigna.png
new file mode 100644
index 0000000000..e09c9131d4
Binary files /dev/null and b/docs/learn/.gitbook/assets/image 44-with-asigna.png differ
diff --git a/docs/learn/.gitbook/assets/image 45 (1)-with-asigna.png b/docs/learn/.gitbook/assets/image 45 (1)-with-asigna.png
new file mode 100644
index 0000000000..30ad78dfbe
Binary files /dev/null and b/docs/learn/.gitbook/assets/image 45 (1)-with-asigna.png differ
diff --git a/docs/learn/.gitbook/assets/image 46-with-asigna.png b/docs/learn/.gitbook/assets/image 46-with-asigna.png
new file mode 100644
index 0000000000..c78859d24f
Binary files /dev/null and b/docs/learn/.gitbook/assets/image 46-with-asigna.png differ
diff --git a/docs/learn/.gitbook/assets/image 47-with-asigna.png b/docs/learn/.gitbook/assets/image 47-with-asigna.png
new file mode 100644
index 0000000000..186243f9cf
Binary files /dev/null and b/docs/learn/.gitbook/assets/image 47-with-asigna.png differ
diff --git a/docs/learn/.gitbook/assets/image 48 (1).png b/docs/learn/.gitbook/assets/image 48 (1).png
new file mode 100644
index 0000000000..28bb295217
Binary files /dev/null and b/docs/learn/.gitbook/assets/image 48 (1).png differ
diff --git a/docs/learn/.gitbook/assets/image 5-with-fordefi.png b/docs/learn/.gitbook/assets/image 5-with-fordefi.png
new file mode 100644
index 0000000000..6edd5519d7
Binary files /dev/null and b/docs/learn/.gitbook/assets/image 5-with-fordefi.png differ
diff --git a/docs/learn/.gitbook/assets/image 51.png b/docs/learn/.gitbook/assets/image 51.png
new file mode 100644
index 0000000000..1068a1749b
Binary files /dev/null and b/docs/learn/.gitbook/assets/image 51.png differ
diff --git a/docs/learn/.gitbook/assets/image 52.png b/docs/learn/.gitbook/assets/image 52.png
new file mode 100644
index 0000000000..1e2f1817fa
Binary files /dev/null and b/docs/learn/.gitbook/assets/image 52.png differ
diff --git a/docs/learn/.gitbook/assets/image 54.png b/docs/learn/.gitbook/assets/image 54.png
new file mode 100644
index 0000000000..b631433dc0
Binary files /dev/null and b/docs/learn/.gitbook/assets/image 54.png differ
diff --git a/docs/learn/.gitbook/assets/image 58 (1).png b/docs/learn/.gitbook/assets/image 58 (1).png
new file mode 100644
index 0000000000..cffb1e01c9
Binary files /dev/null and b/docs/learn/.gitbook/assets/image 58 (1).png differ
diff --git a/docs/learn/.gitbook/assets/image 59 (1).png b/docs/learn/.gitbook/assets/image 59 (1).png
new file mode 100644
index 0000000000..2f38ecdc2f
Binary files /dev/null and b/docs/learn/.gitbook/assets/image 59 (1).png differ
diff --git a/docs/learn/.gitbook/assets/image 6-with-fordefi.png b/docs/learn/.gitbook/assets/image 6-with-fordefi.png
new file mode 100644
index 0000000000..55f9302b83
Binary files /dev/null and b/docs/learn/.gitbook/assets/image 6-with-fordefi.png differ
diff --git a/docs/learn/.gitbook/assets/image 61.png b/docs/learn/.gitbook/assets/image 61.png
new file mode 100644
index 0000000000..511198ba49
Binary files /dev/null and b/docs/learn/.gitbook/assets/image 61.png differ
diff --git a/docs/learn/.gitbook/assets/image 63.png b/docs/learn/.gitbook/assets/image 63.png
new file mode 100644
index 0000000000..1baf7eb30e
Binary files /dev/null and b/docs/learn/.gitbook/assets/image 63.png differ
diff --git a/docs/learn/.gitbook/assets/image 64.png b/docs/learn/.gitbook/assets/image 64.png
new file mode 100644
index 0000000000..bda195f724
Binary files /dev/null and b/docs/learn/.gitbook/assets/image 64.png differ
diff --git a/docs/learn/.gitbook/assets/image 67.png b/docs/learn/.gitbook/assets/image 67.png
new file mode 100644
index 0000000000..3d9caedca8
Binary files /dev/null and b/docs/learn/.gitbook/assets/image 67.png differ
diff --git a/docs/learn/.gitbook/assets/image 68.png b/docs/learn/.gitbook/assets/image 68.png
new file mode 100644
index 0000000000..c276c29218
Binary files /dev/null and b/docs/learn/.gitbook/assets/image 68.png differ
diff --git a/docs/learn/.gitbook/assets/image 69.png b/docs/learn/.gitbook/assets/image 69.png
new file mode 100644
index 0000000000..ce091cec2b
Binary files /dev/null and b/docs/learn/.gitbook/assets/image 69.png differ
diff --git a/docs/learn/.gitbook/assets/image 7-with-fordefi.png b/docs/learn/.gitbook/assets/image 7-with-fordefi.png
new file mode 100644
index 0000000000..26d2b2a603
Binary files /dev/null and b/docs/learn/.gitbook/assets/image 7-with-fordefi.png differ
diff --git a/docs/learn/.gitbook/assets/image 74.png b/docs/learn/.gitbook/assets/image 74.png
new file mode 100644
index 0000000000..a9a9a34bd7
Binary files /dev/null and b/docs/learn/.gitbook/assets/image 74.png differ
diff --git a/docs/learn/.gitbook/assets/image 75 (1) (1).png b/docs/learn/.gitbook/assets/image 75 (1) (1).png
new file mode 100644
index 0000000000..55bbbe3eca
Binary files /dev/null and b/docs/learn/.gitbook/assets/image 75 (1) (1).png differ
diff --git a/docs/learn/.gitbook/assets/image 75 (1).png b/docs/learn/.gitbook/assets/image 75 (1).png
new file mode 100644
index 0000000000..55bbbe3eca
Binary files /dev/null and b/docs/learn/.gitbook/assets/image 75 (1).png differ
diff --git a/docs/learn/.gitbook/assets/image 78 (1).png b/docs/learn/.gitbook/assets/image 78 (1).png
new file mode 100644
index 0000000000..3aeef02d16
Binary files /dev/null and b/docs/learn/.gitbook/assets/image 78 (1).png differ
diff --git a/docs/learn/.gitbook/assets/image 8-with-fordefi.png b/docs/learn/.gitbook/assets/image 8-with-fordefi.png
new file mode 100644
index 0000000000..1d60b4bce2
Binary files /dev/null and b/docs/learn/.gitbook/assets/image 8-with-fordefi.png differ
diff --git a/docs/learn/.gitbook/assets/image 80.png b/docs/learn/.gitbook/assets/image 80.png
new file mode 100644
index 0000000000..351df29025
Binary files /dev/null and b/docs/learn/.gitbook/assets/image 80.png differ
diff --git a/docs/learn/.gitbook/assets/image 85.png b/docs/learn/.gitbook/assets/image 85.png
new file mode 100644
index 0000000000..fe418d2a94
Binary files /dev/null and b/docs/learn/.gitbook/assets/image 85.png differ
diff --git a/docs/learn/.gitbook/assets/image 86.png b/docs/learn/.gitbook/assets/image 86.png
new file mode 100644
index 0000000000..d253139871
Binary files /dev/null and b/docs/learn/.gitbook/assets/image 86.png differ
diff --git a/docs/learn/.gitbook/assets/image 92.png b/docs/learn/.gitbook/assets/image 92.png
new file mode 100644
index 0000000000..510d2f5c99
Binary files /dev/null and b/docs/learn/.gitbook/assets/image 92.png differ
diff --git a/docs/learn/.gitbook/assets/image 94.png b/docs/learn/.gitbook/assets/image 94.png
new file mode 100644
index 0000000000..ec171c271c
Binary files /dev/null and b/docs/learn/.gitbook/assets/image 94.png differ
diff --git a/docs/learn/.gitbook/assets/image 95.png b/docs/learn/.gitbook/assets/image 95.png
new file mode 100644
index 0000000000..08abb6b42c
Binary files /dev/null and b/docs/learn/.gitbook/assets/image 95.png differ
diff --git a/docs/learn/.gitbook/assets/image.png b/docs/learn/.gitbook/assets/image.png
new file mode 100644
index 0000000000..de29d8de4d
Binary files /dev/null and b/docs/learn/.gitbook/assets/image.png differ
diff --git a/docs/learn/.gitbook/assets/pox-light.png b/docs/learn/.gitbook/assets/pox-light.png
new file mode 100644
index 0000000000..54713ec366
Binary files /dev/null and b/docs/learn/.gitbook/assets/pox-light.png differ
diff --git a/docs/learn/.gitbook/assets/pox.png b/docs/learn/.gitbook/assets/pox.png
new file mode 100644
index 0000000000..2f03fd4127
Binary files /dev/null and b/docs/learn/.gitbook/assets/pox.png differ
diff --git a/docs/learn/.gitbook/assets/sandbox-faucet.png b/docs/learn/.gitbook/assets/sandbox-faucet.png
new file mode 100644
index 0000000000..60ab2f7c4f
Binary files /dev/null and b/docs/learn/.gitbook/assets/sandbox-faucet.png differ
diff --git a/docs/learn/.gitbook/assets/stacks-circle.png b/docs/learn/.gitbook/assets/stacks-circle.png
new file mode 100644
index 0000000000..16265bb06c
Binary files /dev/null and b/docs/learn/.gitbook/assets/stacks-circle.png differ
diff --git a/docs/learn/.gitbook/assets/usdc-deposit.png b/docs/learn/.gitbook/assets/usdc-deposit.png
new file mode 100644
index 0000000000..1a41139ea4
Binary files /dev/null and b/docs/learn/.gitbook/assets/usdc-deposit.png differ
diff --git a/docs/learn/.gitbook/assets/usdc-withdrawal.png b/docs/learn/.gitbook/assets/usdc-withdrawal.png
new file mode 100644
index 0000000000..15b9656a26
Binary files /dev/null and b/docs/learn/.gitbook/assets/usdc-withdrawal.png differ
diff --git a/docs/learn/.gitbook/assets/usdcx-bridge-app.png b/docs/learn/.gitbook/assets/usdcx-bridge-app.png
new file mode 100644
index 0000000000..728909f8d0
Binary files /dev/null and b/docs/learn/.gitbook/assets/usdcx-bridge-app.png differ
diff --git a/docs/learn/.gitbook/assets/usdcx-bridge.png b/docs/learn/.gitbook/assets/usdcx-bridge.png
new file mode 100644
index 0000000000..0367a79652
Binary files /dev/null and b/docs/learn/.gitbook/assets/usdcx-bridge.png differ
diff --git a/docs/learn/README.md b/docs/learn/README.md
new file mode 100644
index 0000000000..0ef18a7721
--- /dev/null
+++ b/docs/learn/README.md
@@ -0,0 +1,89 @@
+---
+layout:
+ width: default
+ title:
+ visible: true
+ description:
+ visible: true
+ tableOfContents:
+ visible: true
+ outline:
+ visible: true
+ pagination:
+ visible: true
+ metadata:
+ visible: true
+---
+
+# Introduction
+
+
+
+{% hint style="info" %}
+For the official Stacks whitepaper: [https://stacks-network.github.io/stacks/stacks.pdf](https://stacks-network.github.io/stacks/stacks.pdf)
+{% endhint %}
+
+### Stacks: The TL;DR
+
+Stacks activates the Bitcoin economy. Bitcoin is the most adopted, most valuable, and most decentralized cryptocurrency. The Stacks L2 enables fast, cheap BTC and full-featured smart contracts on the L2 without modifying Bitcoin itself. Users and developers can use BTC in their apps and pay gas fees with BTC. All transactions on Stacks L2 are secured by Bitcoin L1 with 100% finality, enabling you to build apps and digital assets that are integrated
with Bitcoin security.
+
+The Stacks layer for smart contracts has the following innovations that make it unique:
+
+**S**: Secured by the entire hash power of Bitcoin (Bitcoin finality).\
+**T**: Trust-minimized Bitcoin peg mechanism; write to Bitcoin.\
+**A**: Atomic BTC swaps and assets owned by BTC addresses.\
+**C**: Clarity language for safe, decidable smart contracts.\
+**K**: Knowledge of full Bitcoin state; read from Bitcoin.\
+**S**: Scalable, fast transactions that settle on Bitcoin.
+
+#### All of this is accomplished by three core components:
+
+{% stepper %}
+{% step %}
+#### Proof of Transfer
+
+Proof of Transfer (PoX) is the block production mechanism of the Stacks chain. Essentially, it attempts to recreate the block production patterns of PoW programmatically. Stacks miners spend BTC for a chance to mine new Stacks blocks. Under the hood, this block production mechanism anchors Stacks blocks to Bitcoin blocks, making it as hard to reverse a Stacks block as it is to reverse a Bitcoin block. That's a big claim, and we unpack it in further detail in the sections on Nakamoto block production.
+
+[Learn more about PoX](stacks-101/proof-of-transfer.md)
+{% endstep %}
+
+{% step %}
+#### Clarity
+
+Clarity is the smart contract language that Stacks uses. It has been designed from the ground up to make it easier for developers to write safe, secure smart contracts. Additionally, since it has been purpose-built for Stacks and Bitcoin, there are built-in functions for reading Bitcoin state, which means you can use Bitcoin state to perform actions in Clarity. For example, you could set up a check to make sure a particular Bitcoin transaction has occurred before executing a mint function in Clarity, which just so happens to be what happens with the third component: sBTC.
+
+[Learn more about Clarity](clarity/)
+{% endstep %}
+
+{% step %}
+#### sBTC
+
+sBTC is the trust-minimized 2-way Bitcoin peg on the Stacks layer. sBTC is the key to making Bitcoin programmable and bringing full smart contract functionality to Bitcoin via Stacks. sBTC is not a federation, but operates as an open-network, decentralized 2-way peg solution to bring smart contract functionality to Bitcoin with as little counterparty risk as possible.
+
+[Learn more about sBTC](sbtc/)
+{% endstep %}
+{% endstepper %}
+
+***
+
+### Why you need to learn the fundamentals of Stacks?
+
+Stacks fundamentals give you the intuition to build apps that are safer, more Bitcoin-aligned, and more future-proof. A developer who learns the basics doesn’t just write Clarity—they build apps that actually _feel like_ Bitcoin apps.
+
+1. You'll build apps that actually leverage Bitcoin
+2. You'll avoid costly design mistakes
+3. You'll write better smart contracts
+4. You'll use sBTC and Bitcoin writes correctly
+
+***
+
+### What to learn next?
+
+Stacks 101 Really dive into the nuts and bolts of how Stacks is built on Bitcoin. stacks-101 Network Fundamentals Learn about accounts, testnets, SIPs, authentication, BNS, and more. network-fundamentals Block Production How do Stacks blocks get validated and mined? block-production Transactions Learn about the lifecycle of a transaction on Stacks. transactions Clarity Discover the philosophy and design principles of the Clarity smart contract language. clarity sBTC Understand how bitcoin is unwrapped into a productive and programmable asset. sbtc Dual Stacking A financial innovation on top of the core foundation of Stacking. Earn bitcoin with bitcoin. dual-stacking
+
+***
+
+### Additional Resources
+
+* \[[Stacks YT](https://youtu.be/0erpW7IEo6Y?si=Ldu4RlVVnLqOL4eP)] How Stacks Will Grow In 2025 With Stacks Founder Muneeb Ali
+* \[[Token2049 Dubai](https://youtu.be/DFTXAOmi0es?si=sMOO6Yfj_TCVdFTF)] Muneeb Ali - Building Bitcoin’s Future: The Role of Stacks L2
diff --git a/docs/learn/SUMMARY.md b/docs/learn/SUMMARY.md
new file mode 100644
index 0000000000..bd3ca9f5ba
--- /dev/null
+++ b/docs/learn/SUMMARY.md
@@ -0,0 +1,74 @@
+# Table of contents
+
+* [Introduction](README.md)
+* [Stacks 101](stacks-101/README.md)
+ * [What Is Stacks?](stacks-101/what-is-stacks.md)
+ * [The Bitcoin Connection](stacks-101/bitcoin-connection.md)
+ * [Proof of Transfer (PoX)](stacks-101/proof-of-transfer.md)
+ * [Stacks Among Other Layers](stacks-101/stacks-among-other-layers.md)
+ * [Financial Incentive And Security Budget](stacks-101/financial-incentive-and-security-budget.md)
+* [Network Fundamentals](network-fundamentals/README.md)
+ * [Network Basics](network-fundamentals/network-basics.md)
+ * [Mainnet and Testnets](network-fundamentals/mainnet-and-testnets.md)
+ * [Wallets & Accounts](network-fundamentals/wallets-and-accounts.md)
+ * [Authentication](network-fundamentals/authentication.md)
+ * [Bitcoin Name System](network-fundamentals/bitcoin-name-system.md)
+ * [SIPs](network-fundamentals/sips.md)
+ * [Technical Specifications](network-fundamentals/technical-specifications/README.md)
+ * [Audits](network-fundamentals/technical-specifications/audits.md)
+* [Block Production](block-production/README.md)
+ * [Mining](block-production/mining.md)
+ * [Signing](block-production/signing.md)
+ * [Bitcoin Finality](block-production/bitcoin-finality.md)
+ * [Bitcoin Reorgs](block-production/bitcoin-reorgs.md)
+ * [Stacking](block-production/stacking.md)
+* [Transactions](transactions/README.md)
+ * [How Transactions Work](transactions/how-transactions-work.md)
+ * [Post Conditions](transactions/post-conditions.md)
+* [Clarity](clarity/README.md)
+ * [Decidability](clarity/decidability.md)
+* [sBTC](sbtc/README.md)
+ * [Core Features](sbtc/core-features.md)
+ * [sBTC Operations](sbtc/sbtc-operations/README.md)
+ * [Deposit](sbtc/sbtc-operations/deposit.md)
+ * [Withdrawal](sbtc/sbtc-operations/withdrawal.md)
+ * [Deposit vs Withdrawal Times](sbtc/sbtc-operations/deposit-vs-withdrawal-times.md)
+ * [Emily API](sbtc/emily-api.md)
+ * [Peg Wallet UTXO](sbtc/peg-wallet-utxo.md)
+ * [Clarity Contracts](sbtc/clarity-contracts/README.md)
+ * [sBTC Signers](sbtc/clarity-contracts/sbtc-signers.md)
+ * [sBTC Token](sbtc/clarity-contracts/sbtc-token.md)
+ * [sBTC Registry](sbtc/clarity-contracts/sbtc-registry.md)
+ * [sBTC Withdrawal](sbtc/clarity-contracts/sbtc-withdrawal.md)
+ * [sBTC Deposit](sbtc/clarity-contracts/sbtc-deposit.md)
+ * [sbtc bootstrap signers](sbtc/clarity-contracts/sbtc-bootstrap-signers.md)
+ * [Auxiliary Features](sbtc/auxiliary-features/README.md)
+ * [Transaction Fee Sponsorship](sbtc/auxiliary-features/transaction-fee-sponsorship.md)
+ * [Signer Wallet Rotation](sbtc/auxiliary-features/signer-wallet-rotation.md)
+ * [Walkthroughs](sbtc/walkthroughs/README.md)
+ * [Signer Process Walkthrough](sbtc/walkthroughs/signer-process-walkthrough.md)
+ * [sBTC Transaction Walkthrough](sbtc/walkthroughs/sbtc-transaction-walkthrough.md)
+ * [Using the sBTC Bridge App](sbtc/using-the-sbtc-bridge-app/README.md)
+ * [How to Use the sBTC Bridge with Xverse/Leather](sbtc/using-the-sbtc-bridge-app/how-to-use-the-sbtc-bridge.md)
+ * [How to Use the sBTC Bridge with Fordefi](sbtc/using-the-sbtc-bridge-app/how-to-use-the-sbtc-bridge-with-fordefi.md)
+ * [How to Use the sBTC Bridge with Asigna](sbtc/using-the-sbtc-bridge-app/how-to-use-the-sbtc-bridge-with-asigna.md)
+ * [Security Model of sBTC](sbtc/security-model-of-sbtc/README.md)
+ * [sBTC Audits](sbtc/security-model-of-sbtc/sbtc-audits.md)
+ * [sBTC FAQ](sbtc/sbtc-faq.md)
+* [Dual Stacking](dual-stacking/README.md)
+ * [How to Start Dual Stacking](dual-stacking/how-to-start-dual-stacking/README.md)
+ * [Dual Stack with Fordefi](dual-stacking/how-to-start-dual-stacking/using-fordefi.md)
+ * [Dual Stack with Asigna](dual-stacking/how-to-start-dual-stacking/using-asigna.md)
+ * [Dual Stack with Leather](dual-stacking/how-to-start-dual-stacking/using-leather.md)
+ * [Economic Model](dual-stacking/economic-model.md)
+ * [Dual Stacking Smart Contract](dual-stacking/dual-stacking-smart-contract.md)
+ * [FAQ](dual-stacking/faq.md)
+* [Bridging](bridging/README.md)
+ * [USDCx](bridging/usdcx/README.md)
+ * [Operations](bridging/usdcx/operations.md)
+ * [Contracts](bridging/usdcx/contracts/README.md)
+ * [usdcx-v1](bridging/usdcx/contracts/usdcx-v1.md)
+ * [usdcx-token](bridging/usdcx/contracts/usdcx-token.md)
+ * [USDCx Bridge App](bridging/usdcx/bridge-app/README.md)
+ * [Migrating aeUSDC](bridging/usdcx/bridge-app/migrating-aeusdc.md)
+ * [FAQ](bridging/usdcx/faq.md)
diff --git a/docs/learn/block-production/README.md b/docs/learn/block-production/README.md
new file mode 100644
index 0000000000..62bdee720e
--- /dev/null
+++ b/docs/learn/block-production/README.md
@@ -0,0 +1,35 @@
+# Block Production
+
+Block production is a key concept to understand how Stacks operates under the hood. This section walks through the three main actions that need to happen for the Stacks chain to operate.
+
+{% stepper %}
+{% step %}
+#### Mining
+
+Miners are responsible for building and proposing new blocks on the Stacks chain.
+{% endstep %}
+
+{% step %}
+#### Signing
+
+Signing is the process used to validate blocks and sign sBTC deposits and withdrawals. Stackers participate in signing once they meet stacking prerequisites.
+{% endstep %}
+
+{% step %}
+#### Stacking
+
+Stacking is an action performed by stackers that is a necessary prerequisite to signing. It enables participation in validation and earning rewards.
+{% endstep %}
+{% endstepper %}
+
+There are two primary parties in Stacks block production: miners and stackers. Miners build and propose new blocks, while stackers validate those blocks and sign sBTC deposits and withdrawals. Stacking enables stackers to participate in signing.
+
+{% hint style="info" %}
+For an in-depth technical overview of block production after the Nakamoto Upgrade, see SIP-021:
+
+https://github.com/stacksgov/sips/blob/feat/sip-021-nakamoto/sips/sip-021/sip-021-nakamoto.md
+{% endhint %}
+
+Here's a diagram outlining the block production process under Nakamoto rules. The following docs dig into each part in detail.
+
+
diff --git a/docs/learn/block-production/bitcoin-finality.md b/docs/learn/block-production/bitcoin-finality.md
new file mode 100644
index 0000000000..a86c441975
--- /dev/null
+++ b/docs/learn/block-production/bitcoin-finality.md
@@ -0,0 +1,46 @@
+# Bitcoin Finality
+
+The concept of 100% Bitcoin finality is crucial to the design of Stacks. This is what turns Stacks into a true Bitcoin L2 and allows it to leverage all of the security inherent in Bitcoin.
+
+Finality refers to the point at which transactions are irreversible. Once a blockchain reaches finality, it is nearly impossible to change the ledger's history without undertaking extraordinary measures that are often computationally and economically prohibitive.
+
+When we talk about Stacks blocks having 100% Bitcoin finality, we mean that they are as hard to reverse as Bitcoin transactions themselves.
+
+That's a bold claim, so how does Stacks accomplish that?
+
+As discussed above, miners are responsible for producing Stacks blocks in their tenure, which corresponds to a single Bitcoin block. As part of their block commit transaction, which is the transaction that previously committed the hash of the next Stacks block to the Bitcoin chain, miners will instead be required to add an indexed block hash.
+
+The indexed block hash is the hash of the first block produced by the last Stacks miner in their tenure. This is the SHA512/256 hash of both the consensus hash of all previously-accepted Bitcoin transactions that Stacks recognizes, as well as the hash of the block itself.
+
+This will anchor the Stacks chain history to Bitcoin up to the start of the previous miner's tenure, as well as all causally-dependent Bitcoin state that Stacks has processed. This ensures Bitcoin finality, resolves miner connectivity issues by putting fork prevention on stackers, and allows nodes with up-to-date copies of the Stacks chain state to identify which Stacks blocks are affected by a Bitcoin reorg and recover the affected Stacks transactions.
+
+This relationship between Stackers, miners, Bitcoin blocks, and Stacks blocks is what maintains Bitcoin finality while allowing miners to rapidly produce Stacks blocks. Bitcoin finality is achieved because at every Bitcoin block N + 1, the state of the Stacks chain as of the start of tenure N is written to Bitcoin. Even if at a future date all of the former Stackers’ signing keys were compromised, they would be unable to rewrite Stacks history for tenure N without rewriting Bitcoin history back to tenure N + 1.
+
+Because of this, Stacks transactions can be considered to have Bitcoin finality after the tenure they are a part of concludes, or Bitcoin block N + 1. As an example, if I initiate a Stacks transaction that gets confirmed by a Stacks miner, at the conclusion of that miner's tenure (the end of the current Bitcoin block) that transaction will be written to Bitcoin as part of the Stacks chain state and all future miners are required to build off of that chain tip, making reversing the transaction as difficult as reversing the corresponding Bitcoin transaction.
+
+{% hint style="info" %}
+Key point: At every Bitcoin block N + 1 the state of the Stacks chain as of the start of tenure N is anchored to Bitcoin. This makes reversing Stacks history for tenure N as hard as rewriting Bitcoin history back to N + 1.
+{% endhint %}
+
+## Nakamoto Transactions and Bitcoin Reorgs
+
+If Nakamoto transactions follow Bitcoin finality, what happens if Bitcoin forks?
+
+In order to answer this question, we need to distinguish between two types of Stacks transactions: Bitcoin-reliant and internal.
+
+{% hint style="info" %}
+* **Bitcoin-reliant** transactions are transactions that read Bitcoin state. If Bitcoin forks, these transactions will change. For these, you cannot do better than following Bitcoin finality. For example, if you moved BTC from L1 to L2, you must wait for Bitcoin finality before your L2 BTC can be used (you don’t have any L2 BTC if the L1 transaction becomes unconfirmed due to a fork).
+* **Internal** transactions don't rely on Bitcoin state, and thus won't change if Bitcoin forks. These can have faster confirmations because even if Bitcoin forks, signers can ensure they are re-processed in the same order.
+{% endhint %}
+
+The key takeaway is this:
+
+Under Nakamoto Stacks, transactions won’t impactfully reorganize due to a Bitcoin fork. Not only is reorging relatively infrequent, but transactions on Stacks that got reorganized due to a Bitcoin fork behave just as reorganized Bitcoin transactions do. With some future analysis, transactions purely on the L2 chain may one day be entirely unaffected.
+
+
+
+Read more about Bitcoin reorg behavior
+
+If you are interested in learning more about how this works, see the [Bitcoin Reorgs](bitcoin-reorgs.md) page of the docs.
+
+
diff --git a/docs/learn/block-production/bitcoin-reorgs.md b/docs/learn/block-production/bitcoin-reorgs.md
new file mode 100644
index 0000000000..86dfec31ec
--- /dev/null
+++ b/docs/learn/block-production/bitcoin-reorgs.md
@@ -0,0 +1,33 @@
+# Bitcoin Reorgs
+
+Under Nakamoto Stacks transactions don’t impactfully reorganize due to a Bitcoin fork. Not only is reorging relatively infrequent, but transactions on Stacks that got reorganized due to a Bitcoin fork behave just as reorganized Bitcoin transactions do. With some future analysis, transactions purely on the L2 chain may one day be entirely unaffected.
+
+Understanding this concept fundamentally comes down to understanding finality on post-Nakamoto Stacks.
+
+{% hint style="info" %}
+Under Nakamoto the Stacks chain won’t fork on its own. It is designed not to fork with only special exceptions, and it’s entirely infeasible for Stacks to fork on its own if even 31% of Stackers don’t want it to fork, and even then it would likely only happen within the span of a single tenure.
+
+The only case in which Stacks forks post-Nakamoto is if Bitcoin forks cause it to fork.
+{% endhint %}
+
+Under Nakamoto, instead of winning the right to make a single block, miners win the right to make a ton of blocks, and during that time we say they’re under “tenure”. Every single Stacks block produced in a tenure requires at least 70% of Stackers to approve (sign) it for it to be included in the Stacks blockchain. The Stackers are watching the Bitcoin blockchain and will only sign blocks from the miner that won the latest sortition.
+
+Now, let’s imagine that Bitcoin reorganizes itself and the Stackers were watching a Bitcoin fork that is now sub-optimal. The Stackers would essentially go back in time to the latest common sortition between the fork that they were watching and the new best Bitcoin fork and start signing the blocks within the tenures from there. Note that 70% of the Stackers will be doing the same thing all at once, and the moment 70% agree to start signing from the latest tenure on the new Bitcoin fork there’s a new singularly optimal Stacks blockchain.
+
+So what happens to the transactions that were confirmed on the tenure that got reorganized? Nothing. Still in the mempool as if the reorganized tenure didn’t happen. For anything within the Stacks blockchain everything is fine.
+
+This is 1:1 with a Bitcoin fork reorganizing a Bitcoin transaction. You shouldn’t consider a transaction on Bitcoin final if it’s near the chain tip, and you shouldn’t consider a Stacks transaction final if it’s near the tenure tip.
+
+
+
+Replaying Transactions
+
+Since 70% of the signers have to sign any Stacks block included in the chain at least 70% of signers know the state of the chain before and after a Bitcoin fork causes a Stacks reorg.
+
+There’s a catch to this that makes enforcing it difficult: if a transaction were dependent on something on the Bitcoin blockchain that also got reorganized (a peg-in, for example), that transaction would now be invalid. Taint analysis is when you attempt to answer the questions “which transaction interacted with the now-orphaned Bitcoin blockchain in a way that makes them invalid (tainted) in the new chain” and then also “which transactions interacted with the now invalid (tainted) transaction such that they are now also invalid”. There’s a cascading effect, but enforcing any kind of replay requires that the Stackers and the Miners can identify which transactions can get replayed at all.
+
+Taint analysis, and subsequently replay enforcement, can be added in the future.
+
+For the first release, Nakamoto explicitly ties the Stacks blockchain to the Bitcoin blockchain such that there’s only one optimal Stacks fork tied to Bitcoin at any given point. This is completely 1:1 with the Bitcoin Blockchain behavior, but on the tenure scale.
+
+
diff --git a/docs/learn/block-production/mining.md b/docs/learn/block-production/mining.md
new file mode 100644
index 0000000000..60b6677f0f
--- /dev/null
+++ b/docs/learn/block-production/mining.md
@@ -0,0 +1,152 @@
+# Mining
+
+source: Hiro blog
+
+{% hint style="info" %}
+This is conceptual guide that covers how mining works. For practical steps on how to setup your own miner please refer to the guides to running a miner on [mainnet](https://app.gitbook.com/s/4cpTb2lbw0LAOuMHrvhA/run-a-miner/mine-mainnet-stacks-tokens) and [testnet](https://app.gitbook.com/s/4cpTb2lbw0LAOuMHrvhA/run-a-miner/mine-testnet-stacks-tokens).
+{% endhint %}
+
+### Miner Tenures
+
+In previous version of Stacks (before the Nakamoto Upgrade), Stacks miners would mine new Stacks blocks at a one-to-one cadence with Bitcoin blocks.
+
+After Nakamoto, this is no longer the case. Under Nakamoto rules, miners are instead selected for a tenure that corresponds to a Bitcoin block. During this tenure, miners build and propose several Stacks blocks (roughly every 10 seconds) and stackers will approve and append them (next section).
+
+To be considered for a tenure, a miner must have a block commit included in a Bitcoin block. If a miner wishes to update their commitment after submission, they may use Bitcoin Replace-By-Fee.
+
+### Coinbase rewards
+
+Miners receive coinbase rewards for tenures they win.
+
+The reward amounts are:
+
+* 1000 STX per tenure are released in the first 4 years of mining
+* 500 STX per tenure are released during the following 4 years
+* 250 STX per tenure are released during the following 4 years
+* 125 STX per tenure are released from then on indefinitely.
+
+These "halvings" are synchronized with Bitcoin halvings.
+
+
+
+### Transaction fees
+
+Miners receive Stacks fees for transactions mined in any block they produce.
+
+### Reward maturity
+
+Block rewards and transaction fees take 100 blocks on the Bitcoin blockchain to mature. After successfully mining a block your rewards appear in your Stacks account after \~24 hours.
+
+### Mining with proof-of-transfer
+
+Miners commit Bitcoin to **two** addresses in every leader block commit. The amount committed to each address must be the same. The addresses are chosen from the current reward set of stacking participants. Addresses are chosen using a verifiable-random-function, and determining the correct two addresses for a given block requires monitoring the Stacks chain.
+
+For more detailed information on this process, read [SIP-007](https://github.com/stacksgov/sips/blob/main/sips/sip-007/sip-007-stacking-consensus.md), which describes proof of transfer in detail.
+
+
+
+PoX mining is a modification of Proof-of-Burn (PoB) mining, where instead of sending the committed Bitcoin to a burn address, it's transferred to eligible STX holders that participate in the stacking protocol.
+
+{% hint style="info" %}
+A PoX miner can only receive newly minted STX tokens when they transfer Bitcoin to eligible owners of STX tokens
+{% endhint %}
+
+
+
+Miners run Stacks nodes with mining enabled to participate in the PoX mechanism. The node implements the PoX mechanism, which ensures proper handling and incentives through four key phases:
+
+* Registration: miners register for a future election by sending consensus data to the network
+* Commitment: registered miners transfer Bitcoin to participate in the election. Committed BTC are sent to a set participating STX token holders
+* Election: a verifiable random function chooses one miner for a new tenure to write blocks on the Stacks blockchain
+* Assembly: the elected miner writes the new blocks by pulling transactions from the mempool and collects rewards in form of new STX tokens
+
+### Probability to mine next block
+
+The miner who is selected to mine the next block is chosen depending on the amount of BTC the miners sent, that is, transferred or burnt.
+
+The probability for a miner to mine the next block is determined using a variation of the Assumed Total Commitment with Carryforward (ATC-C) MEV mitigation strategy described in [this document](https://github.com/stacksgov/sips/blob/feat/sip-021-nakamoto/sips/sip-021/MEV-Report.pdf) to allocate block rewards to miners. The probability a miner will win the sortition and be granted the current tenure will be based on a function that accounts for the total block commit spend on the blocks leading up to the current sortition.
+
+You can read more about this in the [MEV section of SIP-021](https://github.com/stacksgov/sips/blob/feat/sip-021-nakamoto/sips/sip-021/sip-021-nakamoto.md#block-reward-distribution-and-mev).
+
+While there is no minimum BTC commitment enforced by the protocol, in practice, there's a floor constrained by [dust](https://unchained-capital.com/blog/dust-thermodynamics/): basically, if the fees for a transaction exceed the value of the spent output, it's considered dust. How dust is [calculated](https://github.com/bitcoin/bitcoin/blob/master/src/policy/policy.cpp#L14) depends on a number of factors, we've found 5,500 satoshis to be good lower bound per [output](https://learnmeabitcoin.com/technical/output). Bitcoin transactions from Stacks miners contain two outputs (for Proof-of-Transfer), so a commitment of at least 11,000 satoshis / block is recommended.
+
+To calculate the amount of BTC to send miners should:
+
+* Guess the price BTC/STX for the next day (100 blocks later)
+* Guess the total amount of BTCs committed by all miners
+
+Stackers are in charge of both validating and appending new blocks and conducting miner tenure changes. The next section will explain how that works, and then we'll see how this process results in Bitcoin finality.
+
+### Stacks mining in practice
+
+If you take a look at [SIgnal21's mining dashboard](https://app.signal21.io/stacks/mining), you can view some interesting data about mining on the Stacks network, including BTC spent per block, STX earned per block, the total number of miners over the course of the chain's history, and the number of miners for any given block.
+
+Many people notice the seemingly small number of miners on Stacks. Without context, this can sometimes raise eyebrows. Let's dig into how mining works on Stacks so we can understand why this isn't an issue for decentralization.
+
+Stacks miners function similarly to sequencers in L2 systems in that they are only responsible for constructing and proposing new blocks, not appending them to the chain. But unlike most Ethereum L2s that operate with just a single centralized sequencer, Stacks consistently has at least 4-5 miners with open membership allowing anyone to join.
+
+It's important to note that there are two primary parties involved in the block production process on Stacks: miners and stackers.
+
+These two roles serve complementary relationships in the [block production process](file:///), and stackers drastically reduce any potential destructive power miners have over the chain.
+
+Miners cannot reorganize the chain. In the worst case, all miners can do is omit (some kinds of) transactions, and all that is required to address this is to run your own miner.
+
+Furthermore, more miners on the network would mean fewer BTC rewards for Stackers, as miners would have to spend more of their funds on Bitcoin L1 fees rather than sending it to the Stackers.
+
+{% hint style="info" %}
+**Wouldn't more miners mean more competition, meaning more rewards?**
+
+The reason more miners means fewer rewards is because miners act economically rationally, and they don't have an unlimited amount of BTC to work with.
+
+Miners are paying their PoX commitments plus their Bitcoin fees for a chance to win the coinbase (1,000 STX) plus fees for a tenure. If there are more miners, they will each pay less, because they will have a lower chance of winning. They can't pay ever-increasing amounts of BTC because at some point they will never be profitable, so there is a limit to how much BTC they can spend in order to try and win a tenure.
+
+As they pay less, the Bitcoin fee becomes a more significant portion of their expenses, and that also decreases their odds of winning the tenure.
+
+Here's a concrete example:
+
+Let's say Stacks is trading at 1,000 Sats per STX.
+
+The total spend from all miners, if everyone is acting logically and we ignore Stacks fees, would be less than 1,000,000 Sats (1,000 STX coinbase \* 1000 Sats/STX).
+
+If that is from 5 miners, then it could be 10,000 Sats (2,000 Sats for each transaction) going to Bitcoin fees and 990,000 Sats going to PoX.
+
+If there are 100 miners, then it would be 200,000 Sats going to Bitcoin fees, and 800,000 Sats going to PoX.
+{% endhint %}
+
+This creates a natural economic equilibrium where:
+
+{% stepper %}
+{% step %}
+#### Enough miners participate to ensure blocks are produced reliably
+
+Content as above describing reliability.
+{% endstep %}
+
+{% step %}
+#### Stackers receive optimal BTC rewards
+
+Content as above describing rewards optimization.
+{% endstep %}
+
+{% step %}
+#### The network maintains censorship resistance without unnecessary mining competition
+
+Content as above describing censorship resistance.
+{% endstep %}
+{% endstepper %}
+
+This design is intentional - by having stackers as complimentary security guarantors who receive BTC rewards via PoX, Stacks achieves security without requiring an excessive number of miners competing solely to win block production rights.
+
+Unlike other chains where miners alone determine the canonical chain, Stacks' two-party system provides stronger guarantees:
+
+* Miners cannot force invalid transactions or blocks (stackers won't sign them, and even if they did, the nodes would not accept them)
+* No miner can unilaterally reorg the chain (stackers control chain finality)
+* The 70% stacker threshold signature requirement ensures broad consensus before blocks are accepted
+
+This separation of concerns between miners and stackers is what makes Stacks uniquely secure despite having a small number of miners.
+
+### What About Microblocks?
+
+Microblocks are a legacy feature of the previous version of Stacks that no longer exist. They were originally created as a way to improve transaction throughput, but without the functionality of Nakamoto, they never worked in practice.
+
+Instead of microblocks, Nakamoto instead utilizes a block production structure that creates Stacks blocks at a rapid cadence as described here.
diff --git a/docs/learn/block-production/signing.md b/docs/learn/block-production/signing.md
new file mode 100644
index 0000000000..d92f6628b3
--- /dev/null
+++ b/docs/learn/block-production/signing.md
@@ -0,0 +1,81 @@
+# Signing
+
+Stackers play an essential role in the Nakamoto system that had previously been the responsibility of miners. Before, miners both decided the contents of blocks, and decided whether or not to include them in the chain (i.e. by deciding whether or not to confirm them). In this system each actor has the following responsibilities necessary to make the system function reliably without forks:
+
+* **Miners** decide the contents of blocks.
+* **Stackers** decide whether or not the block is included in the chain.
+
+The bulk of the complexity of the Nakamoto changes is in separating these two concerns while ensuring that both mining and Stacking remain open-membership processes. **Crucially, anyone can become a miner and anyone can become a Stacker, just as before.** The most substantial changes are in getting miners and Stackers to work together in their new roles to achieve this proposal's goals.
+
+The key idea is that Stackers are required to acknowledge and validate a miner's block before it can be appended to the chain. To do so, Stackers must first agree on the canonical chain tip, and then apply (and roll back) the block on this chain tip to determine its validity. Once Stackers agree that the block is both canonical and valid, they collectively sign it and replicate it to the rest of the Stacks peer network. Only at this point do nodes append the block to their chain histories.
+
+This new behavior prevents forks from arising. If a miner builds a block atop a stale tip, Stackers will refuse to sign the block. If Stackers cannot agree on the canonical Stacks tip, then no block will be appended in the first place. While this behavior creates a new failure mode for Stacks -- namely, the chain can halt indefinitely if Stackers cannot agree on the chain tip -- this is mitigated by having a large and diverse body of Stackers such that enough of them are online at all times to meet quorum and incentivizing them via PoX rewards to act as such.
+
+### Stacker Signing
+
+{% hint style="info" %}
+You can view a list of all of the [active signers](https://explorer.hiro.so/signers?chain=mainnet) on Hiro's block explorer.
+{% endhint %}
+
+We'll cover how stacking works in the Stacking section and the sBTC signing in the sBTC section; here we'll cover the signing process as it relates to Stacks block production.
+
+The means by which Stackers agree on the canonical chain tip and agree to append blocks is tied to PoX. In each reward cycle, a Stacker clinches one or more reward slots; there are at most 4,000 reward slots per reward cycle. Stackers vote to accept blocks by producing a weighted threshold signature over the block. The signature must represent a substantial fraction of the total STX locked in PoX (the threshold), and each Stacker's share of the signature (its weight) is proportional to the fraction of locked STX it owns.
+
+The weighted threshold signature is a Schnorr signature generated through a variation of the [FROST protocol](https://eprint.iacr.org/2020/852.pdf). Each Stacker generates a signing key pair, and they collectively generate an aggregate public key for nodes to use to verify signatures computed through a distributed signing protocol. This signing protocol allocates shares of the associated aggregate private key to Stackers proportional to the number of reward slots they clinch. No Stacker learns the aggregate private key; Stackers instead compute shares of the private key and use them to compute shares of a signature, which can be combined into a single Schnorr signature.
+
+When a miner produces a block, Stackers execute a distributed signing protocol to collectively generate a single Schnorr signature for the block. Crucially, the signing protocol will succeed only if at least X% of the reward slots are accounted for in the aggregate signature. Nakamoto is currently set to use a 70% signing threshold -- at least 70% of the reward slots (by proxy, 70% of the stacked STX) must sign a block in order to append it to the Stacks blockchain.
+
+Nakamoto uses the [WSTS protocol with the FIRE extension](https://trust-machines.github.io/wsts/wsts.pdf), which admits a distributed key generation and signature generation algorithm pair whose CPU and network bandwidth complexity grows with the number of distinct Stackers. The FIRE extension enables WSTS to tolerate byzantine Stackers.
+
+Here is a diagram outlining the relationship between signing and stacking.
+
+
+
+### Validating and Appending New Blocks
+
+When miners are selected for a new tenure, they begin building new blocks from transactions in the mempool. They then send those blocks to stackers for approval. Stackers must approve the blocks with a quorum of at least 70% for them to be appended to the chain.
+
+Stackers will approve a block based on several properties:
+
+* The block is well-formed
+ * It has the correct version and mainnet/testnet flag
+ * Its header contains the right number of Stacks blocks preceding this one.
+ * Its header contains the correct total Bitcoin spent in the sortition that elected the current tenure.
+ * Its header contains the same Bitcoin block hash as the Bitcoin block that contains its tenure's block-commit transaction\*
+ * Its header contains the correct parent block ID of the immediate parent of this block.\*
+ * The transaction Merkle tree root is consistent with the transactions
+ * The state root hash matches the MARF tip root hash once all transactions are applied
+ * The block header has a valid ECDSA signature from the miner.
+ * The block header has a valid WSTS Schnorr signature from the set of Stackers.
+* All Bitcoin transactions since the last valid sortition up to (but not including) this tenure's block-commit’s Bitcoin block have been applied to the Stacks chain state\*
+* In the case of a tenure start block:
+ * The first transaction is the `TenureChange` transaction.
+ * The first transaction after the `TenureChange` transaction is a `Coinbase`.
+
+The properties marked with \* are collectively how Stacks ensures Bitcoin finality. By adhering to these properties, it ensures that miners are only able to append blocks if they build atop the correct chain tip, which also anchors the history to Bitcoin.
+
+Stackers, by validating these rules, ensure Bitcoin finality. We'll talk about this more in the next section.
+
+### Conducting Miner Tenure Changes
+
+The other primary signing responsibility in block production involves conducting tenure change transactions. As discussed in the mining section, miners will submit a `block-commit` transaction on the Bitcoin chain to initiate mining. If they are selected, stackers will detect that and create a `tenure-change` transaction.
+
+This tenure change transaction includes:
+
+| Name | Description | Representation |
+| ------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------- |
+| tenure consensus hash | Consensus hash of this tenure. Corresponds to the sortition in which the miner of this block was chosen. It may be the case that this miner's tenure gets extended across subsequent sortitions; if this happens, then this `consensus hash` value remains the same as the sortition in which the winning block-commit was mined. | 20 bytes |
+| previous tenure consensus hash | Consensus hash of the previous tenure. Corresponds to the sortition of the previous winning block-commit. | 20 bytes |
+| burn view consensus hash | Current consensus hash on the underlying burnchain. Corresponds to the last-seen sortition. | 20 bytes |
+| previous tenure end | The index block hash of the last Stacks block from the previous tenure. | 32 bytes |
+| previous tenure blocks | The number of blocks produced since the last sortition-linked tenure. | 4 bytes, big-endian |
+| cause | A flag to indicate the cause of this tenure change - 0x00 indicates that a sortition occurred, and a new miner should begin producing blocks. - 0x01 indicates that the current miner should continue producing blocks. The current miner’s tenure execution budget is reset upon processing this transaction.
| 1 byte |
+| pubkey hash | The ECDSA public key hash of the current tenure. | 20 bytes |
+
+This tenure change transaction is then sent to the newly elected miner and they must include it as the first transaction in their first block, otherwise stackers will not approve it.
+
+This process is then repeated over and over as new miners are elected for tenures.
+
+Be sure to take a look at [SIP-021](https://github.com/stacksgov/sips/blob/feat/sip-021-nakamoto/sips/sip-021/sip-021-nakamoto.md) to get a detailed description of exactly what happens under the hood during these processes.
+
+Next up, let's dig a little deeper into this idea of Bitcoin finality and how the Stacks block production mechanism achieves it.
diff --git a/docs/learn/block-production/stacking.md b/docs/learn/block-production/stacking.md
new file mode 100644
index 0000000000..484b03e2b7
--- /dev/null
+++ b/docs/learn/block-production/stacking.md
@@ -0,0 +1,197 @@
+# Stacking
+
+### Introduction
+
+Stacking rewards Stacks (STX) token holders with bitcoin for providing a valuable service to the network by locking up their tokens for a certain time and participating as consensus-critical signers. If you aren't familiar with the concept of signers in Stacks, be sure to check out the [Signing section](signing.md). This document is a conceptual overview of stacking and how it works.
+
+`pox-4.clar` is the stacking contract. If you are interested in experimenting with proof of transfer use cases including state changes, solo stacking, and pool stacking, all the functions you’ll need can be found at the deployed contract:
+
+* Testnet: https://explorer.hiro.so/txid/0xfba7f786fae1953fa56f4e56aeac053575fd48bf72360523366d739e96613da3?chain=testnet
+* Mainnet: https://explorer.hiro.so/txid/0xc6d6e6ec82cabb2d7a9f4b85fcc298778d01186cabaee01685537aca390cdb46?chain=mainnet
+
+### Stacking vs Staking
+
+While stacking on the Stacks network can be conceptually similar to staking, Stacks is not a PoS network and there are a couple key differences.
+
+There are two primary differences between stacking in Stacks and staking in PoS networks.
+
+#### Yield generated in burnchain token
+
+In staking, users lock one token and earn their yield in the same token. In stacking, users lock one token (STX) and earn a yield in the "burnchain" token (BTC), rather than the same token that was locked. In PoX, the yield comes from a finite, external source (Bitcoin deposits from Stacks miners). In PoS, the yield comes from the currency's issuance schedule itself.
+
+How are these issuance rates set? In Ethereum, issuance rates are determined by network usage. Ethereum's goal is to create a deflationary money supply, so the issuance rate is determined depending on the usage of the network. In order for an Ethereum transaction to be considered valid, it must include a base fee that is burned during transaction execution. The [issuance rate is algorithmically determined](https://ethereum.org/en/roadmap/merge/issuance/#post-merge) block-by-block depending on how much ETH is being burned by these base fees plus normal gas fees.
+
+Stacking doesn't generate yield in the same token and therefore doesn't need to issue new STX for stacking rewards. Stacking yield requires an input of an external token (BTC). Stacks does have an issuance rate and does generate new STX tokens, but that process is separate from stacking and the stacking yield mechanism.
+
+#### No slashing
+
+Although stackers do fulfill a consensus-critical role in Stacks by serving as signers, there is no concept of slashing in PoX (Proof of Transfer).
+
+Rather, if stackers do not perform their duties as signers, they simply cannot unlock their STX tokens and will not receive their BTC rewards.
+
+Stacking is a built-in action, required by the "proof-of-transfer" (PoX) mechanism. The PoX mechanism is executed by every miner on the Stacks network.
+
+{% hint style="info" %}
+Stacking functionality is implemented as a smart contract, using Clarity. Read more about [the contract](https://app.gitbook.com/s/GVj1Z9vMuEOMe7oH7Wnq/clarity/example-contracts/stacking).
+{% endhint %}
+
+### Locking and Unlocking STX
+
+When STX tokens are "locked", no transfer of STX tokens occurs. Locking STX tokens is non-custodial, and STX tokens remain in your wallet. When you initiate a stacking transaction those tokens are locked and unspendable at the protocol level, but they do not leave the stacker's wallet.
+
+At the end of the lock period, they will be automatically unlocked (spendable at the protocol level). This occurs implicitly; there is no direct transaction that unlocks them.
+
+### Stacking flow
+
+The Stacking mechanism can be presented as a flow of actions:
+
+
+
+{% stepper %}
+{% step %}
+#### Make API calls to get details about the upcoming reward cycle
+
+Query the network to discover the upcoming cycle parameters and timing.
+{% endstep %}
+
+{% step %}
+#### Confirm eligibility for a specific Stacks account
+
+Verify the account meets the minimum requirements and is eligible to participate.
+{% endstep %}
+
+{% step %}
+#### Confirm the BTC reward address and lockup duration
+
+Specify the Bitcoin address to receive payouts and input the desired lockup period.
+{% endstep %}
+
+{% step %}
+#### Broadcast the stacking transaction to lock STX
+
+The transaction is broadcast and the STX tokens are locked. This must happen before the prepare phase of the next reward cycle (the last 100 Bitcoin blocks of the ongoing reward phase).
+{% endstep %}
+
+{% step %}
+#### Reward cycles execute and BTC rewards are sent
+
+The stacking mechanism executes reward cycles and sends out rewards to the configured BTC reward address.
+{% endstep %}
+
+{% step %}
+#### Monitor unlocking timing and rewards during lockup
+
+During the lockup period, you can obtain details about unlocking timing, expected rewards, and more.
+{% endstep %}
+
+{% step %}
+#### Tokens are released after the lockup period
+
+Once the lockup period has passed, the tokens become spendable again.
+{% endstep %}
+
+{% step %}
+#### Display reward history
+
+Show historical details like earnings for previous reward cycles.
+{% endstep %}
+{% endstepper %}
+
+{% hint style="info" %}
+Keep in mind that the target duration for a reward cycle is \~2 weeks. This duration is based on the target block time of the Bitcoin network (10 minutes) and can be higher at times due to [confirmation time variances](https://www.blockchain.com/charts/median-confirmation-time) of the Bitcoin network.
+{% endhint %}
+
+### Stacking delegation flow
+
+There are two main ways you can stack: solo stacking and delegated stacking.
+
+{% stepper %}
+{% step %}
+#### Solo stacking
+
+Solo stacking follows the general stacking flow. You stack your own STX tokens and run your own signer. To operate as a solo stacker, you must have a minimum amount of STX tokens. This minimum is dynamic and can be found by viewing the [pox endpoint of the API](https://api.testnet.hiro.so/v2/pox) in the `min_threshold_ustx` field.
+{% endstep %}
+
+{% step %}
+#### Delegated stacking
+
+
+
+Delegated stacking differs:
+
+* Before stacking on behalf of a token holder, the delegator must be granted permission by the account owner. Permission is restricted to a maximum amount the delegator may stack; the maximum can be set higher than available funds. An account can be associated with only one delegator.
+* The account sets the delegation relationship. They can optionally restrict the Bitcoin reward address that must be used for payouts and specify an expiration burn block height to limit the delegation duration.
+* Delegators lock STX from different accounts ("pooling phase") until they reach the minimum required to participate in stacking.
+* Once the delegator locks enough STX, they can finalize and commit participation in the next reward cycle.
+* Some delegation relationships may allow the STX holder to receive payouts directly from the miner.
+* Delegation can terminate automatically based on expiration rules or by actively revoking delegation rights.
+{% endstep %}
+{% endstepper %}
+
+### Token holder eligibility
+
+Stacks (STX) token holders don't automatically receive stacking rewards. To participate, they must:
+
+* Commit to participation before a reward cycle begins
+* Commit at least the minimum amount of STX tokens to secure a reward slot, or pool with others to reach the minimum
+* Lock up STX tokens for a specified period
+* Provide a supported Bitcoin address to receive rewards
+* Maintain their signer software (if they operate a signer)
+
+
+
+Token holders have a variety of providers and tools to support their participation in stacking. The Stacks website contains a [list of pools and stacking options](https://www.stacks.co/learn/stacking#startstacking).
+
+### Stacking in the PoX consensus algorithm
+
+Stacking is a built-in capability of PoX and occurs through a set of actions on the Stacks blockchain. The [full proof-of-transfer implementation details](https://github.com/stacks-network/stacks-blockchain/blob/develop/sip/sip-007-stacking-consensus.md) are in SIP-007. Below is a summary of the most relevant actions of the algorithm.
+
+{% hint style="info" %}
+Note that SIP-007 describes stacking before Nakamoto. While much of the functionality remains the same, stackers now have the additional responsibility of operating as signers as outlined in [SIP-021](https://github.com/stacksgov/sips/blob/feat/sip-021-nakamoto/sips/sip-021/sip-021-nakamoto.md).
+{% endhint %}
+
+
+
+Stacking happens in reward cycles of 2100 Bitcoin blocks (roughly two weeks). Reward cycles are split into two phases: the prepare phase and the reward phase.
+
+* The prepare phase lasts 100 Bitcoin blocks and is where the new stackers for the upcoming reward phase are selected by the PoX anchor block (see SIP-007 for details).
+* Because Stacks does not fork after the Nakamoto upgrade, the PoX anchor block is always known 100 Bitcoin blocks before the start of the next reward cycle. It is the last tenure-start block that precedes the prepare phase.
+* The PoX anchor block identifies the next stackers. They have 100 Bitcoin blocks to prepare for signing Stacks blocks, including completing a Distributed Key Generation round for signing blocks.
+* The PoX contract requires stackers to register their block-signing keys when they stack or delegate-stack STX, so the entire network can validate signatures on blocks.
+
+This process is handled by [running a signer](https://app.gitbook.com/s/4cpTb2lbw0LAOuMHrvhA/run-a-signer) and then subsequently conducting stacking operations as that signer.
+
+### Stacking and Signing
+
+Stacking and signing are distinct actions, but both are necessary. Signers must stack their STX tokens, and you cannot stack STX without associated signing information. The nuance depends on solo vs delegated stacking.
+
+### Solo Stacking
+
+If you are solo stacking, you have two options for signing.
+
+#### Run your own signer
+
+You can run your own signer by following the How to Run a Signer guide. This requires technical knowledge and resources for running a machine. See the guide for details.
+
+#### Work with another signer
+
+If you don't want to run your own signer, you can collaborate with another signer and include their signature in your stacking transactions. Details on how to do this are in the [Stack STX](https://app.gitbook.com/s/4cpTb2lbw0LAOuMHrvhA/stacking-stx) guide.
+
+### Delegated Stacking
+
+If you delegate your STX to a pool operator, you do not need to run a signer. The pool operator conducts the actual stacking transaction and is responsible for running the signer.
+
+If you are a pool operator, see the [operate-a-pool guide](https://app.gitbook.com/s/4cpTb2lbw0LAOuMHrvhA/stacking-stx/operate-a-stacking-pool).
+
+### How and Where to Stack
+
+Options for stacking include solo stacking, participating in a pool, using an exchange, and liquid stacking. The Stacks website has a [stacking page](https://www.stacks.co/learn/stacking) describing these options.
+
+For detailed instructions on how to stack, see the [Stack STX guides](https://app.gitbook.com/s/4cpTb2lbw0LAOuMHrvhA/stacking-stx).
+
+Tools and explorers for stacking data and statistics:
+
+* https://app.signal21.io/
+* https://www.stacking-tracker.com/
+* https://www.stakingrewards.com/calculator?asset=stacks
+* https://stacking.tools/
diff --git a/docs/learn/bridging/README.md b/docs/learn/bridging/README.md
new file mode 100644
index 0000000000..463631c93a
--- /dev/null
+++ b/docs/learn/bridging/README.md
@@ -0,0 +1,13 @@
+---
+description: Exploring the plethora of ways to bridge assets to and from Stacks
+---
+
+# Bridging
+
+
+
+A blockchain bridge is a protocol or mechanism that serves as a connection between different blockchains, allowing for the transfer of tokens and data between them. Bridges enable the seamless transfer of data and assets between disparate blockchain networks. They break down the silos of individual blockchains and unlock the full potential of a permissionless, borderless Web3.
+
+#### Explore the different bridges available with Stacks
+
+USDCx Learn how USDC can flow to and from the bitcoin layer 2. usdcx
diff --git a/docs/learn/bridging/usdcx/README.md b/docs/learn/bridging/usdcx/README.md
new file mode 100644
index 0000000000..24da3d2d9e
--- /dev/null
+++ b/docs/learn/bridging/usdcx/README.md
@@ -0,0 +1,36 @@
+---
+description: >-
+ USDCx is a 1:1 USDC-backed stablecoin issued through Circle xReserve and
+ native to Stacks.
+---
+
+# USDCx
+
+
+
+{% hint style="info" %}
+Developer support for integrating USDCx bridging into applications will be available via Circle’s Bridge Kit SDK in Q1 2026.
+{% endhint %}
+
+Stacks now has a fully USDC-backed stablecoin that plugs directly into Circle’s multichain ecosystem and brings stable, interoperable dollar liquidity to Bitcoin’s leading Layer 2.
+
+### What is USDCx?
+
+USDCx is a 1:1 USDC-backed stablecoin issued through Circle xReserve and native to Stacks. It will exist as a SIP-010 token on Stacks.
+
+Circle's xReserve provides cryptographic attestations for deposits and minting, while Circle Gateway and CCTP handle cross-chain movement. The result is USDC on Stacks without third-party bridges, wrapped assets, or fragmented liquidity.
+
+{% hint style="info" %}
+For more info on xReserve, check out the dedicated Circle docs [here](https://developers.circle.com/xreserve).
+{% endhint %}
+
+### Discover more of USDCx
+
+
+
+***
+
+### Additional Resources
+
+* \[[Stacks Blog](https://www.stacks.co/blog/usdcx-launch-stacks-bitcoin-defi)] USDCx Launches on Stacks: Bitcoin Gets Its Top Tier Stablecoin
+* \[[Circle Blog](https://www.circle.com/blog/usdcx-on-stacks-now-available-via-circle-xreserve)] USDCx on Stacks now available via Circle xReserve
diff --git a/docs/learn/bridging/usdcx/bridge-app/README.md b/docs/learn/bridging/usdcx/bridge-app/README.md
new file mode 100644
index 0000000000..b7f23a69fb
--- /dev/null
+++ b/docs/learn/bridging/usdcx/bridge-app/README.md
@@ -0,0 +1,11 @@
+# USDCx Bridge App
+
+
+
+The USDCx Bridge app is maintained by Stacks Labs and is powered by Circle xReserve.
+
+Acquire USDCx through the [official bridge app](https://bridge.stacks.co/) or migrate your aeUSDC into USDCx to take advantage of better liquidity and improved trust assumptions.
+
+At launch, the USDCx bridge on Stacks supports transfers between Ethereum and Stacks. The first aeUSDC–USDCx liquidity pool will be available on Bitflow in early January.
+
+Support for additional Circle / CCTP-compatible networks is on the roadmap and will roll out in Q1 2026, enabling broader interoperability across Circle’s multichain USDC ecosystem.
diff --git a/docs/learn/bridging/usdcx/bridge-app/migrating-aeusdc.md b/docs/learn/bridging/usdcx/bridge-app/migrating-aeusdc.md
new file mode 100644
index 0000000000..52fac06042
--- /dev/null
+++ b/docs/learn/bridging/usdcx/bridge-app/migrating-aeusdc.md
@@ -0,0 +1,64 @@
+---
+description: Migrate your aeUSDC tokens to USDCx.
+---
+
+# Migrating aeUSDC
+
+### What is aeUSDC?
+
+aeUSDC on Stacks is a bridged form of USDC managed by Allbridge. Now that USDCx is live on Stacks, aeUSDC holders should upgrade to USDCx for better liquidity, better UX and improved trust assumptions.
+
+aeUSDC was first released in 2023. It will be gradually depreciated in favor of USDCx.
+
+{% hint style="warning" %}
+Minting aeUSDC is disabled. Users will not be able to mint new aeUSDC. Only transfers from Stacks to Ethereum enabled.
+{% endhint %}
+
+### Why should you migrate your aeUSDC to USDCx?
+
+* **Better liquidity** → USDCx gives you deeper liquidity and smoother swaps, powered by a more connected market.
+* **Better UX** → Enjoy a cleaner, faster experience with tools and apps built for real usability, not workarounds.
+* **Trust & reputation via attestations** → Onchain attestations backed by trusted issuers, Circle, strengthen transparency, credibility, and confidence.
+
+***
+
+### How to migrate aeUSDC to USDCx
+
+There are two primary ways to migrate aeUSDC tokens to USDCx. We’ll explain both of them here.
+
+
+
+Swap via Bitflow's Conversion Pool
+
+{% hint style="warning" %}
+Please note, the first aeUSDC:USDCx pool will be available in early January via Bitflow. This pool is not yet live.
+{% endhint %}
+
+aeUSDC holders can use the aeUSDC/USDC pool on Bitflow. This is the fastest and cheapest way to migrate to USDCx.
+
+* Navigate to Swaps in the [Bitflow app](https://app.bitflow.finance/trade).
+* Connect your wallet.
+* Select aeUSDC as the “From” token.
+* Set the amount you want to migrate. You may decide to migrate your full aeUSDC balance at once, or test a small amount first before migrating the full balance.
+* Select USDCx as the “To” token.
+* Click “Swap” button to initiate the swap. You’ll need to sign the transaction requests from your wallet in order to complete the transaction.
+
+
+
+
+
+Bridge via Allbridge Classic
+
+Users can bridge aeUSDC back to Ethereum and then bridge back to mint USDCx on Stacks.
+
+* Navigate to the [Allbridge](https://app.allbridge.io/bridge?from=STX\&to=ETH\&asset=aeUSDC) app.
+* Choose “Stacks” in the dropdown menu in the “From” field
+* Choose “Ethereum” in the dropdown menu in the “To” field
+* Choose “aeUSDC” as the asset.
+* Connect your wallet.
+* Set the amount you want to migrate. You may decide to migrate your full aeUSDC balance at once, or test a small amount first before migrating the full balance.
+* Note that it may take 60 minutes (six confirmation blocks) to complete the transaction.
+* Once you have migrated aeUSDC back to USDC on Ethereum, you can use the USDCx Stacks bridge to deposit USDC on Stacks. http://bridge.stacks.co/
+
+
+
diff --git a/docs/learn/bridging/usdcx/contracts/README.md b/docs/learn/bridging/usdcx/contracts/README.md
new file mode 100644
index 0000000000..9aeb020b36
--- /dev/null
+++ b/docs/learn/bridging/usdcx/contracts/README.md
@@ -0,0 +1,13 @@
+# Contracts
+
+The USDCx smart contract is deployed on Stacks. It's role mirrors native USDC behavior and verifies Circle’s deposit attestations for minting and emits burn events for redemption.
+
+Below are the integral contracts that make up the USDCx architecture.
+
+### Stacks
+
+
+
+### Ethereum
+
+
diff --git a/docs/learn/bridging/usdcx/contracts/usdcx-token.md b/docs/learn/bridging/usdcx/contracts/usdcx-token.md
new file mode 100644
index 0000000000..8a607c8c2d
--- /dev/null
+++ b/docs/learn/bridging/usdcx/contracts/usdcx-token.md
@@ -0,0 +1,437 @@
+# usdcx-token
+
+{% code title=".usdcx" lineNumbers="true" expandable="true" %}
+```clarity
+;; USDCx token
+;;
+;; This contract implements the SIP-010 trait for fungible contracts.
+;;
+;; This contract utilizes a role-based access control system to manage protocol permissions.
+;; There are three roles:
+;;
+;; - `governance`: Allowed to update the protocol contracts and add/remove roles
+;; - `mint`: Allowed to mint and burn tokens
+;; - `pause`: Allowed to pause and unpause the protocol
+;;
+
+(impl-trait 'SP3FBR2AGK5H9QBDH3EEN6DF8EK8JY7RX8QJ5SVTE.sip-010-trait-ft-standard.sip-010-trait)
+
+;; `tx-sender` or `contract-caller` tried to move a token it does not own.
+(define-constant ERR_NOT_OWNER (err u4))
+;; `contract-caller` tried to use a function it is not authorized to use.
+(define-constant ERR_UNAUTHORIZED (err u400))
+;; Protocol is paused.
+(define-constant ERR_PAUSED (err u401))
+
+(define-fungible-token usdcx-token)
+
+(define-data-var token-name (string-ascii 32) "USDCx")
+(define-data-var token-symbol (string-ascii 10) "USDCx")
+;; The SIP-16 URI for token metadata
+(define-data-var token-uri (optional (string-utf8 256)) (some u"https://ipfs.io/ipfs/bafkreifkhq47bgrlq2z2qgtps65eawgp6xsqkwldz57y2bjpefgo5zvza4"))
+(define-constant token-decimals u6)
+
+;; Allowed to update the protocol contracts
+(define-constant governance-role 0x00)
+;; Allowed to mint and burn tokens
+(define-constant mint-role 0x01)
+;; Allowed to pause and unpause the protocol
+(define-constant pause-role 0x02)
+
+;; Allow protocol to be paused
+(define-data-var paused bool false)
+
+;; Mapping of active protocol contracts (by role)
+(define-map active-protocol-contracts
+ {
+ caller: principal,
+ role: (buff 1),
+ }
+ bool
+)
+
+;; The contract .usdcx-v1 automatically has the `mint` role
+(map-set active-protocol-contracts {
+ caller: .usdcx-v1,
+ role: mint-role,
+}
+ true
+)
+;; Default the contract deployer as having the `governance` role
+(map-set active-protocol-contracts {
+ caller: tx-sender,
+ role: governance-role,
+}
+ true
+)
+
+;; SIP-010 functions
+
+(define-public (transfer
+ (amount uint)
+ (sender principal)
+ (recipient principal)
+ (memo (optional (buff 34)))
+ )
+ (begin
+ (asserts! (or (is-eq tx-sender sender) (is-eq contract-caller sender))
+ ERR_NOT_OWNER
+ )
+ (try! (ft-transfer? usdcx-token amount sender recipient))
+ (match memo
+ to-print (print to-print)
+ 0x
+ )
+ (ok true)
+ )
+)
+
+(define-read-only (get-name)
+ (ok (var-get token-name))
+)
+
+(define-read-only (get-symbol)
+ (ok (var-get token-symbol))
+)
+
+(define-read-only (get-decimals)
+ (ok token-decimals)
+)
+
+(define-read-only (get-balance (who principal))
+ (ok (ft-get-balance usdcx-token who))
+)
+
+(define-read-only (get-balance-available (who principal))
+ (ok (ft-get-balance usdcx-token who))
+)
+
+(define-read-only (get-balance-locked (who principal))
+ (ok (ft-get-balance usdcx-token who))
+)
+
+(define-read-only (get-total-supply)
+ (ok (ft-get-supply usdcx-token))
+)
+
+(define-read-only (get-token-uri)
+ (ok (var-get token-uri))
+)
+
+;; Protocol caller validation
+
+;; Checks whether the contract-caller is a protocol contract
+(define-read-only (is-protocol-caller
+ (contract-flag (buff 1))
+ (contract principal)
+ )
+ (validate-protocol-caller contract-flag contract)
+)
+
+;; Validate that a given principal is a protocol contract
+(define-read-only (validate-protocol-caller
+ (contract-flag (buff 1))
+ (contract principal)
+ )
+ (begin
+ ;; Check that the caller has the required role
+ (asserts!
+ (default-to false
+ (map-get? active-protocol-contracts {
+ caller: contract,
+ role: contract-flag,
+ })
+ )
+ ERR_UNAUTHORIZED
+ )
+ (ok true)
+ )
+)
+
+;; Protocol pausing
+
+(define-read-only (is-protocol-paused)
+ (var-get paused)
+)
+
+;; Validate that protocol is not paused
+(define-read-only (validate-protocol-active)
+ (ok (asserts! (not (is-protocol-paused)) ERR_PAUSED))
+)
+
+;; --- Protocol functions
+
+;; Transfer tokens from one account to another.
+;; Only the `mint` role is allowed to call this function.
+(define-public (protocol-transfer
+ (amount uint)
+ (sender principal)
+ (recipient principal)
+ )
+ (begin
+ ;; #[filter(amount, sender, recipient)]
+ (try! (validate-protocol-active))
+ (try! (validate-protocol-caller mint-role contract-caller))
+ (ft-transfer? usdcx-token amount sender recipient)
+ )
+)
+
+;; Mint tokens to an account.
+;; Only the `mint` role is allowed to call this function.
+(define-public (protocol-mint
+ (amount uint)
+ (recipient principal)
+ )
+ (begin
+ ;; #[filter(amount, recipient)]
+ (try! (validate-protocol-active))
+ (try! (validate-protocol-caller mint-role contract-caller))
+ (ft-mint? usdcx-token amount recipient)
+ )
+)
+
+;; Burn tokens from an account.
+;; Only the `mint` role is allowed to call this function.
+(define-public (protocol-burn
+ (amount uint)
+ (owner principal)
+ )
+ (begin
+ ;; #[filter(amount, owner)]
+ (try! (validate-protocol-active))
+ (try! (validate-protocol-caller mint-role contract-caller))
+ (ft-burn? usdcx-token amount owner)
+ )
+)
+
+;; Set the name of the token.
+;; Only the `governance` role is allowed to call this function.
+(define-public (protocol-set-name (new-name (string-ascii 32)))
+ (begin
+ ;; #[filter(new-name)]
+ (try! (validate-protocol-active))
+ (try! (validate-protocol-caller governance-role contract-caller))
+ (ok (var-set token-name new-name))
+ )
+)
+
+;; Set the symbol of the token.
+;; Only the `governance` role is allowed to call this function.
+(define-public (protocol-set-symbol (new-symbol (string-ascii 10)))
+ (begin
+ ;; #[filter(new-symbol)]
+ (try! (validate-protocol-active))
+ (try! (validate-protocol-caller governance-role contract-caller))
+ (ok (var-set token-symbol new-symbol))
+ )
+)
+
+;; Set the SIP-16 URI for token metadata.
+;; Only the `governance` role is allowed to call this function.
+(define-public (protocol-set-token-uri (new-uri (optional (string-utf8 256))))
+ (begin
+ ;; #[filter(new-uri)]
+ (try! (validate-protocol-active))
+ (try! (validate-protocol-caller governance-role contract-caller))
+ (ok (var-set token-uri new-uri))
+ )
+)
+
+;; Helper function to mint tokens to multiple recipients.
+;; Only the `mint` role is allowed to call this function.
+(define-private (protocol-mint-many-iter (item {
+ amount: uint,
+ recipient: principal,
+}))
+ ;; #[allow(unchecked_data)]
+ (ft-mint? usdcx-token (get amount item) (get recipient item))
+)
+
+;; Mint tokens to multiple recipients.
+;; Only the `mint` role is allowed to call this function.
+(define-public (protocol-mint-many (recipients (list 200 {
+ amount: uint,
+ recipient: principal,
+})))
+ (begin
+ ;; #[filter(recipients)]
+ (try! (validate-protocol-active))
+ (try! (validate-protocol-caller mint-role contract-caller))
+ (ok (map protocol-mint-many-iter recipients))
+ )
+)
+
+;; Set an active protocol caller.
+;; Only the `governance` role is allowed to call this function.
+(define-public (set-active-protocol-caller
+ (caller principal)
+ (role (buff 1))
+ (enabled bool)
+ )
+ (begin
+ ;; #[filter(caller, role, enabled)]
+ (try! (validate-protocol-active))
+ (try! (validate-protocol-caller governance-role contract-caller))
+ (map-set active-protocol-contracts {
+ caller: caller,
+ role: role,
+ }
+ enabled
+ )
+ (ok true)
+ )
+)
+
+;; Pause the protocol.
+;; Only the `pause` role is allowed to call this function.
+(define-public (pause)
+ (begin
+ (try! (validate-protocol-caller pause-role contract-caller))
+ (print {
+ topic: "pause",
+ paused: true,
+ caller: contract-caller,
+ })
+ (ok (var-set paused true))
+ )
+)
+
+;; Unpause the protocol.
+;; Only the `pause` role is allowed to call this function.
+(define-public (unpause)
+ (begin
+ (try! (validate-protocol-caller pause-role contract-caller))
+ (print {
+ topic: "pause",
+ paused: false,
+ caller: contract-caller,
+ })
+ (ok (var-set paused false))
+ )
+)
+
+```
+{% endcode %}
+
+## **USDCx-Token Contract Summary**
+
+This contract implements **USDCx**, a SIP-010 fungible token on Stacks with a **role-based access control system** and **pause functionality** for protocol safety. It exposes the standard SIP-010 interface for transfers, supply queries, and metadata, while providing protocol-only functions for minting, burning, governance updates, and pausing.
+
+#### **Roles**
+
+The contract defines three privileged roles:
+
+* **Governance (`governance-role`)** – manages protocol configuration, updates token metadata, and assigns roles.
+* **Mint (`mint-role`)** – authorized to mint, burn, and perform protocol-level transfers.
+* **Pause (`pause-role`)** – authorized to pause and unpause the protocol.
+
+A protocol pause halts state-changing operations for safety. The contract deployer automatically receives the **governance** role. The companion contract `.usdcx-v1` automatically receives the **mint** role.
+
+***
+
+### Function-by-Function Breakdown
+
+### **SIP-010 Standard Functions**
+
+#### **`transfer(amount, sender, recipient, memo)`**
+
+Transfers USDCx between principals, following SIP-010 rules. The function checks that the sender is either `tx-sender` or `contract-caller` (for contracts managing escrow or vaults) and then performs the transfer. An optional memo is logged on-chain.
+
+#### **`get-name()`**, **`get-symbol()`**, **`get-decimals()`**
+
+Standard SIP-010 metadata getters returning token name, symbol, and decimal precision.
+
+#### **`get-balance(who)`**, **`get-balance-available(who)`**, **`get-balance-locked(who)`**
+
+Returns the token balance for the given principal. In this implementation, all three accessor functions return the same SIP-010 balance value.
+
+#### **`get-total-supply()`**
+
+Returns the total USDCx supply minted minus burned.
+
+#### **`get-token-uri()`**
+
+Returns the token metadata URI.
+
+***
+
+### **Protocol Caller Validation**
+
+These functions enforce the contract’s role-based permissions.
+
+#### **`is-protocol-caller(role, contract)`**
+
+Checks whether the specified contract principal holds the required role.
+
+#### **`validate-protocol-caller(role, contract)`**
+
+Ensures the caller has the correct role. If not, returns `ERR_UNAUTHORIZED`.
+
+#### **`is-protocol-paused()`**
+
+Returns whether the protocol is currently paused.
+
+#### **`validate-protocol-active()`**
+
+Asserts that the protocol is not paused, otherwise returns `ERR_PAUSED`.
+
+***
+
+### **Protocol-Only Token Operations**
+
+These functions enable minting/burning/transfers strictly for authorized protocol contracts.
+
+#### **`protocol-transfer(amount, sender, recipient)`**
+
+Performs a protocol-level transfer on behalf of another contract. Only callers with the **mint role** can use it. Fails if the protocol is paused.
+
+#### **`protocol-mint(amount, recipient)`**
+
+Mints new USDCx to a principal. Restricted to the **mint role** and disabled when paused.
+
+#### **`protocol-burn(amount, owner)`**
+
+Burns tokens from a principal’s balance. Also restricted to the **mint role** and disabled when paused.
+
+#### **`protocol-mint-many(recipients)`**
+
+Batch-mints tokens to multiple recipients in a single call. Each item includes `{ amount, recipient }`. Only callable by entities with the **mint role**.
+
+***
+
+### **Governance Functions**
+
+Only the **governance role** may call these functions.
+
+#### **`protocol-set-name(new-name)`**
+
+Updates the token’s SIP-010 name.
+
+#### **`protocol-set-symbol(new-symbol)`**
+
+Updates the token’s SIP-010 ticker symbol.
+
+#### **`protocol-set-token-uri(new-uri)`**
+
+Updates the SIP-016 metadata URI.
+
+#### **`set-active-protocol-caller(caller, role, enabled)`**
+
+Adds or removes a principal from a specific protocol role.\
+Used for rotating systems, updating companion contracts, or delegating new responsibility.
+
+***
+
+### **Pause Controls**
+
+These functions allow the protocol to halt operations for safety or maintenance.
+
+#### **`pause()`**
+
+Pauses the contract, disabling minting, burning, and all protocol-only actions. Only callable by the **pause role**.
+
+#### **`unpause()`**
+
+Re-enables the protocol after a pause. Also restricted to the **pause role**.
+
+Both functions emit an on-chain event for transparency.
diff --git a/docs/learn/bridging/usdcx/contracts/usdcx-v1.md b/docs/learn/bridging/usdcx/contracts/usdcx-v1.md
new file mode 100644
index 0000000000..aeb6305f9f
--- /dev/null
+++ b/docs/learn/bridging/usdcx/contracts/usdcx-v1.md
@@ -0,0 +1,406 @@
+# usdcx-v1
+
+{% code title=".usdcx-v1" lineNumbers="true" expandable="true" %}
+```clarity
+;; USDCx v1
+;;
+;; This contract implements the USDC xReserve protocol for bridging USDC between
+;; Stacks and other chains.
+;;
+;; This contract is the main entry point for minting and burning USDCx.
+
+;; An error occurred while recovering a deposit intent signature's
+;; public key.
+(define-constant ERR_UNABLE_TO_RECOVER_PK (err u100))
+;; The length of the deposit intent is invalid.
+(define-constant ERR_INVALID_DEPOSIT_BYTE_LENGTH (err u101))
+;; The amount of the deposit intent is larger than u128::max.
+(define-constant ERR_INVALID_DEPOSIT_AMOUNT_TOO_HIGH (err u102))
+;; The max fee of the deposit intent is larger than u128::max.
+(define-constant ERR_INVALID_DEPOSIT_MAX_FEE_TOO_HIGH (err u103))
+;; The magic bytes of the deposit intent are invalid.
+(define-constant ERR_INVALID_DEPOSIT_INTENT_MAGIC (err u104))
+;; The hook data length of the deposit intent is invalid.
+(define-constant ERR_INVALID_DEPOSIT_HOOK_DATA_LENGTH (err u105))
+;; The signature of the deposit intent is invalid.
+(define-constant ERR_INVALID_DEPOSIT_SIGNATURE (err u106))
+;; The version of the deposit intent is invalid.
+(define-constant ERR_INVALID_DEPOSIT_VERSION (err u107))
+;; After accounting for fees, the amount of USDCx to mint is zero.
+(define-constant ERR_INVALID_DEPOSIT_AMOUNT_ZERO (err u108))
+;; The fee amount of the mint is larger than the max fee of the deposit intent.
+(define-constant ERR_INVALID_DEPOSIT_FEE_AMOUNT_TOO_HIGH (err u109))
+;; The remote domain of the deposit intent is invalid.
+(define-constant ERR_INVALID_DEPOSIT_REMOTE_DOMAIN (err u110))
+;; The remote token of the deposit intent is invalid.
+(define-constant ERR_INVALID_DEPOSIT_REMOTE_TOKEN (err u111))
+;; The remote recipient of the deposit intent is invalid.
+(define-constant ERR_INVALID_DEPOSIT_REMOTE_RECIPIENT (err u112))
+;; This nonce has already been used in a different deposit
+(define-constant ERR_INVALID_DEPOSIT_NONCE (err u113))
+;; The max fee is greater than or equal to the amount.
+(define-constant ERR_INVALID_DEPOSIT_MAX_FEE_GTE_AMOUNT (err u114))
+;; The remote recipient length of the deposit intent is invalid.
+(define-constant ERR_INVALID_DEPOSIT_REMOTE_RECIPIENT_LENGTH (err u115))
+;; The withdrawal amount is less than the minimum withdrawal amount.
+(define-constant ERR_INVALID_WITHDRAWAL_AMOUNT_TOO_LOW (err u116))
+;; The native domain is not the supported value (currently only 0)
+(define-constant ERR_INVALID_NATIVE_DOMAIN (err u117))
+
+;; Magic bytes for deposit encoding
+(define-constant DEPOSIT_INTENT_MAGIC 0x5a2e0acd)
+
+;; Supported version for parsing deposit intents
+(define-constant DEPOSIT_INTENT_VERSION u1)
+
+;; Supported native-domain for withdrawals
+(define-constant ETHEREUM_NATIVE_DOMAIN u0)
+
+;; Allowed `domain` for deposits
+(define-constant DOMAIN u10003)
+
+;; Map of used nonces
+(define-map used-nonces
+ (buff 32)
+ bool
+)
+
+;; Map of Circle attestor public keys
+(define-map circle-attestors
+ (buff 33)
+ bool
+)
+
+;; Minimum amount required to withdrawal USDCx
+(define-data-var min-withdrawal-amount uint u0)
+
+;; Helper function to parse a deposit intent from raw bytes.
+;; This function takes care of parsing the deposit intent according to the Circle specification.
+;; Stacks-specific logic (such as converting the remote recipient to a principal) is handled by other functions.
+;;
+;; For full validation, including parsing the remote recipient and preventing nonce reuse, use
+;; `parse-and-validate-deposit-intent`.
+(define-read-only (parse-deposit-intent (deposit-intent (buff 320)))
+ (begin
+ (asserts! (>= (len deposit-intent) u240) ERR_INVALID_DEPOSIT_BYTE_LENGTH)
+ (let (
+ (magic (unwrap-panic (as-max-len? (unwrap-panic (slice? deposit-intent u0 u4)) u4)))
+ (version (buff-to-uint-be (unwrap-panic (as-max-len? (unwrap-panic (slice? deposit-intent u4 u8)) u4))))
+ (amount-left-bytes (unwrap-panic (as-max-len? (unwrap-panic (slice? deposit-intent u8 u24)) u16)))
+ (amount (buff-to-uint-be (unwrap-panic (as-max-len? (unwrap-panic (slice? deposit-intent u24 u40)) u16))))
+ (remote-domain (buff-to-uint-be (unwrap-panic (as-max-len? (unwrap-panic (slice? deposit-intent u40 u44)) u4))))
+ (remote-token (unwrap-panic (as-max-len? (unwrap-panic (slice? deposit-intent u44 u76)) u32)))
+ (remote-recipient (unwrap-panic (as-max-len? (unwrap-panic (slice? deposit-intent u76 u108)) u32)))
+ (local-token (unwrap-panic (as-max-len? (unwrap-panic (slice? deposit-intent u108 u140)) u32)))
+ (local-depositor (unwrap-panic (as-max-len? (unwrap-panic (slice? deposit-intent u140 u172)) u32)))
+ (max-fee-left-bytes (unwrap-panic (as-max-len? (unwrap-panic (slice? deposit-intent u172 u188)) u16)))
+ (max-fee (buff-to-uint-be (unwrap-panic (as-max-len? (unwrap-panic (slice? deposit-intent u188 u204)) u16))))
+ (nonce (unwrap-panic (as-max-len? (unwrap-panic (slice? deposit-intent u204 u236)) u32)))
+ (hook-data-len (buff-to-uint-be (unwrap-panic (as-max-len? (unwrap-panic (slice? deposit-intent u236 u240)) u4))))
+ )
+ (asserts! (is-eq magic DEPOSIT_INTENT_MAGIC)
+ ERR_INVALID_DEPOSIT_INTENT_MAGIC
+ )
+ (asserts! (is-eq amount-left-bytes 0x00000000000000000000000000000000)
+ ERR_INVALID_DEPOSIT_AMOUNT_TOO_HIGH
+ )
+ (asserts! (is-eq max-fee-left-bytes 0x00000000000000000000000000000000)
+ ERR_INVALID_DEPOSIT_MAX_FEE_TOO_HIGH
+ )
+ (asserts! (is-eq (len deposit-intent) (+ u240 hook-data-len))
+ ERR_INVALID_DEPOSIT_HOOK_DATA_LENGTH
+ )
+ (ok {
+ magic: magic,
+ version: version,
+ amount: amount,
+ remote-domain: remote-domain,
+ remote-token: remote-token,
+ remote-recipient: remote-recipient,
+ local-token: local-token,
+ local-depositor: local-depositor,
+ max-fee: max-fee,
+ nonce: nonce,
+ hook-data: (if (is-eq hook-data-len u0)
+ 0x
+ (unwrap-panic (as-max-len?
+ (unwrap-panic (slice? deposit-intent u240 (+ u240 hook-data-len)))
+ u80
+ ))
+ ),
+ })
+ )
+ )
+)
+
+;; Recover the attestor public key from a deposit intent and signature.
+;; Recovery is done by hashing the deposit intent (via `keccak256`)
+;; and then using the `secp256k1-recover?` function.
+(define-read-only (recover-deposit-intent-pk
+ (deposit-intent (buff 320))
+ (signature (buff 65))
+ )
+ (let (
+ (hash (keccak256 deposit-intent))
+ (recovered-pk (unwrap! (secp256k1-recover? hash signature) ERR_UNABLE_TO_RECOVER_PK))
+ )
+ (ok recovered-pk)
+ )
+)
+
+;; Add or remove a Circle attestor.
+;;
+;; Can only be called by a caller with the governance role.
+(define-public (add-or-remove-circle-attestor
+ (public-key (buff 33))
+ (enabled bool)
+ )
+ (begin
+ ;; #[filter(public-key, enabled)]
+ (try! (contract-call? .usdcx validate-protocol-caller 0x00 contract-caller))
+ (map-set circle-attestors public-key enabled)
+ (ok true)
+ )
+)
+
+;; Recover and verify a deposit intent signature.
+;;
+;; The public key is first recovered (via `recover-deposit-intent-pk`).
+;; Then, the public key is checked against the `circle-attestors` map.
+(define-read-only (verify-deposit-intent-signature
+ (deposit-intent (buff 320))
+ (signature (buff 65))
+ )
+ (begin
+ ;; #[filter(deposit-intent, signature)]
+ (let ((recovered-pk (try! (recover-deposit-intent-pk deposit-intent signature))))
+ (asserts! (default-to false (map-get? circle-attestors recovered-pk))
+ ERR_INVALID_DEPOSIT_SIGNATURE
+ )
+ (ok recovered-pk)
+ )
+ )
+)
+
+;; Convert 32 bytes to a standard principal. This is serialized as
+;; 1 version byte, plus 20 hash bytes. This is then left-padded
+;; with 11 bytes of 0x00.
+;;
+;; To support contracts as recipients, `hook-data` can contain a contract name.
+;; To use this functionality, `hook-data` MUST be a consensus-serialized buffer
+;; of the type { contract-name: (string-ascii 40) }.
+;;
+;; If `hook-data` is not able to be deserialized, this function falls back
+;; to using a standard principal.
+(define-read-only (get-remote-recipient
+ (remote-recipient-bytes (buff 32))
+ (hook-data (buff 80))
+ )
+ (let (
+ (valid-len (asserts! (is-eq (len remote-recipient-bytes) u32)
+ ERR_INVALID_DEPOSIT_REMOTE_RECIPIENT_LENGTH
+ ))
+ (version-byte (unwrap-panic (element-at? remote-recipient-bytes u11)))
+ (hash-bytes (unwrap-panic (as-max-len? (unwrap-panic (slice? remote-recipient-bytes u12 u32)) u20)))
+ ;; Avoid a VM runtime error when `hook-data` is empty:
+ (hook-contract-name (if (is-eq (len hook-data) u0)
+ none
+ (from-consensus-buff? { contract-name: (string-ascii 40) } hook-data)
+ ))
+ )
+ ;; Must have 0x00 as padding
+ (asserts!
+ (is-eq
+ (unwrap-panic (as-max-len? (unwrap-panic (slice? remote-recipient-bytes u0 u11)) u11))
+ 0x0000000000000000000000
+ )
+ ERR_INVALID_DEPOSIT_REMOTE_RECIPIENT
+ )
+ (ok (unwrap!
+ (match hook-contract-name
+ contract-name-tup (principal-construct? version-byte hash-bytes
+ (get contract-name contract-name-tup)
+ )
+ (principal-construct? version-byte hash-bytes)
+ )
+ ERR_INVALID_DEPOSIT_REMOTE_RECIPIENT
+ ))
+ )
+)
+
+;; 32-byte encoded version of the `.usdcx` contract address.
+;; This must be used in deposit intents as the `remote-token` field.
+(define-read-only (get-valid-remote-token)
+ (concat 0x00000000
+ (unwrap-panic (as-max-len? (unwrap-panic (to-consensus-buff? .usdcx)) u28))
+ )
+)
+
+;; Helper function to parse and validate a deposit intent.
+;;
+;; In addition to basic parsing (done via `parse-deposit-intent`), this function
+;; also validates certain Stacks-specific fields, such as the
+;; remote token, remote domain, remote recipient, and version.
+;;
+;; Additionally, this function validates the `amount` and `max-fee` fields.
+(define-read-only (parse-and-validate-deposit-intent (deposit-intent (buff 320)))
+ (let (
+ (parsed-intent (try! (parse-deposit-intent deposit-intent)))
+ (remote-recipient (try! (get-remote-recipient (get remote-recipient parsed-intent)
+ (get hook-data parsed-intent)
+ )))
+ (amount (get amount parsed-intent))
+ )
+ (asserts! (is-eq (get remote-token parsed-intent) (get-valid-remote-token))
+ ERR_INVALID_DEPOSIT_REMOTE_TOKEN
+ )
+ (asserts! (> amount u0) ERR_INVALID_DEPOSIT_AMOUNT_ZERO)
+ (asserts! (is-eq (get remote-domain parsed-intent) DOMAIN)
+ ERR_INVALID_DEPOSIT_REMOTE_DOMAIN
+ )
+ (asserts! (is-eq (get version parsed-intent) DEPOSIT_INTENT_VERSION)
+ ERR_INVALID_DEPOSIT_VERSION
+ )
+ (asserts! (>= amount (get max-fee parsed-intent))
+ ERR_INVALID_DEPOSIT_MAX_FEE_GTE_AMOUNT
+ )
+ (asserts! (is-none (map-get? used-nonces (get nonce parsed-intent)))
+ ;; This nonce has already been used in a different deposit
+ ERR_INVALID_DEPOSIT_NONCE
+ )
+ (ok (merge parsed-intent { remote-recipient: remote-recipient }))
+ )
+)
+
+;; Mint USDCx using a deposit intent.
+;; This is the main entry point for minting USDCx.
+;;
+;; In addition to validation performed by `parse-and-validate-deposit-intent`, and
+;; `verify-deposit-intent-signature`, this function also validates the `fee-amount`
+;; provided by the caller to ensure that zero-amount mints are not possible.
+;;
+;; If `fee-amount` is non-zero (and less than the deposit's `max-fee`),
+;; this function will mint `fee-amount` of USDCx to the caller. This allows
+;; for accounts other than the deposit's recipient to cover the STX fee needed to mint.
+(define-public (mint
+ (deposit-intent (buff 320))
+ (signature (buff 65))
+ (fee-amount uint)
+ )
+ (let (
+ (parsed-intent (try! (parse-and-validate-deposit-intent deposit-intent)))
+ (recovered-pk (try! (verify-deposit-intent-signature deposit-intent signature)))
+ (mint-amount (- (get amount parsed-intent) fee-amount))
+ )
+ (asserts! (>= (get max-fee parsed-intent) fee-amount)
+ ERR_INVALID_DEPOSIT_FEE_AMOUNT_TOO_HIGH
+ )
+ ;; mint to the recipient
+ (if (is-eq mint-amount u0)
+ true
+ (try! (contract-call? .usdcx protocol-mint mint-amount
+ (get remote-recipient parsed-intent)
+ ))
+ )
+ (if (is-eq fee-amount u0)
+ true
+ (try! (contract-call? .usdcx protocol-mint fee-amount tx-sender))
+ )
+ (map-set used-nonces (get nonce parsed-intent) true)
+ (print {
+ topic: "mint",
+ parsed-intent: parsed-intent,
+ attestor-pk: recovered-pk,
+ mint-amount: mint-amount,
+ fee-amount: fee-amount,
+ })
+ (ok true)
+ )
+)
+
+;; Set the minimum withdrawal amount.
+;;
+;; Can only be called by a caller with the custom role `0x04` role.
+(define-public (set-min-withdrawal-amount (new-min-withdrawal-amount uint))
+ (begin
+ (try! (contract-call? .usdcx validate-protocol-caller 0x04 contract-caller))
+ (var-set min-withdrawal-amount new-min-withdrawal-amount)
+ (ok true)
+ )
+)
+
+(define-read-only (get-min-withdrawal-amount)
+ (var-get min-withdrawal-amount)
+)
+
+;; Burn USDCx for the purpose of withdrawing USDCx from the protocol.
+;;
+;; This function burns USDCx from the caller's account and emits a `burn` event.
+;;
+;; The amount must be greater than or equal to the minimum withdrawal amount.
+;;
+;; `native-domain` must be a supported value (currently only `ETHEREUM_NATIVE_DOMAIN` (u0)).
+(define-public (burn
+ (amount uint)
+ (native-domain uint)
+ (native-recipient (buff 32))
+ )
+ (begin
+ (asserts! (>= amount (var-get min-withdrawal-amount))
+ ERR_INVALID_WITHDRAWAL_AMOUNT_TOO_LOW
+ )
+ (asserts! (is-eq native-domain ETHEREUM_NATIVE_DOMAIN)
+ ERR_INVALID_NATIVE_DOMAIN
+ )
+ (try! (contract-call? .usdcx protocol-burn amount tx-sender))
+ (print {
+ topic: "burn",
+ native-domain: native-domain,
+ native-recipient: native-recipient,
+ sender: tx-sender,
+ amount: amount,
+ })
+ (ok true)
+ )
+)
+
+```
+{% endcode %}
+
+## **USDCx-v1 Contract Summary**
+
+The `usdcx-v1` contract implements the **USDC xReserve protocol** for moving USDC between Stacks and external chains. It serves as the **primary entry point for minting and burning USDCx** based on Circle-issued deposit intents.
+
+This contract handles:
+
+* Parsing and validating deposit intent payloads
+* Recovering and verifying Circle attestor signatures
+* Enforcing nonce-based replay protection
+* Minting USDCx through the `usdcx` token contract
+* Burning USDCx to initiate withdrawals
+* Managing Circle attestor keys
+* Handling Stacks-specific recipient conversions
+* Applying fee logic for sponsored mints
+* Managing minimum withdrawal thresholds
+
+It works in tandem with the main `usdcx` token contract, which enforces protocol roles (`mint`, `governance`, etc.). All minting/burning occurs through `protocol-mint` and `protocol-burn`.
+
+### Minting USDCx
+
+The entry point for minting USDCx is via the `mint` function. The caller provides a serialized deposit intent, along with a signature, both of which are received off-chain as part of the bridging process. The deposit intent is parsed according to the xReserve specificiation.
+
+There are a few Stacks-specific elements:
+
+* The `remote-token` of the deposit intent MUST be the consensus-serialized bytes of the principal `.usdcx` (where the deployer address is network-dependent), with 0x left-padded.
+* The `remote-domain` for Stacks is always `10003`.
+* Because Stacks only supports `u128` integers, the deserialization functions throw an error if any 64-byte integers in the deposit intent are larger than `u128::max`. This is allowed according to the xReserve spec.
+
+### **Verifying attestations**
+
+The `.usdcx-v1` contract keeps a `circle-attestors` map to keep track of public keys of valid attestors. When a deposit intent is provided, it must be signed by a public key in this map.
+
+### Burning USDCx
+
+To withdrawal USDCx to another chain, users call `burn`. The specified amount of USDCx is burned from their Stacks account. A `print` event is emitted, which is used for triggering a burn attestation off-chain.
+
+The `.usdcx-v1` contract stores a minimum amount variable. Users must withdrawal at least this amount, or the burn fails. Accounts with the role `0x04` can update this variable.
diff --git a/docs/learn/bridging/usdcx/faq.md b/docs/learn/bridging/usdcx/faq.md
new file mode 100644
index 0000000000..6d86e385c4
--- /dev/null
+++ b/docs/learn/bridging/usdcx/faq.md
@@ -0,0 +1,58 @@
+# FAQ
+
+
+
+What's the purpose of having stablecoins on Stacks?
+
+Stablecoins make capital move. They enable institutions to lend and borrow, and they give users access to liquidity without leaving the Bitcoin economy.
+
+
+
+
+
+Why is it USDCx and not native USDC on Stacks?
+
+USDCx is a 1:1 USDC-backed stablecoin issued through Circle xReserve and native to Stacks. xReserve provides cryptographic attestations for deposits and minting, while Circle Gateway and CCTP handle cross-chain movement. The result is USDC on Stacks without third-party bridges, wrapped assets, or fragmented liquidity.
+
+With this setup, Stacks now has a fully USDC-backed stablecoin that plugs directly into Circle’s multichain ecosystem and brings stable, interoperable dollar liquidity to Bitcoin’s leading Layer 2. USDCx will always be fully backed by USDC on the source chain.
+
+
+
+
+
+Which networks are supported for USDCx interoperabiity?
+
+Currently, interoperability is between Ethereum and Stacks. Other Circle/CCTP-compatible networks will be added in the future.
+
+
+
+
+
+How is USDCx different from aeUSDC?
+
+aeUSDC on Stacks is a bridged form of USDC managed by Allbridge. Now that USDCx is live on Stacks, aeUSDC holders should upgrade to USDCx for better liquidity, better UX and improved trust assumptions. aeUSDC was first released in 2023. It will be gradually depreciated in favor of USDCx.
+
+
+
+
+
+How does USDCx differ from the other stablecoins already on Stacks?
+
+USDCx is a fully USDC-backed, cryptographically attested dollar asset that moves across chains through Circle’s native infrastructure. It works everywhere USDC works, from Ethereum to Solana and beyond, all while settling on Bitcoin through Stacks.
+
+With USDCx, developers get a reliable dollar rail to build with, users get predictable liquidity, and protocols get a trusted base asset for markets and collateral. It provides the missing piece for deeper liquidity, healthier markets, and real Bitcoin-denominated yield.
+
+* Deeper liquidity pools on Stacks DeFi protocols
+* Simplified user experience with Circle-managed reserves
+* Institutional confidence and proven infrastructure
+* Bitcoin capital flowing freely to where it's most productive
+
+
+
+
+
+What will happen to aeUSDC?
+
+aeUSDC will be gradually depreciated in favor of USDCx. Now that USDCx is live on Stacks, aeUSDC holders should upgrade to USDCx for better liquidity, better UX and improved trust assumptions.
+
+
diff --git a/docs/learn/bridging/usdcx/operations.md b/docs/learn/bridging/usdcx/operations.md
new file mode 100644
index 0000000000..b317d2cf93
--- /dev/null
+++ b/docs/learn/bridging/usdcx/operations.md
@@ -0,0 +1,41 @@
+# Operations
+
+Let's walkthrough each of the operations that enable the bridging of USDC in and out of Stacks.
+
+### Definitions
+
+* **USDC**: Refers to native-chain USDC locked on the source chain that secures USDC-backed token at a 1-to-1 ratio.
+* **xReserve smart contract**: Circle deploys and audits the xReserve contract on source blockchains such as Ethereum. It holds USDC deposited by users in reserve when a USDC-backed token is minted on Stacks
+* **xReserve attestation service**: Operated by Circle. They monitor USDC deposits into the xReserve smart contract and sign deposit attestations. They also verify withdrawal attestations to release USDC.
+* **Stacks attestation service**: Operated by Stacks. They monitor signed deposit attestations to trigger minting of USDCx on Stacks. In addition, they monitor burns of USDCx tokens to sign burn intents which are then forwarded to Circle's xReserve attestation service.
+* **USDCx**: A SIP-010 token on Stacks fully backed by USDC.
+
+### Deposits
+
+
+
+For bridging source-chain USDC into the Stacks network.
+
+1. A user deposits USDC from their wallet app into an xReserve smart contract, managed by Circle, on the source chain.
+2. The xReserve contract emits a deposit event and locks the funds, holding them in reserve.
+3. The xReserve attestation service, managed by Circle, generates and signs a deposit attestation.
+4. The Stacks network's attestation service fetches the signed deposit attestation.
+5. The Stacks network mints USDC-backed tokens, USDCx, and emits a mint event.
+6. The Stacks' USDCx token contract deposits the newly minted USDC-backed tokens into the user’s Stacks wallet.
+
+After completing the deposit process, the user receives an equivalent amount of USDC-backed tokens on Stacks.
+
+### Withdrawals
+
+
+
+For withdrawing USDC from the Stacks network.
+
+1. A user requests to burn USDCx tokens on Stacks and to withdraw USDC on the destination network.
+2. The Stacks USDCx token contract burns their USDCx tokens and emits a burn event.
+3. The Stacks network's attestation service monitors the burn emitted burn event and then signs a generated burn intent message offchain.
+4. The Stacks network's attestation service passes the burn intent message and signature to xReserve, managed by Circle.
+5. xReserve verifies the burn and issues a withdrawal attestation.
+6. xReserve releases USDC to the user’s wallet on the destination network.
+
+After completing the withdrawal process, the user receives USDC on the destination network.
diff --git a/docs/learn/clarity/README.md b/docs/learn/clarity/README.md
new file mode 100644
index 0000000000..c1baf59a2c
--- /dev/null
+++ b/docs/learn/clarity/README.md
@@ -0,0 +1,59 @@
+---
+description: A smart contract language built to be readable and predictable.
+---
+
+# Clarity
+
+
+
+{% hint style="info" %}
+Head to the [Clarity Crash Course](https://app.gitbook.com/s/Zz9BLmTU9oydDpL3qiUh/get-started/clarity-crash-course) to build your first Clarity smart contract.
+{% endhint %}
+
+Clarity is a **decidable** smart contract language that optimizes for predictability and security, designed for the Stacks blockchain. It has been built from the ground up to make it easier for developers to write safe, secure smart contracts. Clarity has several unique features that make it an ideal choice for writing smart contracts.
+
+The design decisions behind Clarity were based heavily on taking lessons learned in common Solidity exploits and creating a language that has been purpose-built for safety and security in mind.
+
+### What makes Clarity different
+
+The following section is an excerpt from the Clarity book, [Clarity of Mind](https://book.clarity-lang.org/ch00-00-introduction.html):
+
+The number of smart contract languages grows by the year. Choosing a first language can be challenging, especially for a beginner. The choice is largely dictated by the ecosystem you are interested in, although some languages are applicable to more than just one platform. Each language has its own upsides and downsides and it is out of the scope of this book to look at all of them. Instead, we will focus on what sets Clarity apart and why it is a prime choice if you require the utmost security and transparency.
+
+One of the core precepts of Clarity is that it is secure by design. The design process was guided by examining common pitfalls, mistakes, and vulnerabilities in the field of smart contract engineering as a whole. There are countless real world examples of where developer failure led to the loss or theft of vast amounts of tokens. To name two big ones: an issue that has become known as the Parity bug led to the irreparable loss of millions of dollars worth of Ethereum. Second, the hacking of The DAO (a "Decentralized Autonomous Organization") caused financial damage so great that the Ethereum Foundation decided to issue a contentious hard fork that undid the theft. These and many other mistakes could have been prevented in the design of the language itself.
+
+#### Clarity is interpreted, not compiled
+
+Clarity code is interpreted and committed to the chain exactly as written. Solidity and other languages are compiled to byte-code before it is submitted to the chain. The danger of compiled smart contract languages is two-fold: first, a compiler adds a layer of complexity. A bug in the compiler may lead to different byte-code than was intended and thus carries the risk of introducing a vulnerability. Second, byte-code is not human-readable, which makes it very hard to verify what the smart contract is actually doing. Ask yourself, would you sign a contract you cannot read? If your answer is no, then why should it be any different for smart contracts? With Clarity, what you see is what you get.
+
+#### Clarity is decidable
+
+A decidable language has the property that from the code itself, you can know with certainty what the program will do. This avoids issues like the halting problem. With Clarity you know for sure that given any input, the program will halt in a finite number of steps. In simple terms: it is guaranteed that program execution will end. Decidability also allows for complete static analysis of the call graph so you get an accurate picture of the exact cost before execution. There is no way for a Clarity call to "run out of gas" in the middle of the call. We explore this idea more, along with a discussion on Turing completeness, in the security deep dive on decidability.
+
+#### Clarity does not permit reentrancy
+
+Reentrancy is a situation where one smart contract calls into another, which then calls back into the first contract—the call "re-enters" the same logic. It may allow an attacker to trigger multiple token withdrawals before the contract has had a chance to update its internal balance sheet. Clarity's design considers reentrancy an anti-feature and disallows it on the language level.
+
+#### Clarity guards against overflow and underflows
+
+Overflows and underflows happen when a calculation results in a number that is either too large or too small to be stored, respectively. These events throw smart contracts into disarray and may intentionally be triggered in poorly written contracts by attackers. Usually this leads to a situation where the contract is either frozen or drained of tokens. Overflows and underflows of any kind automatically cause a transaction to be aborted in Clarity.
+
+#### Support for custom tokens is built-in
+
+Issuance of custom fungible and non-fungible tokens is a popular use-case for smart contracts. Custom token features are built into the Clarity language. Developers do not need to worry about creating an internal balance sheet, managing supply, and emitting token events. Creating custom tokens is covered in depth in later chapters.
+
+#### On Stacks, transactions are secured by post conditions
+
+In order to further safeguard user tokens, post conditions can be attached to transactions to assert the chain state has changed in a certain way once the transaction has completed. For example, a user calling into a smart contract may attach a post condition that states that after the call completes, exactly 500 STX should have been transferred from one address to another. If the post condition check fails, then the entire transaction is reverted. Since custom token support is built right into Clarity, post conditions can also be used to guard any other token in the same way.
+
+#### Returned responses cannot be left unchecked
+
+Public contract calls must return a so-called response that indicates success or failure. Any contract that calls another contract is required to properly handle the response. Clarity contracts that fail to do so are invalid and cannot be deployed on the network. Other languages like Solidity permit the use of low level calls without requiring the return value to be checked. For example, a token transfer can fail silently if the developer forgets to check the result. In Clarity it is not possible to ignore errors, although that obviously does prevent buggy error handling on behalf of the developer. Responses and error handling are covered extensively in the chapters on functions and control flow.
+
+#### Composition over inheritance
+
+Clarity adopts a composition over inheritance. It means that Clarity smart contracts do not inherit from one another like you see in languages like Solidity. Developers instead define traits which are then implemented by different smart contracts. It allows contracts to conform to different interfaces with greater flexibility. There is no need to worry about complex class trees and contracts with implicit inherited behavior.
+
+#### Access to the base chain: Bitcoin
+
+Clarity smart contracts can read the state of the Bitcoin base chain. It means you can use Bitcoin transactions as a trigger in your smart contracts! Clarity also features a number of built-in functions to verify secp256k1 signatures and recover keys.
diff --git a/docs/learn/clarity/decidability.md b/docs/learn/clarity/decidability.md
new file mode 100644
index 0000000000..427424c44e
--- /dev/null
+++ b/docs/learn/clarity/decidability.md
@@ -0,0 +1,173 @@
+# Decidability
+
+### What does it mean for a language to be Non-Turing Complete or Decidable?
+
+Non-Turing complete and decidable are two terms you will often hear about the security advantages of Clarity, but what do they mean?
+
+While related, they are not quite interchangeable, since there are a few differences.
+
+#### Non-Turing Complete
+
+A system or language is non-Turing complete if it cannot simulate a Turing machine, which is an abstract model of computation. Non-Turing complete systems have limited computational power compared to Turing complete systems. A Turing-complete system or language can simulate any Turing machine. Examples of non-Turing complete systems include finite state machines and some domain-specific languages (like Clarity).
+
+Non-Turing complete languages typically cannot express all possible algorithms. Specifically, some problems whose solutions require unbounded loops or recursion cannot be expressed using non-Turing complete languages. This last property is especially important in the context of Clarity, as it makes it so that features like unbounded loops and reentrancy are disallowed at a language level.
+
+#### Decidable
+
+A problem is decidable if there exists an algorithm that can always determine whether a given input has a particular property or not in a finite amount of time. In other words, a decidable problem can be solved by a Turing machine that is guaranteed to halt for all input instances. Decidability is a property of problems, whereas Turing completeness is a property of languages or computational systems.
+
+The fact that Clarity is decidable means that developers (and tooling) can more easily reason about and predict with certainty the behavior of Clarity contracts, regardless of the input.
+
+### Mindset of a Smart Contract Developer
+
+Before we dive into specifics, let's first set the context and viewpoint we should hold as smart contract developers who want to write secure code.
+
+As you explore further into the security properties of Solidity and Clarity, you'll see that there are always mitigation steps that _can_ be taken by developers to help address some of these security issues.
+
+The main issue, with this line of thinking, is it increases the odds of human error in smart contract security. If we can preserve functionality while mitigating the chance of human error as much as possible, we should do so.
+
+### Should smart contracts be Turing complete?
+
+We will discover new applications for smart contracts. These applications will go beyond current smart contracts, traditional contracts, and may even open new economic opportunities. Given these possibilities, how should we build our smart contracts? What characteristics should our smart contract languages have?
+
+It is good practice to separate data from programs. Should smart contracts be data, or programs, or something in between? If smart contracts are data, then should the programs that execute them be Turing complete or perhaps less powerful? If smart contracts are programs, then what language should smart contracts be written in? What characteristics should this programming language have?
+
+The Church–Turing thesis is the hypothesis that all formal notions of computation are captured by Turing machines or modern computers. A programming language is Turing complete if it captures all formal notions of computation. Many programming languages are Turing complete. For example, Python, C++, Rust, Java, Lisp, and Solidity are all Turing complete.
+
+Consider a program and its input. In the worst case, determining this program’s output is impossible. Validating a program, on a particular input, is done by generating a proof-of-correctness.
+
+Proofs-of-correctness are logical proofs that can be mechanically validated. Finding proofs-of-correctness for programs and their input is undecidable. Kurt Gödel showed there are undecidable logical statements.
+
+This indicates all programs in Turing complete languages cannot be validated in the worst case. Thus, Turing complete smart contract languages must allow contracts that cannot be validated.
+
+Alonzo Church and Alan Turing showed there are problems that are uncomputable. Uncomputable problems cannot be solved by any Turing machine. Hence, assuming the Church–Turing thesis, these uncomputable problems cannot be solved by any computer.
+
+We'll explore this idea further later in this section.
+
+Turing complete languages are very expressive. In fact, assuming the Church–Turing thesis, Turing complete languages are as expressive as possible in some sense.
+
+Is there a trade-off? What types of problems can occur with uncomputable problems and programs whose validity may be undecidable?
+
+As smart contracts subsume parts of contract law, consider the large body of laws and regulations for tax law.
+
+For instance, US tax law and regulations take up several million words. International tax law and regulations pushes these numbers much higher.
+
+Are these laws and regulations programs or are they data? If tax law were to be written in a Turing complete language, then the law may codify uncomputable problems. It is an accountant’s nightmare for their advice to be undecidable.
+
+Clarity is non-Turing complete, yet very expressive. This makes it so that Clarity is decidable and cannot encode uncomputable problems. There are discussions and papers on smart contract languages such as Solidity that propose subsets of Solidity that are non-Turing complete. These subsets are decidable and cannot encode uncomputable problems. However, there is no consensus on which subsets to work with and they are not widely used.
+
+### Advantages of Decidability in Smart Contracts
+
+Why is decidability important in the context of smart contracts?
+
+First, it is not possible for a Clarity call to run out of gas in the middle of a call. Because of its decidability, it is possible to get a complete static analysis of the call graph to get an accurate picture of the cost before execution.
+
+Solidity allows for unbounded loops, recursion, and dynamic function calls, which makes it difficult to accurately predict the execution cost or gas usage beforehand. As a result, Solidity contracts may run out of gas during execution if the gas limit is not set appropriately or if the contract encounters a scenario with unexpectedly high computational requirements.
+
+One practical example is the issue of a specific kind of DoS attack in Solidity, where the contract is rendered inoperable because of unbounded execution constraints. An example of this is the GovernMental attack, where a mapping that needed to be deleted for a payout became so large that working with it exceeded the block gas limit.
+
+There are a few different properties of Clarity's language design that prevents such DoS attacks.
+
+The reason that the analysis system can accurately estimate the execution cost is because certain functionality is intentionally limited in Clarity.
+
+For example, there is no recursion in Clarity, so we can't infinitely call into a function over and over.
+
+Data types in Clarity are also restricted. Any data types that don't require a hard length limit are not iterable.
+
+Maps and tuples, for example, do not require you to enter a maximum length when defining them, but you also can't iterate over them.
+
+Lists, on the other hand, which are iterable, do require the developer to define an upper limit when defining them. This is a large part of what allows an accurate static analysis of Clarity contracts.
+
+So how would we implement a mapping of an undefined size in Clarity? We wouldn't, because it's an anti-pattern in smart contract design.
+
+Instead, Clarity forces us to think of a better solution to our problem. For example, implementing a way for users to handle mapping/list element operations themselves, instead of mass operations handled at the contract level.
+
+If you [analyze the GovernMental attack](https://hackernoon.com/smart-contract-attacks-part-2-ponzi-games-gone-wrong-d5a8b1a98dd8#h-attack-2-call-stack-attack), you'll see that it took advantage of multiple security issues, all of which are mitigated in Clarity. You'll also see that a fix was added to make it economically infeasible to carry out this type of attack again.
+
+This brings up another crucial point when setting appropriate mental models for smart contracts and blockchain systems: complexity means more potential bugs, which means adding more complexity to address those bugs.
+
+When this happens over and over again, we are trapping ourselves into creating an evermore complex system. Addressing these issues at the language level prevents this ever-growing complexity.
+
+For a deep dive into how Clarity was designed, check out [SIP-002](https://github.com/stacksgov/sips/blob/main/sips/sip-002/sip-002-smart-contract-language.md).
+
+{% hint style="info" %}
+You can view some more common smart contract vulnerabilities and how they are mitigated in [this article](https://stacks.org/bringing-clarity-to-8-dangerous-smart-contract-vulnerabilities/).
+{% endhint %}
+
+This has second-order effects as well when we look at security testing and auditing. One of the common tools for testing smart contracts is formal verification, where we mathematically prove that certain properties of smart contracts will or will not remain true in all cases.
+
+This can lead to the path explosion problem, where there are so many paths available that formal verification becomes incredibly difficult. This problem is mitigated in Clarity, since there is not chance of a program encountering an unbounded loop.
+
+This leads us to a more general mental model for thinking about decidability as smart contracts continue to become a larger part of our economy. Remember that the goal with blockchain systems is to create an open, transparent, fair financial system.
+
+This means that smart contracts will be responsible for managing large amounts of wealth for ever-growing amounts of people. As smart contracts encompass more financial structures, their complexity and usage will grow.
+
+Complexity is the enemy of security. The more complex a system is, the more danger there is in creating uncomputable problems when there are no hard restrictions on the execution steps that can be taken.
+
+This is deadly in financial infrastructure that is not only open and transparent, but immutable. Let's explore this idea of uncomputability a bit more.
+
+### Intuition on Uncomputability
+
+Intuitively, uncomputability is an algorithmic view of undecidability. Uncomputability has the same foundations as undecidability. Undecidable questions are framed as logic statements or statements about integers. Of course, programs are logic statements and may even be viewed as integers, though we view programs differently. We often view programs with additional details of memory models, implementation details, and execution semantics.
+
+The [Halting problem](https://en.wikipedia.org/wiki/Halting_problem): As an example, given any program `P` and any finite input `I` for `P`, then the Halting Problem is the challenge of determining if `P` halts on input `I`.
+
+Alonzo Church and Alan Turing showed the Halting Problem is unsolvable.
+
+Christopher Strachey gave an intuitive proof-by-contradiction showing the Halting problem is uncomputable. This is set up by supposing there is a program `H` that can solve the Halting problem for any program `P`. `H(P)` returns true if `P` halts and false otherwise. Then build a program `P` that does not halt when `H(P)` is true, giving a contradiction. Similarly, this program `P` halts when `H(P)` is false, also a contradiction.
+
+Uncomputable problems are problems that cannot be solved by an algorithm or a computer, no matter how much time or resources are provided. These problems exist in various forms, and one such example is the Post correspondence problem, which was proposed by Emil Post.
+
+The Post correspondence problem can be described using pairs of strings and an integer. Imagine you have n pairs of strings, called P. These strings are made up of characters from a character set, such as UTF-8 or any other alphabet with at least two symbols. The pairs of strings look like this:
+
+```
+P = { (x1, y1), (x2, y2), … , (xn, yn) }
+```
+
+Now, you also have an integer m that is greater than 0. The Post correspondence problem asks whether there is a way to create a list of indices (i1, i2, …, im) using the given pairs of strings. You can repeat these indices if needed, with one condition: when you combine the x strings from the pairs using the indices, the resulting string must be equal to the combined y strings from the same pairs using the same indices. In other words:
+
+```
+x(i1) x(i2) … x(im) = y(i1) y(i2) … y(im)
+```
+
+When developers try to solve the Post correspondence problem, they often attempt to use indeterminate loops (loops without a fixed number of iterations) rather than recursion. This is because the problem seems to require searching through different combinations of indices until a solution is found or it's proven that no solution exists.
+
+In simple terms, the Post correspondence problem involves trying to find a sequence of indices that, when applied to the given pairs of strings, produces equal concatenated strings from both the x and y components. This problem is considered uncomputable because there is no general algorithm that can solve it for all possible input pairs of strings and integers.
+
+It turns out, many questions about how programs behave are uncomputable. This has a number of consequences for smart contracts that are built in Turing complete languages, many of which we are not aware of yet but will surely become aware of as we encounter them in the future.
+
+### Raymond Smullyan’s Intuition on Undecidability
+
+This is a part of Raymond Smullyan’s approach to understanding undecidability in propositional logic. It uses meta-information to show something must be true, though it cannot be proved in propositional logic. This is based on a paradox.
+
+In propositional logic, a logical statement is undecidable if we cannot prove it true or false. Given a propositional logic statement S, a proof is a sequence of formal logical deductions, starting from basic facts and ending by indicating if S is true or false.
+
+Smullyan starts with an island of Knights and Knaves. Knights always tell the truth. Knaves always lie. We cannot distinguish islanders otherwise.
+
+There is a great logician named Ray. Whatever Ray proves is true. This is just like a good theorem prover.
+
+An islander Jack proclaims: “You cannot prove I am a Knight” to the logician Ray.
+
+The next reasoning is based on meta-knowledge of this situation. This meta-knowledge shows that some problems are undecidable in propositional logic.
+
+If Ray can prove Jack is a Knight, then Jack must be a Knave, since Jack must have lied. That is because Ray proved Jack is a Knight. Since Jack is a Knave, Ray’s proof contradicts the assumption that Ray only proves true things. So, this case cannot hold.
+
+If Ray cannot prove Jack is a Knight, then Jack must be a Knight, since Jack stated the truth. But Ray cannot prove the fact that Jack is a Knight.
+
+In the context of smart contracts and programming languages, Turing complete languages like Solidity come with the possibility of undecidable problems.
+
+These undecidable problems are similar to the paradox presented in the Knights and Knaves story, where it's impossible to determine whether Jack is a Knight or a Knave based on the given information.
+
+In the Knights and Knaves story, Ray is analogous to a theorem prover or a smart contract in a Turing complete language. Ray is faced with a statement that is undecidable within the constraints of the system (Knights and Knaves), which leads to a paradox.
+
+Similarly, a Turing complete smart contract language might face undecidable problems that can't be resolved, leading to unexpected behavior, vulnerabilities, or resource consumption issues (like running out of gas in Ethereum).
+
+On the other hand, non-Turing complete languages like Clarity are designed to avoid undecidable problems by limiting their expressiveness.
+
+In the context of the Knights and Knaves story, a non-Turing complete language would simply not allow Jack to make a statement that could lead to a paradox. By disallowing certain features like unbounded loops and recursion, non-Turing complete languages can provide stronger guarantees about the behavior and resource usage of smart contracts.
+
+This predictability is desirable in many cases, especially when dealing with high-value transactions or critical systems.
+
+### Reference
+
+The Mathematics of Various Entertaining Subjects: Research in Recreational Math Illustrated Edition, Jennifer Beineke (Editor), Jason Rosenhouse (Editor), Raymond M. Smullyan (Foreword), Princeton University Press, 2016.
diff --git a/docs/learn/dual-stacking/README.md b/docs/learn/dual-stacking/README.md
new file mode 100644
index 0000000000..e9679f8ea1
--- /dev/null
+++ b/docs/learn/dual-stacking/README.md
@@ -0,0 +1,32 @@
+---
+description: An overview of the BTC-denominated rewards mechanism on Stacks
+---
+
+# Dual Stacking
+
+
+
+{% hint style="info" %}
+Check out the official blog announcement of Dual Stacking [here](https://www.stacks.co/blog/dual-stacking-launches-on-stacks).
+{% endhint %}
+
+{% hint style="danger" %}
+Dual Stacking contracts will be upgraded on Dec 15. This upgrade enables more flexible reward parameters and allows users to view their sBTC holdings and corresponding rewards within the Dual Stacking app.
+
+1. If you enrolled in Dual Stacking you'll be moved over automatically with no action needed.
+2. If you did not enroll in the web app but were receiving Dual Stacking rewards through a participating app, you need to enroll on the web app.
+
+To check your enrollment status go to [app.stacks.co](https://app.stacks.co/).
+{% endhint %}
+
+Dual Stacking enables Bitcoin holders to earn Bitcoin-denominated rewards through Stacks' [Proof of Transfer](../stacks-101/proof-of-transfer.md) consensus. Rewards are paid in [sBTC](../sbtc/).
+
+Dual Stacking is the only way to earn Bitcoin rewards while stacking Bitcoin. Other blockchains pay rewards in their native token (ETH, SOL, etc.). They have no mechanism to generate real Bitcoin. **Stacks' Proof of Transfer (PoX)** is the architectural difference that makes Bitcoin earning Bitcoin rewards possible.\
+\
+As more BTC enters the Stacks network, rates will adjust. But the multiplier effect remains: pairing STX with your BTC and deploying sBTC into DeFi always amplify your returns.
+
+***
+
+Additional Resources
+
+* \[[Stacks YT](https://youtu.be/bfWPr_qMQmc?si=A9R2OKRHZ-N6Uwhe)] Dual Stacking Explained: Earn Bitcoin on Your Bitcoin
diff --git a/docs/learn/dual-stacking/dual-stacking-smart-contract.md b/docs/learn/dual-stacking/dual-stacking-smart-contract.md
new file mode 100644
index 0000000000..adcbcf4120
--- /dev/null
+++ b/docs/learn/dual-stacking/dual-stacking-smart-contract.md
@@ -0,0 +1,660 @@
+# Dual Stacking Smart Contract
+
+## Overview
+
+The Dual Stacking contract enables participants to earn boosted sBTC rewards by holding sBTC and optionally stacking STX. It operates in cycles with periodic snapshots to calculate rewards based on holdings and stacking participation.
+
+{% hint style="info" %}
+For the live dual stacking contract on mainnet, check out the contract page [here](https://explorer.hiro.so/txid/SP1HFCRKEJ8BYW4D0E3FAWHFDX8A25PPAA83HWWZ9.dual-stacking-v1?chain=mainnet).
+
+On December 15, 2025, the dual stacking contract will be upgraded to [`.dual-stacking-v2_0_2`](https://explorer.hiro.so/txid/SP1HFCRKEJ8BYW4D0E3FAWHFDX8A25PPAA83HWWZ9.dual-stacking-v2_0_2?chain=mainnet)
+{% endhint %}
+
+### Decentralized Architecture
+
+* Permissionless operations: Anyone can execute critical cycle operations including snapshot capturing, ratio proposal/validation, weight calculation, and reward distribution.
+* On-chain data only: All participant data (sBTC balances, STX stacking amounts) is read directly from the blockchain — no off-chain oracles or trusted data sources required.
+* Competitive ratio discovery: Multiple participants can propose different golden ratios; the system validates based on mathematical criteria (95th percentile), not admin approval.
+* Transparent execution: All operations are executed on-chain with verifiable results and public event logs.
+* Self-service enrollment: Users can enroll, opt-out, and manage their participation independently.
+
+### Main Operations
+
+{% stepper %}
+{% step %}
+**Initialization**
+
+The contract is initialized once with a Stacks block height parameter that is the first one in the Bitcoin block specified, or after it, in case there aren't any STX blocks anchored to it.
+{% endstep %}
+
+{% step %}
+**Enrollment**
+
+Users can self-enroll for participation with custom reward addresses. DeFi protocols can be enrolled by admin with custom tracking, stacking, and reward addresses. All participants can opt-out or change their addresses at any time.
+{% endstep %}
+
+{% step %}
+**Snapshots and Cycles**
+
+Anyone can trigger periodic snapshots that capture participant sBTC balances and STX stacking amounts from on-chain data based on predefined block intervals.
+{% endstep %}
+
+{% step %}
+**Ratio Computation**
+
+After snapshots are complete, anyone can propose a golden ratio (optimal STX/sBTC ratio), tally participant distributions, and validate if their proposal meets the 95th percentile criteria to determine the benchmark for maximum rewards.
+{% endstep %}
+
+{% step %}
+**Weight Calculation**
+
+Anyone can trigger participant weight calculations using the validated dual stacking formula that provides up to 10x boost (configurable) for those who meet or exceed the golden ratio.
+{% endstep %}
+
+{% step %}
+**Rewards**
+
+Anyone can trigger reward distribution every cycle based on calculated weights. Administrators can update configurations like APR, yield boost multiplier, snapshot length, and number of snapshots per cycle.
+{% endstep %}
+
+{% step %}
+**Administrative Controls**
+
+Admins maintain protocol parameters, enroll/opt-out DeFi protocols with special address configurations, manage whitelists and blacklists, and can perform emergency operations if needed.
+{% endstep %}
+{% endstepper %}
+
+***
+
+## Cycle Structure
+
+* Each cycle consists of a fixed number of snapshots (default 14).
+* Each snapshot occurs after a set number of Bitcoin blocks (default 150).
+* The total cycle length is thus 2100 Bitcoin blocks by default (14 snapshots × 150 blocks).
+* These defaults can be adjusted for production environments (e.g., 1 snapshot per day with appropriate block counts).
+
+## Dual Stacking Formula
+
+Weight Calculation:
+
+$$
+w_i = \cfrac{[B_i \cdot (1 + M \cdot \sqrt{r_i})]}{n}
+$$
+
+Where:
+
+* _w__i_ _ = weight for user i_
+* _B__i_ _ = sBTC balance of user i (sum across all snapshots)_
+* _M = yield boost multiplier (default 9, meaning max boost of 10x)_
+* _r__i_ _ = min(d__i_ _/D, 1), the ratio adjustment factor_
+* _d__i_ _ = S__i_ _/B__i_ _, user's personal STX/sBTC ratio_
+* _S__i_ _ = STX stacked by user i (sum across all snapshots)_
+* _D = golden ratio (95th percentile STX/sBTC ratio across all participants)_
+* _n = number of snapshots per cycle (default 14)_
+
+Rewards Distribution:
+
+$$
+R_i = (\frac{w_i}{Σw}) \cdot Total Rewards
+$$
+
+Where:
+
+* _R__i_ _ = reward for user i_
+* _Σw = sum of all participant weights_
+* _Total Rewards = min(pool balance, APR-based cap)_
+
+Key Properties:
+
+* _Participants with d__i_ _ ≥ D receive maximum boost of (M+1) x (default 10x)._
+* _Participants with d__i_ _ = 0 (no STX stacked) receive base rewards (1x)._
+* _Boost scales with the square root of the ratio for intermediate values._
+* _Whitelisted DeFi tracking addresses automatically receive maximum boost without needing to stack STX._
+* _Weights are divided by the number of snapshots per cycle to normalize across the cycle duration._
+
+***
+
+## Cycle Workflow
+
+The Dual Stacking smart contract operates in cycles, each divided into snapshots. The process ensures accurate reward distribution through a series of permissionless operations that anyone can execute.
+
+{% stepper %}
+{% step %}
+**Snapshot Phase (Anyone Can Execute)**
+
+* capture-snapshot-balances: Anyone can capture balances for enrolled users after each snapshot.
+* advance-to-next-snapshot: Anyone can transition to the next snapshot.
+* finalize-snapshots: Anyone can conclude all snapshot data after the final snapshot.
+{% endstep %}
+
+{% step %}
+**Ratio Validation Phase (Competitive & Permissionless)**
+
+* propose-golden-ratio: Anyone can propose a golden ratio.
+* tally-participant-ratios: The proposer tallies participant ratios relative to their proposed ratio.
+* validate-ratio: The proposer validates their proposal — succeeds only if it represents the 95th percentile.
+* Multiple proposals can be submitted; the first valid one locks in for the cycle.
+{% endstep %}
+
+{% step %}
+**Weight Computation Phase (Anyone Can Execute)**
+
+* calculate-participant-weights: Anyone can calculate participant weights using the dual stacking formula.
+* finalize-weight-computation: Anyone can finalize weight computation.
+{% endstep %}
+
+{% step %}
+**Reward Distribution Phase (Anyone Can Execute)**
+
+* set-is-distribution-enabled: Anyone can enable reward distribution by determining the available reward pool.
+* distribute-rewards: Anyone can distribute rewards to enrolled users based on their weights.
+* finalize-reward-distribution: Anyone can finalize reward distribution after all participants are rewarded.
+{% endstep %}
+
+{% step %}
+**Cycle Transition (Anyone Can Execute)**
+
+* advance-to-next-cycle: Anyone can advance to the next cycle after all rewards are distributed.
+{% endstep %}
+{% endstepper %}
+
+Note: All operations read data directly from the blockchain (sBTC balances from the sBTC token contract, STX stacking from native Stacks protocol). No off-chain data sources or trusted intermediaries are required.
+
+***
+
+## Public Functions
+
+### 1. Contract Initialization
+
+#### initialize-contract
+
+Activates the contract with an initial cycle.
+
+* Parameters: stx-block-height (uint)
+* Assertions:
+ * Current Bitcoin block height must be >= the configured cycle start Bitcoin block height.
+ * The contract must not be active.
+ * The Stacks block height must bracket the configured Bitcoin block height.
+* Effect:
+ * Initializes state variables for the first cycle and marks the contract as active.
+ * Records cycle data and the first snapshot.
+
+#### update-initialize-block
+
+Updates the initialization Bitcoin block height before the contract is activated.
+
+* Parameters: new-bitcoin-block-height (uint)
+* Assertions:
+ * Contract must not be active.
+ * Caller must be the admin.
+* Effect:
+ * Updates the starting Bitcoin block height for the first cycle.
+
+#### update-cycle-data-before-initialized
+
+Updates both the snapshots per cycle and blocks per snapshot for the first cycle before initialization.
+
+* Parameters: updated-snapshots-per-cycle (uint), updated-blocks-per-snapshot (uint)
+* Assertions:
+ * Contract must not be active.
+ * Caller must be the admin.
+* Effect:
+ * Sets the cycle structure for the first cycle.
+
+***
+
+### 2. Enrollment
+
+#### enroll
+
+Enrolls the caller for rewards in future cycles.
+
+* Parameters: rewarded-address (optional principal)
+* Assertions:
+ * Caller must not already be enrolled.
+ * Caller must not be blacklisted.
+ * Caller must hold at least the minimum required sBTC amount.
+* Effect:
+ * Adds the caller to the participants map with tracking, stacking, and rewarded addresses set appropriately.
+ * Increments the next cycle participant count.
+
+#### enroll-defi
+
+Enrolls a DeFi protocol for rewards with custom addresses (admin only).
+
+* Parameters:
+ * defi-contract (principal)
+ * tracking-address (principal)
+ * rewarded-address (principal)
+ * stacking-address (optional principal)
+* Assertions:
+ * Caller must be the admin.
+ * DeFi contract must not already be enrolled.
+ * DeFi contract must not be blacklisted.
+* Effect:
+ * Adds the DeFi protocol to the participants map with custom addresses.
+ * Increments the next cycle participant count.
+
+#### enroll-defi-batch
+
+Batch enroll multiple DeFi protocols (admin only).
+
+* Parameters: defi-contracts (list 900 {...})
+* Assertions:
+ * Caller must be the admin.
+* Effect:
+ * Enrolls multiple DeFi protocols in a single transaction.
+
+#### opt-out
+
+Allows the caller to opt out of participation in future cycles.
+
+* Assertions:
+ * Caller must be enrolled.
+* Effect:
+ * Removes the caller from the participants map.
+ * Decrements the next cycle participant count.
+
+#### opt-out-defi
+
+Opts out a DeFi protocol from participation (admin only).
+
+* Parameters: defi-contract (principal)
+* Assertions:
+ * Caller must be the admin.
+ * DeFi contract must be enrolled.
+* Effect:
+ * Removes the DeFi protocol from the participants map.
+
+#### opt-out-defi-batch
+
+Batch opt out multiple DeFi protocols (admin only).
+
+* Parameters: defi-contracts (list 200 principal)
+* Assertions:
+ * Caller must be the admin.
+* Effect:
+ * Opts out multiple DeFi protocols in a single transaction.
+
+***
+
+### 3. Participant Address Management
+
+* change-reward-address
+* change-reward-address-defi
+* change-stacking-address-defi
+* change-tracking-address-defi
+* change-addresses-defi
+* change-addresses-defi-batch
+
+(Each function has parameters, admin assertions where applicable, and updates participant/DeFi addresses as described in the original spec.)
+
+***
+
+### 4. Snapshots and Cycles
+
+#### capture-snapshot-balances
+
+Captures snapshot balances for a list of participants at the current snapshot block height. Permissionless.
+
+* Parameters: principals (list of up to 900 principals)
+* Assertions:
+ * The contract must be active.
+ * The current snapshot Stacks block height must be available.
+* Effect:
+ * Reads sBTC balance from the sBTC token contract for each participant.
+ * Reads STX stacked amount from native Stacks protocol (including liquid stacking if enabled).
+ * Updates snapshot totals and participant holdings.
+ * Tracks stacking and tracking addresses.
+
+#### advance-to-next-snapshot
+
+Advances the contract to the next snapshot within the current cycle. Permissionless.
+
+* Parameters: new-stx-block-height (uint)
+* Assertions:
+ * The contract must be active.
+ * All participants must be snapshotted.
+ * Current Bitcoin block height must have reached the next snapshot block.
+ * The cycle must not have ended.
+ * The Stacks block height must bracket the next snapshot Bitcoin block height.
+* Effect:
+ * Increments snapshot index.
+ * Aggregates snapshot totals into cycle totals.
+ * Resets snapshot counters.
+ * Records the new snapshot block heights.
+
+#### finalize-snapshots
+
+Finalizes all snapshots for the current cycle after the last snapshot is complete. Permissionless.
+
+* Assertions:
+ * The contract must be active.
+ * Snapshots must not already be finalized.
+ * Must be on the last snapshot of the cycle.
+ * All participants must be snapshotted in the final snapshot.
+* Effect:
+ * Aggregates the final snapshot totals into cycle totals.
+ * Marks snapshots as finalized.
+ * Sets last operation state to "concluded".
+ * Enables the ratio proposal phase.
+
+#### advance-to-next-cycle
+
+Advances the contract to the next cycle after all rewards are distributed. Permissionless.
+
+* Parameters: stx-block-height (uint)
+* Assertions:
+ * The contract must be active.
+ * Current Bitcoin block height must have reached the next cycle.
+ * All participants must be rewarded.
+ * Reward distribution must be finalized.
+ * The Stacks block height must bracket the next cycle Bitcoin block height.
+* Effect:
+ * Increments cycle ID.
+ * Resets state variables for the new cycle.
+ * Updates cycle configuration from next-cycle settings.
+ * Initializes the first snapshot of the new cycle.
+
+***
+
+### 5. Ratio Computation and Validation
+
+#### propose-golden-ratio
+
+Proposes a golden ratio for the current cycle. Permissionless.
+
+* Parameters: ratio (uint) — proposed ratio scaled by 10^8
+* Assertions:
+ * Snapshots must be finalized.
+ * A ratio must not already be validated for this cycle.
+ * The caller must not have already proposed a ratio for this cycle.
+* Effect:
+ * Records the proposed ratio for the caller.
+ * Initializes tracking for participant tallying.
+ * Sets last operation state to "proposed-ratio".
+
+#### change-proposed-golden-ratio
+
+Change a previously proposed golden ratio before validation.
+
+* Parameters: ratio (uint)
+* Assertions:
+ * The caller must have already proposed a ratio.
+ * The ratio must not yet be validated.
+* Effect:
+ * Updates the proposed ratio and resets tally data.
+
+#### tally-participant-ratios
+
+Tallies how many participants have ratios above, below, or equal to the proposed golden ratio.
+
+* Parameters: principals (list of up to 900 principals)
+* Assertions:
+ * The caller must have proposed a ratio.
+ * The ratio must not yet be validated.
+ * Must not have already tallied all participants.
+* Effect:
+ * Computes each participant's STX/sBTC ratio.
+ * Tracks sBTC amounts above, below, and equal to the proposed ratio.
+ * Increments participants counted.
+
+#### validate-ratio
+
+Validates that the proposed ratio represents the 95th percentile of participant ratios.
+
+* Assertions:
+ * The caller must have proposed a ratio.
+ * All participants must be tallied.
+ * The ratio must not already be validated.
+ * If no STX is stacked by anyone, ratio must equal 1.0 (baseline).
+ * sBTC above the ratio must be ≤ 5% of total sBTC.
+ * sBTC at or above the ratio must be ≥ 5% of total sBTC.
+* Effect:
+ * Marks the ratio as validated.
+ * Records the validated ratio for the cycle.
+ * Sets last operation state to "ratio-validated".
+
+#### set-max-percentage-above-ratio
+
+Updates the percentage threshold for validation (admin only).
+
+* Parameters: new-max-percentage-above-ratio (uint) — default 500 = 5%
+* Assertions:
+ * Caller must be the admin.
+* Effect:
+ * Updates the validation threshold.
+
+***
+
+### 6. Weight Computation
+
+#### calculate-participant-weights
+
+Calculates participant weights using the dual stacking formula. Permissionless.
+
+* Parameters: principals (list of up to 900 principals)
+* Assertions:
+ * The ratio must be validated.
+ * The current cycle Stacks block height must be available.
+* Effect:
+ * Retrieves validated golden ratio D.
+ * Applies minimum threshold to D to prevent division by zero $$D = max(D, 10^-8)$$.
+ * For each participant, computes weight using: $$w_i = \cfrac{[B_i \cdot (1 + M \cdot √r_i)]}{n}$$
+ * Accumulates total weights in total-weights-sum.
+ * Records individual weights per tracking address (not per enrolled address).
+
+Notes:
+
+* Multiple enrolled addresses sharing the same tracking address will share the same weight.
+* Can be called in batches of up to 900 participants.
+
+#### finalize-weight-computation
+
+Finalizes the weight computation phase. Permissionless.
+
+* Assertions:
+ * The ratio must be validated.
+ * Weights must not already be finalized.
+ * All participants must have weights computed.
+* Effect:
+ * Marks weights as computed.
+ * Sets last operation state to "weights-finalized".
+ * Enables the reward distribution phase.
+
+***
+
+### 7. Reward Distribution
+
+#### set-is-distribution-enabled
+
+Prepares the contract to distribute rewards by determining the available reward pool. Permissionless.
+
+* Assertions:
+ * The contract must be active.
+ * Distribution must not already be enabled.
+ * Weights must be computed.
+* Effect:
+ * Reads the contract's sBTC balance.
+ * Calculates rewards to distribute: min(pool balance, APR-based cap).
+ * The cap is: $$(CPR × total-weights-sum) / (M + 1)$$
+ * Marks rewards as ready for distribution.
+ * Sets last operation state to "set-can-distribute".
+
+#### distribute-rewards
+
+Distributes rewards to participants based on their computed weights. Permissionless.
+
+* Parameters: principals (list of up to 900 principals)
+* Assertions:
+ * Distribution must be enabled.
+* Effect:
+ * Calculates reward for each participant: (weight / total-weights) × total-rewards
+ * Transfers sBTC rewards to rewarded addresses.
+ * Marks participants as rewarded.
+ * Aggregates rewards per rewarded address.
+
+Notes:
+
+* Can be called in batches of up to 900 participants.
+* Multiple enrolled addresses sharing the same rewarded address aggregate rewards and only trigger one transfer per tracking address.
+
+#### finalize-reward-distribution
+
+Marks reward distribution as finalized for the current cycle. Permissionless.
+
+* Assertions:
+ * The contract must be active.
+ * All participants must be rewarded.
+ * Distribution must be enabled.
+ * Must not already be finalized.
+* Effect:
+ * Records the finalization block height.
+ * Sets last operation state to "finalized".
+ * Enables cycle advancement.
+ * Triggers external DeFi protocols to distribute their internal rewards (they monitor this finalization event).
+
+***
+
+### 8. Administrative Controls
+
+* update-admin
+* update-min-sbtc-hold-required-for-enrollment
+* update-snapshot-length
+* update-snapshots-per-cycle
+* update-cycle-data
+* update-bitcoin-blocks-per-year
+* update-APR
+* update-yield-boost-multiplier
+* set-liquid-stacking
+* emergency-withdraw-sbtc
+
+(Each of the above has parameters, admin-only assertions where applicable, and effects described in the original spec. Notable constraints include APR bounds and multiplier bounds.)
+
+***
+
+### 9. Blacklist Management
+
+* add-blacklisted
+* add-blacklisted-batch
+* remove-blacklisted
+* remove-blacklisted-batch
+
+(Admin-only operations to manage blacklist; adding an enrolled address auto opts it out.)
+
+***
+
+### 10. DeFi Whitelist Management
+
+#### whitelist-defi-tracking
+
+Adds a DeFi tracking address to the whitelist (gives maximum weight boost automatically).
+
+* Parameters: defi-rewards-contract (principal)
+* Assertions:
+ * Caller must be the admin.
+ * Address must not already be whitelisted.
+* Effect:
+ * Adds the tracking address to the whitelist.
+ * Whitelisted addresses receive maximum boost (ri = 1.0) in weight calculations.
+ * During snapshots, whitelisted addresses have their STX stacking recorded as 0 (they don't need to stack STX to receive max boost).
+
+#### remove-whitelisted-defi-tracking
+
+Removes a DeFi tracking address from the whitelist (admin only).
+
+* Parameters: defi-rewards-contract (principal)
+* Assertions:
+ * Caller must be the admin.
+ * Address must be whitelisted.
+* Effect:
+ * Removes the tracking address from the whitelist.
+
+#### remove-whitelisted-defi-tracking-batch
+
+Batch removes DeFi tracking addresses from the whitelist (admin only).
+
+* Parameters: defi-rewards-contract (list 200 principal)
+* Assertions:
+ * Caller must be the admin.
+* Effect:
+ * Removes multiple tracking addresses from the whitelist.
+
+***
+
+## Private Functions
+
+* update-snapshot-for-new-cycle: Resets snapshot counters and sets initial snapshot block heights.
+* reset-state-for-cycle: Applies next-cycle configuration, resets flags and totals, records cycle data, updates participant count.
+* capture-participant-balances: Reads sBTC and STX stacked at snapshot height, updates holdings and aggregates totals.
+* calculate-participant-weight: Computes weight per tracking address using the dual stacking formula (integer math details in original spec).
+* tally-user-ratio: Classifies a user's ratio relative to a proposed ratio and accumulates sBTC totals.
+* distribute-reward-user: Transfers reward per tracking address and updates rewarded status.
+* remove-participant: Deletes participant and decrements counts.
+* enroll-defi-one / change-addresses-defi-one: helpers for batch operations.
+* is-blacklisted: checks blacklist membership.
+
+(Private functions implement the described effects and integer scaling considerations; refer to function details above for math/scaling behavior.)
+
+***
+
+## Read-Only Functions
+
+### Cycle Information
+
+* get-current-cycle-id
+* cycle-data
+* get-cycle-current-state
+* current-overview-data
+* get-yield-cycle-data
+* nr-cycles-year
+* cycle-percentage-rate
+
+### Snapshot Information
+
+* snapshot-data
+* get-stacks-block-height-for-cycle-snapshot
+* get-bitcoin-block-height-for-cycle-snapshot
+
+### Reward Information
+
+* get-reward-distribution-status
+* is-distribution-ready
+* reward-amount-for-cycle-and-address
+* reward-amount-for-cycle-and-reward-address
+* is-distribution-finalized-for-current-cycle
+* get-distribution-finalized-at-height
+
+### Ratio and Weight Information
+
+* get-ratio-data
+* get-weight-computation-status
+* get-participant-weight
+
+### Participant Information
+
+* is-enrolled-in-next-cycle
+* is-enrolled-this-cycle
+* get-is-blacklisted
+* get-is-blacklisted-list
+* get-is-whitelisted-defi
+* get-latest-reward-address
+* get-participant-cycle-info
+
+### State and Configuration
+
+* get-last-operation-state
+* get-admin
+* get-is-contract-active
+* get-current-bitcoin-block-height
+* get-minimum-enrollment-amount
+* get-next-action-bitcoin-height
+* get-contract-sbtc-balance
+* get-apr-data
+
+### STX Stacking Queries
+
+* get-amount-stx-stacked
+* get-amount-stx-stacked-at-block-height
+* get-amount-stacked-at-block-height
+* get-amount-stacked-now
diff --git a/docs/learn/dual-stacking/economic-model.md b/docs/learn/dual-stacking/economic-model.md
new file mode 100644
index 0000000000..3bc7993e1c
--- /dev/null
+++ b/docs/learn/dual-stacking/economic-model.md
@@ -0,0 +1,73 @@
+---
+description: Understanding the economics behind Dual Stacking.
+---
+
+# Economic Model
+
+Users stake BTC, STX, or both to earn BTC-denominated rewards (via sBTC and BTC).
+
+Dual Stacking introduces an economic model in which BTC-denominated rewards scale with the participant’s ratio of sBTC to stacked STX as well as sBTC deployed in DeFi. This creates a direct link between Bitcoin capital and the growth of the Stacks ecosystem.
+
+All participants receive a baseline BTC-denominated reward on the sBTC enrolled in Dual Stacking. They have the option of earning additional rewards by stacking STX as well as deploying sBTC into DeFi.
+
+For Stacking STX, Bitcoin rewards grow based on an individuals STX-to-sBTC ratio relative to other participants, up to 10× the base yield. The system uses a square-root curve, meaning the first stacked STX has the greatest impact, with smaller boosts as more STX is stacked. The DeFi boost is straightforward, you automatically earn 10x multiple for any amount of sBTC deployed in DeFi.
+
+At the same time, an individual's stacked STX continues earning standard [stacking](../block-production/stacking.md) rewards.
+
+{% hint style="info" %}
+The following Reward Function Parameters section is taken directly from the [Dual Stacking litepaper](https://github.com/stx-labs/papers/blob/main/Dual%20Stacking%20Litepaper.pdf).
+{% endhint %}
+
+#### Reward Function Parameters
+
+* **Rewards Boost Multiplier** – Defines the maximum multiple of base reward attainable by users\
+ with the highest STX/BTC ratio. For example, with a 10× multiplier, a user earning 0.5%\
+ base reward could reach 5% if staking the maximum effective ratio of STX to BTC.
+* **Reward Function Curve** – Defines how rewards scale across intermediate STX/BTC\
+ ratios. A square-root curve introduces diminishing returns, encouraging broad\
+ participation rather than concentration of rewards among large holders.
+* **Max Reference STX/BTC Ratio** – Set to the BTC-weighted 95th percentile of STX/BTC\
+ ratios among users. That is, the value above which only 5% of total locked BTC has a\
+ higher STX/BTC ratio. Under this approach, for a user to unilaterally set the max\
+ reference STX/BTC ratio, the user would need both 5% of the total BTC locked and have\
+ the highest STX/BTC ratio for those BTC. This design minimizes manipulation by\
+ preventing outliers from disproportionately setting the maximum yield threshold.
+
+To describe the reward function more precisely, we’ll define some terms:
+
+* 𝑌 − 𝑇𝑜𝑡𝑎𝑙 𝐵𝑇𝐶 𝑑𝑖𝑠𝑡𝑟𝑖𝑏𝑢𝑡𝑒𝑑 𝑎𝑠 𝑟𝑒𝑤𝑎𝑟𝑑𝑠 𝑡𝑜 𝑑𝑢𝑎𝑙 𝑠𝑡𝑎𝑐𝑘𝑖𝑛𝑔 𝑑𝑢𝑟𝑖𝑛𝑔 𝑎 𝑆𝑡𝑎𝑐𝑘𝑖𝑛𝑔 𝑐𝑦𝑐𝑙𝑒
+* 𝐵𝑖 − 𝐴𝑚𝑜𝑢𝑛𝑡 𝑜𝑓 𝐵𝑇𝐶 𝑡ℎ𝑒 𝑖𝑡ℎ 𝑢𝑠𝑒𝑟 𝑙𝑜𝑐𝑘𝑠 𝑖𝑛 𝑎 𝑆𝑡𝑎𝑐𝑘𝑖𝑛𝑔 𝑐𝑦𝑐𝑙𝑒
+* 𝑆𝑖 − 𝐴𝑚𝑜𝑢𝑛𝑡 𝑜𝑓 𝑆𝑇𝑋 𝑡ℎ𝑒 𝑖𝑡ℎ 𝑢𝑠𝑒𝑟 𝑙𝑜𝑐𝑘𝑠 𝑖𝑛 𝑎 𝑆𝑡𝑎𝑐𝑘𝑖𝑛𝑔 𝑐𝑦𝑐𝑙𝑒
+* 𝑑𝑖 = 𝑆𝑖 _/_ 𝐵𝑖 − 𝐴𝑚𝑜𝑢𝑛𝑡 𝑜𝑓 𝑆𝑇𝑋 𝑝𝑒𝑟 𝐵𝑇𝐶 𝑡ℎ𝑒 𝑖𝑡ℎ 𝑢𝑠𝑒𝑟 𝑙𝑜𝑐𝑘𝑠 𝑖𝑛 𝑎 𝑆𝑡𝑎𝑐𝑘𝑖𝑛𝑔 𝑐𝑦𝑐𝑙𝑒
+* 𝐷 − 𝑀𝑎𝑥 𝑟𝑒𝑓𝑒𝑟𝑒𝑛𝑐𝑒 𝑑𝑖 , 𝑤ℎ𝑖𝑐ℎ 𝑖𝑠 𝑠𝑒𝑡 𝑡𝑜 𝑡ℎ𝑒 95𝑡ℎ 𝑝𝑒𝑟𝑐𝑒𝑛𝑡𝑖𝑙𝑒 𝑜𝑓 𝐵𝑇𝐶𝑤𝑒𝑖𝑔ℎ𝑡𝑒𝑑 𝑑𝑖
+* 𝑀 − 𝑟𝑒𝑤𝑎𝑟𝑑𝑠 𝑏𝑜𝑜𝑠𝑡 𝑚𝑢𝑙𝑡𝑖𝑝𝑙𝑖𝑒𝑟 𝑚𝑖𝑛𝑢𝑠 𝑜𝑛𝑒
+
+The first step in our reward function is to determine a normalized ratio, 𝑟𝑖 , for all users:
+
+$$
+𝑟_𝑖 = 𝑚𝑖𝑛(\frac{𝑑_𝑖}{𝐷}, 1)
+$$
+
+With the normalized ratio, we can then determine normalized weights, _w_𝑖 , for all users:
+
+$$
+𝑤_𝑖 = 𝐵_𝑖\cdot(1 + 𝑀\cdot \sqrt{𝑟_𝑖})
+$$
+
+Ultimately, the rewards for each user, _y_𝑖 , would be:
+
+$$
+𝑦_𝑖 = 𝑌 \cdot \frac{𝑤_𝑖}{\sum𝑤_𝑗}
+$$
+
+The generalized shape of the reward function is shown in the graph below. The two lines, one\
+dark orange and one light orange, show the shape of the yield curves for the expected rewards on\
+one’s sBTC holdings only as a result of dual stacking rewards, and the shape of the yield curve\
+for one’s combined sBTC and STX as a result of the combination of dual stacking rewards on\
+one’s sBTC and the standard stacking rewards for one’s STX.
+
+Staking STX alongside BTC amplifies rewards based on a yield curve, up to 10x.
+
+***
+
+For more detail on the Reward Function parameters and models, refer to the [Dual Stacking litepaper](https://github.com/stx-labs/papers/blob/main/Dual%20Stacking%20Litepaper.pdf).
diff --git a/docs/learn/dual-stacking/faq.md b/docs/learn/dual-stacking/faq.md
new file mode 100644
index 0000000000..862653f05d
--- /dev/null
+++ b/docs/learn/dual-stacking/faq.md
@@ -0,0 +1,141 @@
+---
+description: >-
+ Clarifying some common questions and sharing external resources for Dual
+ Stacking
+---
+
+# FAQ
+
+#### General Dual Stacking Questions
+
+
+
+Why can't other chains do this?
+
+Other blockchains pay rewards in what they can mint (ETH, SOL, etc.). They have no mechanism to channel real Bitcoin.
+
+Stacks has Proof of Transfer (PoX): Consensus mechanism that channels Bitcoin from miners to network participants. Operational since 2021. Over 4,000 BTC moved through PoX to date. This architectural difference makes Bitcoin earning Bitcoin rewards possible.
+
+
+
+
+
+How is this different from wrapped BTC?
+
+Rewards are paid in sBTC, redeemable for Bitcoin at any time and actual Bitcoin through PoX consensus, not platform tokens.
+
+{% hint style="info" %}
+**What is sBTC?**
+
+sBTC is a [SIP-010](https://github.com/stacksgov/sips/blob/main/sips/sip-010/sip-010-fungible-token-standard.md) token on Stacks that can be converted back to BTC on Bitcoin. The key property of sBTC is its 1:1 peg to Bitcoin, meaning 1 sBTC is always equivalent to 1 BTC.
+{% endhint %}
+
+
+
+
+
+When is this live?
+
+sBTC has been operational since December 2024. Dual Stacking launches November 2025.
+
+{% hint style="info" %}
+Coinciding with the Dual Stacking launch, the existing sBTC Rewards Program will sunset on October 31, 2024.
+{% endhint %}
+
+
+
+
+
+What will happen to the sBTC Rewards Program?
+
+Coinciding with the Dual Stacking launch, the existing sBTC Rewards Program will sunset on October 31, 2024. But don’t worry, you can earn even more sBTC with Dual Stacking - a new way to stack both STX and sBTC to create stronger alignment between Bitcoin capital and the Stacks network.
+
+**Key Dates to be aware of:**
+
+Oct 30: Dual Stacking launches and you can enroll to start earning
+
+Nov 4: sBTC Rewards Program ends and final rewards distributed
+
+Nov 5: First Dual Stacking rewards cycle begins
+
+Nov 20 (estimated): First Dual Stacking rewards cycle ends, rewards distributed\\
+
+
+
+#### Dual Stacking Rewards
+
+
+
+What are the minimum requirements?
+
+The minimum to mint sBTC via the sBTC Bridge app is currently at 0.001 BTC (100,000 sats).
+
+The minimum to enroll in Dual Stacking with your minted sBTC will be 0.0001 sBTC (10,000 sats).
+
+Stacking STX is done normally through stacking pools, so no minimum. The Dual Stacking web app will auto-detect if a user is currently stacking STX.
+
+
+
+
+
+Can I just stack BTC?
+
+Yes, if you lock BTC only, you still earn base rewards. No STX required to participate.
+
+
+
+
+
+Where does the yield come from?
+
+Stacks is the only blockchain with Proof of Transfer—a consensus mechanism that channels BTC from miners to participants who secure the network by Stacking STX. At launch, Dual Stacking rewards will come from Stacks entities who volunteer their Stacking rewards (earned via Proof of Transfer) to Dual Stacking participants as sBTC.
+
+
+
+
+
+How often are rewards paid out?
+
+Rewards are paid out roughly every 2 weeks in line with PoX stacking cycles, with the first cycle beginning on November 5, 2025.
+
+
+
+
+
+How are rewards calculated?
+
+A Dual Stacking calculator is available in-app to help estimate your annual rewards based on the ratio of BTC/STX you are stacking. The system uses a square-root reward curve that creates diminishing returns, meaning your first STX paired with BTC has the biggest impact on your rewards, while additional STX continues to help at a decreasing rate. Review the [Dual Stacking Litepaper](https://github.com/stx-labs/papers/blob/main/Dual%20Stacking%20Litepaper.pdf) for more details.
+
+
+
+
+
+How will this impact my existing Stacking rewards?
+
+Dual Stacking does not modify PoX consensus, meaning there is no direct change to native Stacking rewards. No action is required to continue natively Stacking. Dual Stacking may indirectly impact stacking rewards by increasing more stacking participation overall.
+
+
+
+#### Concerning Dual Stacking Security
+
+
+
+What are the trust assumptions?
+
+Dual Stacking operates as a transparent smart contract on the Stacks network. sBTC bridge operations are secured by a federation of [reputable signers](https://www.stacks.co/sbtc), with a 70% threshold of signer approval required for any transaction. No single entity can move funds unilaterally.
+
+
+
+#### External Resources
+
+* [\[Twitter\]](https://x.com/andrerserrano/status/1977845457226178757) Dual Stacking Litepaper Announcement from Andre Serrano
+* [\[Github\]](https://github.com/stx-labs/papers/blob/main/Dual%20Stacking%20Litepaper.pdf) Official Dual Stacking Litepaper
+* [\[Stacks Forum\]](https://forum.stacks.org/t/stacks-economic-model-unlocking-bitcoin-capital-long-term-growth/18035#dual-stacking-aligning-btc-and-stx-incentives-3) Initial Dual Stacking Announcement
+* [\[Stacks Official\]](https://www.stacks.co/dual-stacking) Dual Stacking landing page on stacks.co
+* \[[Stacks Blog](https://www.stacks.co/blog/dual-stacking-launches-on-stacks)] Official blog announcement
+* \[[Stacks Twitter](https://x.com/Stacks/status/1983900168954286342)] Official twitter announcement
+* \[[Dual Stacking App](https://app.stacks.co/)] Official Dual Stacking App
+
+#### Related Technical Resources
+
+* [\[Explorer\]](https://explorer.hiro.so/txid/SP1HFCRKEJ8BYW4D0E3FAWHFDX8A25PPAA83HWWZ9.dual-stacking-v1?chain=mainnet) `dual-stacking-v1` : Main Dual Stacking Contract
diff --git a/docs/learn/dual-stacking/how-to-start-dual-stacking/README.md b/docs/learn/dual-stacking/how-to-start-dual-stacking/README.md
new file mode 100644
index 0000000000..4ec94785b2
--- /dev/null
+++ b/docs/learn/dual-stacking/how-to-start-dual-stacking/README.md
@@ -0,0 +1,68 @@
+---
+description: Getting starting in Dual Stacking is simple.
+---
+
+# How to Start Dual Stacking
+
+app.stacks.co
+
+{% hint style="warning" %}
+Coinciding with the Dual Stacking launch, the existing sBTC Rewards Program will sunset on October 31, 2024. Starting October 30th, enroll in the Dual Stacking Rewards Contract (specific instructions to follow).
+
+NOTE: you will have until \~ Nov 4 (end of Cycle 121) to enroll, and you will continue to earn rewards from the current program until this date.
+{% endhint %}
+
+### **Overview of how to start Dual Stacking**
+
+1. **Mint sBTC** → 1:1 Bitcoin-backed. Enroll in dual stacking to earn baseline reward.
+2. **Stack STX** → Stack STX alongside your sBTC to multiply returns up to 10x.
+3. **Use in DeFi** → Deploy sBTC across protocols while still earning rewards.
+4. **Earn sBTC** → and redeem 1:1 for BTC anytime.
+
+PS: your stacked STX continues to earn bitcoin while in dual stacking.
+
+### Dual Stacking Web App
+
+The [Dual Stacking Web App](https://app.stacks.co/) is the primary user interface for participating in Dual Stacking — a mechanism that allows Bitcoin holders to earn BTC-denominated rewards through sBTC, and maximize those rewards by either stacking STX or using sBTC in DeFi.
+
+{% hint style="info" %}
+The minimum to mint sBTC via the sBTC Bridge app is currently at 0.001 BTC (100,000 sats).
+
+The minimum to enroll in Dual Stacking with your minted sBTC will be 0.0001 sBTC (10,000 sats).
+{% endhint %}
+
+Once connected to the web app, you'll see the dashboard that lays out all the metrics regarding your rewards composition and different methods for boosting rewards. Track your balances, rewards and payouts at anytime.
+
+The 'Boost your rewards' section will layout the steps for you to enroll and boost your rewards. All rewards are distributed in sBTC, redeemable 1:1 for BTC anytime.
+
+Track your balances, rewards and payouts at anytime on the Dual Stacking dashboard.
+
+Use the Dual Stacking calculator for estimated rewards based on the ratio of sBTC in your wallet and STX stacked. For more details on how your rewards are calculated and the math behind it, check out the section on the Dual Stacking [reward function](../economic-model.md#reward-function-parameters).
+
+Start Dual Stacking now with the following wallets:
+
+* [Dual Stack with Fordefi](using-fordefi.md)
+* [Dual Stacking with Asigna](using-asigna.md)
+* [Dual Stack with Leather](using-leather.md)
+
+### Who is this app for?
+
+{% tabs %}
+{% tab title="sBTC holders" %}
+At the end of October, users participating in sBTC Rewards program will need to enroll in Dual Stacking in order to continue earning sBTC rewards. This web app is the main way for them to do that.
+{% endtab %}
+
+{% tab title="BTC holders" %}
+There are relatively few options to earn yield on BTC. This app gives BTC holders an option to earn BTC denominated rewards in an easy, trust minimized way.
+{% endtab %}
+
+{% tab title="STX holders" %}
+STX holders who have participated in regular Stacking might be intrigued about a new type of Stacking, dual stacking. This app lets them try out a new iteration of a familiar flow.
+{% endtab %}
+{% endtabs %}
+
+***
+
+It's simple: Stack bitcoin, Earn bitcoin 🟧
+
+For more questions and help with Dual Stacking, reach out to us and the community in our [Discord](https://discord.gg/5DJaBrf) and on our official [Stacks twitter](https://twitter.com/Stacks).
diff --git a/docs/learn/dual-stacking/how-to-start-dual-stacking/using-asigna.md b/docs/learn/dual-stacking/how-to-start-dual-stacking/using-asigna.md
new file mode 100644
index 0000000000..a9f13e781f
--- /dev/null
+++ b/docs/learn/dual-stacking/how-to-start-dual-stacking/using-asigna.md
@@ -0,0 +1,129 @@
+---
+description: A guide in getting started with Dual Stacking using the Asigna wallet.
+---
+
+# Dual Stack with Asigna
+
+{% hint style="warning" %}
+This guide is specifically for entities or teams that use [Asigna](https://www.asigna.io/). This assumes you have the Asigna wallet setup with its browser extension and a multi-signature setup.
+{% endhint %}
+
+The Dual Stacking Web App is the primary user interface for participating in Dual Stacking — a mechanism that allows Bitcoin holders to earn BTC-denominated rewards through sBTC, and maximize those rewards by either stacking STX or using sBTC in DeFi.
+
+{% hint style="danger" %}
+Ensure that you are using the official Dual Stacking app located at [app.stacks.co](https://app.stacks.co/).
+{% endhint %}
+
+For this guide, we'll walkthrough how you can use your Asigna wallet in enrolling Dual Stacking and participating in DeFi for boosted rewards. This guide assumes you have a dedicated Stacks vault setup with multi-signature in your Asigna wallet.
+
+If you need assistance in setting up your vaults in Asigna, check out their dedicated [docs](https://asigna.gitbook.io/asigna).
+
+Before enrolling in Dual Stacking, you'll need sBTC. Peg in BTC to sBTC through the [sBTC bridge](https://app.stacks.co/) (where it remains 1:1 Bitcoin-backed at all times). Check out the dedicated [guide](https://docs.stacks.co/build/sbtc/how-to-use-the-sbtc-bridge-with-asigna) on how you can mint sBTC to your Asigna wallet.
+
+### Walkthrough for enrolling in Dual Stacking
+
+Here are the necessary steps to enroll your sBTC using Asigna:
+
+{% stepper %}
+{% step %}
+#### Connect Asigna to the Dual Stacking app
+
+Upon popup of the connect wallet modal, select the Asigna option to connect with. As per the usual flow of connecting your Asigna wallet with other Stacks apps, you'll most likely also need to connect the Asigna web wallet view with the Asigna browser extension before connecting with the app.
+
+Select which safe (Stacks vault) you want to connect with.
+{% endstep %}
+
+{% step %}
+#### Enroll now for Dual Stacking
+
+On the dashboard, you'll be able to see stats regarding your current sBTC in wallet, sBTC in DeFi, STX currently stacked, and estimated APY you could be earning.
+
+Let's get started by enrolling your sBTC into Dual Stacking.
+
+Your Asigna extension will appear with a popup asking you to review the transaction for approval. This will create the transaction which you will later sign and broadcast in your Asigna web wallet view.
+
+Click on 'Enroll now' under the 'Enroll for rewards' step and approve transaction in the extension popup.
+{% endstep %}
+
+{% step %}
+#### Sign transaction in Asigna web view
+
+If you navigate back to your Asigna web wallet view, you'll see the transaction queued up for signatures. In this scenario, we have a 2-of-2 multi-signature scheme setup so we'll need to sign the transaction by both parties involved.
+
+The first signature of the 2-of-2 setup will need to be signed in the Asigna web wallet view.
+
+Once the first signature is completed, the second signature will also need to take place in that respective signer's Asigna web wallet view. After signing, that same signer will then need to hit 'Execute' to complete the broadcasting of the transaction.
+
+The second signature of the 2-of-2 setup will need to be signed in the Asigna web wallet view. After all signatures are completed, hit 'Execute' to broadcast the transaction and navigate back to the Dual Stacking app.
+
+Execute the signed transaction to broadcast it to the Stacks network.
+
+
+
+Your enroll transaction will look like this [here](https://explorer.hiro.so/txid/0x3b4ea853df54825adad3ab475d93be18c6a12f04033c665d4597984786feb608?chain=mainnet).
+{% endstep %}
+
+{% step %}
+#### You are now enrolled in Dual Stacking
+
+You'll notice your sBTC now enrolled in Dual Stacking and when the rewards cycle will start for your enrolled sBTC.
+
+You are now Dual Stacking!
+
+The dashboard will also provide a view of your Dual Stacking portfolio.
+
+
+
+View when your sBTC will start earning rewards and the breakdown of rewards composition.
+{% endstep %}
+
+{% step %}
+#### Boost rewards by stacking STX
+
+So what's next? You could then boost your rewards by stacking STX. Let's start by stacking STX via [StackingDAO](https://www.stackingdao.com/). StackingDAO is a popular stacking option in Stacks as it is a liquid stacking method.
+
+{% hint style="info" %}
+There are other options for stacking your STX that you can find [here](https://app.leather.io/stacking).
+{% endhint %}
+
+Navigate to the StackingDAO embedded app within your Asigna web wallet view, connect your wallet, and start stacking. There are many methods to start liquid stacking or native stacking within StackingDAO. In this example, we'll use our STX to liquid stack with sBTC yield.
+
+Liquid stacking with sBTC yield allows us to stay liquid and earn sBTC while stacking.
+
+Complete the same 2-of-2 multi-signature flow in your Asigna web wallet views.
+
+After all signatures are completed, execute the transaction to broadcast it to the network.
+
+Navigate back to the Dual Stacking app, and you'll then notice the Dual Stacking app has instantly detect your stacked positions and include that as part of your portfolio's reward composition for boosted rewards.
+
+Notice the change in estimated APY and total portfolio value after stacking.
+
+Let's then boost reward with Stacks DeFi. This will help reach the maximum APY boost for your sBTC.
+{% endstep %}
+
+{% step %}
+#### Deploy your sBTC to Stacks DeFi protocols
+
+You'll notice near the bottom of the dashboard page, there is a section highlighting popular DeFi protocols in Stacks. Each one of these protocols are eligible for the boosted rewards you can realize.
+
+
+
+Let's deploy sBTC with Zest.
+
+{% hint style="info" %}
+As with using the embedded StackingDAO app, we'll also be using the embedded Zest app found in the Asigna web wallet view.
+{% endhint %}
+
+Supplying sBTC in Zest will provide users with a supply APY. Confirm the 'Supply' transaction via the same signature flow with Asigna.
+
+
+
+After deploying sBTC into Zest, navigate back to the Dual Stacking web app to see your current estimated APY and rewards composition.
+
+Check back on the Dual Stacking dashboard to stay current with your rewards and rewards composition. All rewards are distributed in sBTC, redeemable 1:1 for BTC anytime.
+{% endstep %}
+{% endstepper %}
+
+***
+
+Reach out to us on [Discord](https://discord.com/invite/stacks-621759717756370964) for any further questions regarding Dual Stacking.
diff --git a/docs/learn/dual-stacking/how-to-start-dual-stacking/using-fordefi.md b/docs/learn/dual-stacking/how-to-start-dual-stacking/using-fordefi.md
new file mode 100644
index 0000000000..dc9923af21
--- /dev/null
+++ b/docs/learn/dual-stacking/how-to-start-dual-stacking/using-fordefi.md
@@ -0,0 +1,123 @@
+---
+description: A guide in getting started with Dual Stacking using the Fordefi MPC wallet
+---
+
+# Dual Stack with Fordefi
+
+{% hint style="warning" %}
+This guide is specifically for entities or teams that use [Fordefi](https://fordefi.com/). This assumes you have the Fordefi wallet setup with its browser extension and with its mobile app.
+{% endhint %}
+
+The Dual Stacking Web App is the primary user interface for participating in Dual Stacking — a mechanism that allows Bitcoin holders to earn BTC-denominated rewards through sBTC, and maximize those rewards by either stacking STX or using sBTC in DeFi.
+
+{% hint style="danger" %}
+Ensure that you are using the official Dual Stacking app located at [app.stacks.co](https://app.stacks.co/).
+{% endhint %}
+
+For this guide, we'll walkthrough how you can use your Fordefi wallet in enrolling Dual Stacking and participating in DeFi for boosted rewards. This guide assumes you have a dedicated Bitcoin vault and Stacks vault setup in your Fordefi wallet.
+
+If you need assistance in setting up your vaults in Fordefi, check out their dedicated [docs](https://docs.fordefi.com/user-guide/policies).
+
+Before enrolling in Dual Stacking, you'll need sBTC. Peg in BTC to sBTC through the [sBTC bridge](https://app.stacks.co/) (where it remains 1:1 Bitcoin-backed at all times). Check out the dedicated guide on how you can mint sBTC to your Fordefi [wallet](https://docs.stacks.co/build/sbtc/how-to-use-the-sbtc-bridge-with-fordefi).
+
+### Walkthrough for enrolling in Dual Stacking
+
+Here are the necessary steps to enroll your sBTC using Fordefi:
+
+{% stepper %}
+{% step %}
+**Connect Fordefi to the Dual Stacking app**
+
+Upon popup of the connect wallet modal, select the Fordefi option to connect with. As per the usual flow of connecting your Fordefi wallet with other Stacks apps, it'll prompt you to first select your Bitcoin vault, and then your Stacks vault.
+
+Select which Bitcoin vault you want to connect with first.
+
+Then choose which Stacks vault you want to connect with.
+{% endstep %}
+
+{% step %}
+**Enroll now for Dual Stacking**
+
+On the dashboard, you'll be able to see stats regarding your current sBTC in wallet, sBTC in DeFi, STX currently stacked, and estimated APY you could be earning.
+
+Let's get started by enrolling your sBTC into Dual Stacking.
+
+Click on 'Enroll now' under the 'Enroll for rewards' step.
+{% endstep %}
+
+{% step %}
+**Create transaction**
+
+Your Fordefi extension will appear with a popup asking you to review the transaction for creation. This will create the transaction which you will later sign and broadcast in your Fordefi mobile wallet.
+
+Create the transaction to queue it up in your Fordefi wallet for signing and broadcasting.
+{% endstep %}
+
+{% step %}
+**Sign transaction in Fordefi mobile app**
+
+If you navigate back to your Fordefi web wallet, you'll see the transaction queued up for signatures. Depending on the transaction policy that is setup with your Fordefi vaults, you may need to instruct the designated approvers to all confirm and sign the transaction in their Fordefi mobile wallets.
+
+The 'enroll' transaction will be queued up in your Fordefi web wallet. You'll need to sign the transaction via the mobile wallet.
+
+Within the Fordefi mobile wallet, you'll see the same transaction waiting for signing. Go ahead and sign the transaction which will then broadcast the transaction to the network.
+
+Complete all signatures in the Fordefi mobile wallet.
+
+Your enroll transaction will look like this [here](https://explorer.hiro.so/txid/0x3b4ea853df54825adad3ab475d93be18c6a12f04033c665d4597984786feb608?chain=mainnet).
+{% endstep %}
+
+{% step %}
+**You are now enrolled in Dual Stacking**
+
+You'll notice your sBTC now enrolled in Dual Stacking and when the rewards cycle will start for your enrolled sBTC.
+
+You are now Dual Stacking!
+
+The dashboard will also provide a view of your Dual Stacking portfolio.
+
+View when your sBTC will start earning rewards and the breakdown of rewards composition.
+{% endstep %}
+
+{% step %}
+**Boost rewards by stacking STX**
+
+So what's next? You could then boost your rewards by stacking STX. Let's start by stacking STX via [StackingDAO](https://www.stackingdao.com/). StackingDAO is a popular stacking option in Stacks as it is a liquid stacking method.
+
+{% hint style="info" %}
+There are other options for stacking your STX that you can find [here](https://app.leather.io/stacking).
+{% endhint %}
+
+Navigate to the StackingDAO app, connect your wallet, and start stacking. There are many methods to start liquid stacking or native stacking within StackingDAO. In this example, we'll use our STX to liquid stack with sBTC yield.
+
+Liquid stacking with sBTC yield allows us to stay liquid and earn sBTC while stacking.
+
+You'll then notice the Dual Stacking app to detect your stacked positions and include that as part of your portfolio's reward composition for boosted rewards.
+
+Notice the change in estimated APY and total portfolio value after stacking.
+
+Let's then boost reward with Stacks DeFi. This will help reach the maximum APY boost for your sBTC.
+{% endstep %}
+
+{% step %}
+**Deploy your sBTC to Stacks DeFi protocols**
+
+You'll notice near the bottom of the dashboard page, there is a section highlighting popular DeFi protocols in Stacks. Each one of these protocols are eligible for the boosted rewards you can realize.
+
+
+
+Let's deploy sBTC with Zest. Supplying sBTC in Zest will provide users with a supply APY. Confirm the 'Supply' transaction via the same signature flow with Fordefi.
+
+
+
+After deploying sBTC into Zest, navigate back to the Dual Stacking web app to see your current estimated APY and rewards composition.
+
+
+
+Check back on the Dual Stacking dashboard to stay current with your rewards and rewards composition. All rewards are distributed in sBTC, redeemable 1:1 for BTC anytime.
+{% endstep %}
+{% endstepper %}
+
+***
+
+Reach out to us on [Discord](https://discord.com/invite/stacks-621759717756370964) for any further questions regarding Dual Stacking.
diff --git a/docs/learn/dual-stacking/how-to-start-dual-stacking/using-leather.md b/docs/learn/dual-stacking/how-to-start-dual-stacking/using-leather.md
new file mode 100644
index 0000000000..d779280527
--- /dev/null
+++ b/docs/learn/dual-stacking/how-to-start-dual-stacking/using-leather.md
@@ -0,0 +1,111 @@
+---
+description: A guide in getting started with Dual Stacking using the Leather wallet.
+---
+
+# Dual Stack with Leather
+
+{% hint style="warning" %}
+This guide is specifically for users that use the Leather wallet. This assumes you have the Leather wallet extension setup. The flow will also be similar for Xverse wallet users.
+{% endhint %}
+
+The Dual Stacking Web App is the primary user interface for participating in Dual Stacking — a mechanism that allows Bitcoin holders to earn BTC-denominated rewards through sBTC, and maximize those rewards by either stacking STX or using sBTC in DeFi.
+
+{% hint style="danger" %}
+Ensure that you are using the official Dual Stacking app located at [app.stacks.co](https://app.stacks.co/).
+{% endhint %}
+
+For this guide, we'll walkthrough how you can use your Leather wallet in enrolling Dual Stacking and participating in DeFi for boosted rewards. This guide assumes you have already setup a Leather wallet extension.
+
+If you need assistance in setting up your Leather wallet extension, check out their webpage [here](https://leather.io/).
+
+Before enrolling in Dual Stacking, you'll need sBTC. Peg in BTC to sBTC through the [sBTC bridge](https://app.stacks.co/) (where it remains 1:1 Bitcoin-backed at all times). Check out the dedicated [guide](https://docs.stacks.co/build/sbtc/how-to-use-the-sbtc-bridge) on how you can mint sBTC to your Leather wallet.
+
+### Walkthrough for enrolling in Dual Stacking
+
+Here are the necessary steps to enroll your sBTC using Leather:
+
+{% stepper %}
+{% step %}
+**Connect Leather to the Dual Stacking app**
+
+Upon popup of the connect wallet modal, select the Leather option to connect with.
+
+Confirm connecting in your Leather modal popup.
+{% endstep %}
+
+{% step %}
+**Enroll now for Dual Stacking**
+
+On the dashboard, you'll be able to see stats regarding your current sBTC in wallet, sBTC in DeFi, STX currently stacked, and estimated APY you could be earning.
+
+
+
+Let's get started by enrolling your sBTC into Dual Stacking.
+
+
+
+Your Leather extension will appear with a popup asking you to review the transaction for approval. This will create the transaction which you will sign and broadcast in your Leather web wallet view.
+
+Your enroll transaction will look like this [here](https://explorer.hiro.so/txid/0x3b4ea853df54825adad3ab475d93be18c6a12f04033c665d4597984786feb608?chain=mainnet).
+{% endstep %}
+
+{% step %}
+**You are now enrolled in Dual Stacking**
+
+You'll notice your sBTC now enrolled in Dual Stacking and when the rewards cycle will start for your enrolled sBTC.
+
+You are now Dual Stacking!
+
+The dashboard will also provide a view of your Dual Stacking portfolio. Track your balances, rewards and payouts at anytime.
+
+
+
+Use the Dual Stacking calculator for estimated rewards based on the ratio of sBTC in your wallet and STX stacked. For more details on your rewards are calculated and the math behind it, check out the section on the [reward function](../economic-model.md#reward-function-parameters).
+
+
+{% endstep %}
+
+{% step %}
+**Boost rewards by stacking STX**
+
+So what's next? You could then boost your rewards by stacking STX. Let's start by stacking STX via [StackingDAO](https://www.stackingdao.com/). StackingDAO is a popular stacking option in Stacks as it is a liquid stacking method.
+
+{% hint style="info" %}
+There are other options for stacking your STX that you can find [here](https://app.leather.io/stacking).
+{% endhint %}
+
+Navigate to the StackingDAO app, connect your wallet, and start stacking. There are many methods to start liquid stacking or native stacking within StackingDAO. In this example, we'll use our STX to liquid stack with sBTC yield.
+
+Liquid stacking with sBTC yield allows us to stay liquid and earn sBTC while stacking.
+
+Choose the amount in STX that you want to stack and click on 'Confirm Stack', your Leather wallet extension will then appear prompting you to approve transaction.
+
+Navigate back to the Dual Stacking app, and you'll then notice the Dual Stacking app has instantly detect your stacked positions and include that as part of your portfolio's reward composition for boosted rewards.
+
+Notice the change in estimated APY and total portfolio value after stacking.
+
+Let's then boost reward with Stacks DeFi. This will help reach the maximum APY boost for your sBTC.
+{% endstep %}
+
+{% step %}
+**Deploy your sBTC to Stacks DeFi protocols**
+
+You'll notice near the bottom of the dashboard page, there is a section highlighting popular DeFi protocols in Stacks. Each one of these protocols are eligible for the boosted rewards you can realize.
+
+
+
+Let's deploy sBTC with Zest. Supplying sBTC in Zest will provide users with a supply APY. Confirm the 'Supply' transaction via the same signature flow using Leather.
+
+
+
+After deploying sBTC into Zest, navigate back to the Dual Stacking web app to see your current estimated APY and rewards composition.
+
+View a breakdown of rewards per reward cycle.
+
+Check back on the Dual Stacking dashboard to stay current with your rewards and rewards composition. Depending on when your rewards cycle start for your enrollment, you'll see the rewards breakdown in the middle section. All rewards are distributed in sBTC, redeemable 1:1 for BTC anytime.
+{% endstep %}
+{% endstepper %}
+
+***
+
+Reach out to us on [Discord](https://discord.com/invite/stacks-621759717756370964) for any further questions regarding Dual Stacking.
diff --git a/docs/learn/network-fundamentals/README.md b/docs/learn/network-fundamentals/README.md
new file mode 100644
index 0000000000..9cbb5d7a9e
--- /dev/null
+++ b/docs/learn/network-fundamentals/README.md
@@ -0,0 +1,5 @@
+# Network Fundamentals
+
+Now that you have a high-level understanding of what Stacks is and how it works, let's dive into some more details of all of the components that make up the Stacks Bitcoin L2.
+
+We're going to start with the basics of how the network is actually structured and the components that comprise it.
diff --git a/docs/learn/network-fundamentals/authentication.md b/docs/learn/network-fundamentals/authentication.md
new file mode 100644
index 0000000000..e4bee58941
--- /dev/null
+++ b/docs/learn/network-fundamentals/authentication.md
@@ -0,0 +1,103 @@
+# Authentication
+
+source: Hiro blog
+
+### Introduction
+
+This guide explains how authentication is performed on the Stacks blockchain.
+
+Authentication provides a way for users to identify themselves to an app while retaining complete control over their credentials and personal details.
+
+Users who register for your app can subsequently authenticate to any other app with support for the [Bitcoin Name System](bitcoin-name-system.md) and vice versa.
+
+### Web2 vs Web3 Authentication
+
+If you come from the web2 world, you are likely used to authenticating with usernames and passwords, where the user's info is stored in a database. Upon entering the password, it is hashed and compared to the hash stored in the database and, if it matches, the user is logged in.
+
+Web3 authentication works a bit differently. One of the core philosophies of web3 is data ownership, which means users are in control of their data, including their authentication.
+
+Authentication in the Bitcoin and Stacks world makes use of cryptography to generate private keys, public keys and addresses.
+
+We'll go over the basics here, but if you want to dig in, [Learn Me a Bitcoin](https://learnmeabitcoin.com/beginners/guide/keys-addresses/) is a great place to start.
+
+To generate a Stacks account, we generate a private key from a 24 word mnemonic phrase, as discussed in the previous section. This private key is then used to generate a public key using a one-way hash function. Meaning you can derive a public key from a private key, but not vice versa.
+
+A user's private key is their main source of security and is used to authenticate them. Do not lose your private key.
+
+So, when I use a wallet app like [Leather](https://leather.io/) and I want to use it to authenticate with a dapp like StackingDAO, what I am doing is that I am giving my wallet my private key, proving that I own the corresponding address.
+
+The wallet will then pass that information (my address and public key) to the app along with a signature.
+
+A signature can be thought of as proof that I own the private key without actually revealing the private key. That mechanism is how I can use the same wallet and address to log in to any app that supports Stacks authentication.
+
+Third Web has a great [conceptual primer](https://blog.thirdweb.com/web3-auth/) on web3 authentication.
+
+For a more practical introduction, take a look at the [Quickstart tutorial ](https://app.gitbook.com/o/hoh4mQXTl8NvI3cETroY/s/Zz9BLmTU9oydDpL3qiUh/)and [Hiro's Stacks.js docs](https://docs.hiro.so/stacks/connect/guides/authenticate-users).
+
+### How it works
+
+The authentication flow with Stacks is similar to the typical client-server flow used by centralized sign in services (for example, OAuth). However, with Stacks the authentication flow happens entirely client-side.
+
+{% hint style="info" %}
+This explanation is here so you can understand how this process works, but the bulk of this functionality is handled by the wallet and the JS library you use. Take a look at the [Stacks.js docs](https://docs.hiro.so/stacks/stacks.js/concepts/accounts-and-addresses) for more info.
+{% endhint %}
+
+An app and authenticator, such as the [Leather wallet](https://leather.io/), communicate during the authentication flow by passing back and forth two tokens. The requesting app sends the authenticator an `authRequest` token. Once a user approves authentication, the authenticator responds to the app with an `authResponse` token.
+
+These tokens are based on [a JSON Web Token (JWT) standard](https://tools.ietf.org/html/rfc7519) with additional support for the `secp256k1` curve used by Bitcoin and many other cryptocurrencies. They are passed via URL query strings.
+
+When a user chooses to authenticate an app, it sends the `authRequest` token to the authenticator via a URL query string with an equally named parameter:
+
+`https://wallet.hiro.so/...?authRequest=j902120cn829n1jnvoa...`
+
+When the authenticator receives the request, it generates an `authResponse` token for the app using an ephemeral transit key. The ephemeral transit key is just used for the particular instance of the app, in this case, to sign the `authRequest`.
+
+The app stores the ephemeral transit key during request generation. The public portion of the transit key is passed in the `authRequest` token. The authenticator uses the public portion of the key to encrypt an app private key which is returned via the `authResponse`.
+
+The authenticator generates the app private key from the user's identity address private key and the app's domain. The app private key serves three functions:
+
+{% stepper %}
+{% step %}
+#### It is used to create credentials that give the app access to a storage bucket in the user's Gaia hub
+
+This allows the app to access the user's app-specific storage in their Gaia hub.
+{% endstep %}
+
+{% step %}
+#### It is used in the end-to-end encryption of files stored for the app in the user's Gaia storage
+
+This key is used to encrypt files so only the app (with the derived key) can decrypt them.
+{% endstep %}
+
+{% step %}
+#### It serves as a cryptographic secret that apps can use to perform other cryptographic functions
+
+Apps can use this deterministic secret for additional cryptographic operations tied to the user's identity and domain.
+{% endstep %}
+{% endstepper %}
+
+Finally, the app private key is deterministic, meaning that the same private key will always be generated for a given Stacks address and domain.
+
+### Key pairs
+
+Authentication with Stacks makes extensive use of public key cryptography generally and ECDSA with the `secp256k1` curve in particular.
+
+The following sections describe the three public-private key pairs used, including how they're generated, where they're used and to whom private keys are disclosed.
+
+#### Transit private key
+
+The transit private key is an ephemeral key that is used to encrypt secrets that need to be passed from the authenticator to the app during the authentication process. It is randomly generated by the app at the beginning of the authentication response.
+
+The public key that corresponds to the transit private key is stored in a single element array in the `public_keys` key of the authentication request token. The authenticator encrypts secret data such as the app private key using this public key and sends it back to the app when the user signs in to the app. The transit private key signs the app authentication request.
+
+#### Identity address private key
+
+The identity address private key is derived from the user's keychain phrase and is the private key of the Stacks username that the user chooses to use to sign in to the app. It is a secret owned by the user and never leaves the user's instance of the authenticator.
+
+This private key signs the authentication response token for an app to indicate that the user approves sign in to that app.
+
+#### App private key
+
+The app private key is an app-specific private key that is generated from the user's identity address private key using the `domain_name` as input.
+
+The app private key is securely shared with the app on each authentication, encrypted by the authenticator with the transit public key. Because the transit key is only stored on the client side, this prevents a man-in-the-middle attack where a server or internet provider could potentially snoop on the app private key.
diff --git a/docs/learn/network-fundamentals/bitcoin-name-system.md b/docs/learn/network-fundamentals/bitcoin-name-system.md
new file mode 100644
index 0000000000..159af84974
--- /dev/null
+++ b/docs/learn/network-fundamentals/bitcoin-name-system.md
@@ -0,0 +1,210 @@
+# Bitcoin Name System
+
+source: Hiro blog
+
+Bitcoin Name System (BNS) is a network system that binds Stacks usernames to off-chain state without relying on any central points of control.
+
+The Stacks V1 blockchain implemented BNS through first-order name operations. In Stacks V2, BNS is instead implemented through a smart-contract loaded during the genesis block.
+
+Names in BNS have three properties:
+
+* **Names are globally unique.** The protocol does not allow name collisions, and all well-behaved nodes resolve a given name to the same state.
+* **Names are human-meaningful.** Each name is chosen by its creator.
+* **Names are strongly owned.** Only the name's owner can change the state it resolves to. Specifically, a name is owned by one or more ECDSA private keys.
+
+The Stacks blockchain ensures that each node's BNS view is synchronized to all of the other nodes in the world, so queries on one node will be the same on other nodes. Stacks blockchain nodes allow a name's owner to bind up to 40Kb of off-chain state to their name, which will be replicated to all other Stacks blockchain nodes via a P2P network.
+
+The biggest consequence for developers is that in BNS, reading name state is fast and cheap but writing name state is slow and expensive. This is because registering and modifying names requires one or more transactions to be sent to the underlying blockchain, and BNS nodes will not process them until they are sufficiently confirmed. Users and developers need to acquire and spend the requisite cryptocurrency (STX) to send BNS transactions.
+
+### Motivation behind name systems
+
+We rely on name systems in everyday life, and they play a critical role in many different applications. For example, when you look up a friend on social media, you are using the platform's name system to resolve their name to their profile. When you look up a website, you are using the Domain Name Service to resolve the hostname to its host's IP address. When you check out a Git branch, you are using your Git client to resolve the branch name to a commit hash. When you look up someone's PGP key on a keyserver, you are resolving their key ID to their public key.
+
+What kinds of things do we want to be true about names? In BNS, names are globally unique, names are human-meaningful, and names are strongly owned. However, if you look at these examples, you'll see that each of them only guarantees two of these properties. This limits how useful they can be.
+
+* In DNS and social media, names are globally unique and human-readable, but not strongly owned. The system operator has the final say as to what each name resolves to.
+ * Problem: Clients must trust the system to make the right choice in what a given name resolves to. This includes trusting that no one but the system administrators can make these changes.
+* In Git, branch names are human-meaningful and strongly owned, but not globally unique. Two different Git nodes may resolve the same branch name to different unrelated repository states.
+ * Problem: Since names can refer to conflicting state, developers have to figure out some other mechanism to resolve ambiguities.
+* In PGP, names are key IDs. They are globally unique and cryptographically owned, but not human-readable. PGP key IDs are derived from the keys they reference.
+ * Problem: These names are difficult for most users to remember since they do not carry semantic information relating to their use in the system.
+
+BNS names have all three properties, and none of these problems. This makes it a powerful tool for building all kinds of network applications. With BNS, we can do the following and more:
+
+* Build domain name services where hostnames can't be hijacked.
+* Build social media platforms where user names can't be stolen by phishers.
+* Build version control systems where repository branches do not conflict.
+* Build public-key infrastructure where it's easy for users to discover and remember each other's keys.
+
+### Organization of BNS
+
+BNS names are organized into a global name hierarchy. There are three different layers in this hierarchy related to naming:
+
+* **Namespaces.** These are the top-level names in the hierarchy. An analogy to BNS namespaces are DNS top-level domains. Existing BNS namespaces include `.id`, `.podcast`, and `.helloworld`. All other names belong to exactly one namespace. Anyone can create a namespace, but in order for the namespace to be persisted, it must be _launched_ so that anyone can register names in it. Namespaces are not owned by their creators.
+* **BNS names.** These are names whose records are stored directly on the blockchain. The ownership and state of these names are controlled by sending blockchain transactions. Example names include `verified.podcast` and `muneeb.id`. Anyone can create a BNS name, as long as the namespace that contains it exists already.
+* **BNS subdomains.** These are names whose records are stored off-chain, but are collectively anchored to the blockchain. The ownership and state for these names lives within the P2P network data. While BNS subdomains are owned by separate private keys, a BNS name owner must broadcast their subdomain state. Example subdomains include `jude.personal.id` and `podsaveamerica.verified.podcast`. Unlike BNS namespaces and names, the state of BNS subdomains is _not_ part of the blockchain consensus rules.
+
+A feature comparison matrix summarizing the similarities and differences between these name objects:
+
+| Feature | **Namespaces** | **BNS names** | **BNS Subdomains** |
+| -------------------------------------- | -------------- | ------------- | ------------------ |
+| Globally unique | X | X | X |
+| Human-meaningful | X | X | X |
+| Owned by a private key | | X | X |
+| Anyone can create | X | X | \[1] |
+| Owner can update | | X | \[1] |
+| State hosted on-chain | X | X | |
+| State hosted off-chain | | X | X |
+| Behavior controlled by consensus rules | X | X | |
+| May have an expiration date | | X | |
+
+\[1] Requires the cooperation of a BNS name owner to broadcast its transactions
+
+### Namespaces
+
+Namespaces are the top-level name objects in BNS. They control a few properties about the names within them:
+
+* How expensive they are to register
+* How long they last before they have to be renewed
+* Who (if anyone) receives the name registration fees
+* Who is allowed to seed the namespace with its initial names
+
+At the time of this writing, by far the largest BNS namespace is the `.id` namespace. Names in the `.id` namespace are meant for resolving user identities. Short names in `.id` are more expensive than long names, and have to be renewed by their owners every two years. Name registration fees are not paid to anyone in particular—they are instead sent to a "black hole" where they are rendered non-spendable (the intention is to discourage ID squatters).
+
+Unlike DNS, anyone can create a namespace and set its properties. Namespaces are created on a first-come first-serve basis, and once created, they last forever.
+
+However, creating a namespace is not free. The namespace creator must burn cryptocurrency to do so. The shorter the namespace, the more cryptocurrency must be burned (that is, short namespaces are more valuable than long namespaces). For example, it cost Blockstack PBC 40 BTC to create the `.id` namespace in 2015 (in transaction `5f00b8e609821edd6f3369ee4ee86e03ea34b890e242236cdb66ef6c9c6a1b281`).
+
+Namespaces can be between 1 and 19 characters long, and are composed of the characters `a-z`, `0-9`, `-`, and `_`.
+
+### Subdomains
+
+BNS names are strongly owned because the owner of its private key can generate valid transactions that update its zone file hash and owner. However, this comes at the cost of requiring a name owner to pay for the underlying transaction in the blockchain. Moreover, this approach limits the rate of BNS name registrations and operations to the underlying blockchain's transaction bandwidth.
+
+BNS overcomes this with subdomains. A **BNS subdomain** is a type of BNS name whose state and owner are stored outside of the blockchain, but whose existence and operation history are anchored to the blockchain. Like their on-chain counterparts, subdomains are globally unique, strongly owned, and human-readable. BNS gives them their own name state and public keys. Unlike on-chain names, subdomains can be created and managed cheaply, because they are broadcast to the BNS network in batches. A single blockchain transaction can send up to 120 subdomain operations.
+
+This is achieved by storing subdomain records in the BNS name zone files. An on-chain name owner broadcasts subdomain operations by encoding them as `TXT` records within a DNS zone file. To broadcast the zone file, the name owner sets the new zone file hash with a `NAME_UPDATE` transaction and replicates the zone file. This, in turn, replicates all subdomain operations it contains, and anchors the set of subdomain operations to an on-chain transaction. The BNS node's consensus rules ensure that only valid subdomain operations from valid `NAME_UPDATE` transactions will ever be stored.
+
+For example, the name `verified.podcast` once wrote the zone file hash `247121450ca0e9af45e85a82e61cd525cd7ba023`, which is the hash of the following zone file:
+
+```bash
+$TTL 3600
+1yeardaily TXT "owner=1MwPD6dH4fE3gQ9mCov81L1DEQWT7E85qH" "seqn=0" "parts=1" "zf0=JE9SSUdJTiAxeWVhcmRhaWx5CiRUVEwgMzYwMApfaHR0cC5fdGNwIFVSSSAxMCAxICJodHRwczovL3BoLmRvdHBvZGNhc3QuY28vMXllYXJkYWlseS9oZWFkLmpzb24iCg=="
+2dopequeens TXT "owner=1MwPD6dH4fE3gQ9mCov81L1DEQWT7E85qH" "seqn=0" "parts=1" "zf0=JE9SSUdJTiAyZG9wZXF1ZWVucwokVFRMIDM2MDAKX2h0dHAuX3RjcCBVUkkgMTAgMSAiaHR0cHM6Ly9waC5kb3Rwb2RjYXN0LmNvLzJkb3BlcXVlZW5zL2hlYWQuanNvbiIK"
+10happier TXT "owner=1MwPD6dH4fE3gQ9mCov81L1DEQWT7E85qH" "seqn=0" "parts=1" "zf0=JE9SSUdJTiAxMGhhcHBpZXIKJFRUTCAzNjAwCl9odHRwLl90Y3AgVVJJIDEwIDEgImh0dHBzOi8vcGguZG90cG9kY2FzdC5jby8xMGhhcHBpZXIvaGVhZC5qc29uIgo="
+31thoughts TXT "owner=1MwPD6dH4fE3gQ9mCov81L1DEQWT7E85qH" "seqn=0" "parts=1" "zf0=JE9SSUdJTiAzMXRob3VnaHRzCiRUVEwgMzYwMApfaHR0cC5fdGNwIFVSSSAxMCAxICJodHRwczovL3BoLmRvdHBvZGNhc3QuY28vMzF0aG91Z2h0cy9oZWFkLmpzb24iCg=="
+359 TXT "owner=1MwPD6dH4fE3gQ9mCov81L1DEQWT7E85qH" "seqn=0" "parts=1" "zf0=JE9SSUdJTiAzNTkKJFRUTCAzNjAwCl9odHRwLl90Y3AgVVJJIDEwIDEgImh0dHBzOi8vcGguZG90cG9kY2FzdC5jby8zNTkvaGVhZC5qc29uIgo="
+30for30 TXT "owner=1MwPD6dH4fE3gQ9mCov81L1DEQWT7E85qH" "seqn=0" "parts=1" "zf0=JE9SSUdJTiAzMGZvcjMwCiRUVEwgMzYwMApfaHR0cC5fdGNwIFVSSSAxMCAxICJodHRwczovL3BoLmRvdHBvZGNhc3QuY28vMzBmb3IzMC9oZWFkLmpzb24iCg=="
+onea TXT "owner=1MwPD6dH4fE3gQ9mCov81L1DEQWT7E85qH" "seqn=0" "parts=1" "zf0=JE9SSUdJTiBvbmVhCiRUVEwgMzYwMApfaHR0cC5fdGNwIFVSSSAxMCAxICJodHRwczovL3BoLmRvdHBvZGNhc3QuY28vb25lYS9oZWFkLmpzb24iCg=="
+10minuteteacher TXT "owner=1MwPD6dH4fE3gQ9mCov81L1DEQWT7E85qH" "seqn=0" "parts=1" "zf0=JE9SSUdJTiAxMG1pbnV0ZXRlYWNoZXIKJFRUTCAzNjAwCl9odHRwLl90Y3AgVVJJIDEwIDEgImh0dHBzOi8vcGguZG90cG9kY2FzdC5jby8xMG1pbnV0ZXRlYWNoZXIvaGVhZC5qc29uIgo="
+36questionsthepodcastmusical TXT "owner=1MwPD6dH4fE3gQ9mCov81L1DEQWT7E85qH" "seqn=0" "parts=1" "zf0=JE9SSUdJTiAzNnF1ZXN0aW9uc3RoZXBvZGNhc3RtdXNpY2FsCiRUVEwgMzYwMApfaHR0cC5fdGNwIFVSSSAxMCAxICJodHRwczovL3BoLmRvdHBvZGNhc3QuY28vMzZxdWVzdGlvbnN0aGVwb2RjYXN0bXVzaWNhbC9oZWFkLmpzb24iCg=="
+_http._tcp URI 10 1 "https://dotpodcast.co/"
+```
+
+Each `TXT` record in this zone file encodes a subdomain-creation. For example, `1yeardaily.verified.podcast` resolves to:
+
+```json
+{
+ "address": "1MwPD6dH4fE3gQ9mCov81L1DEQWT7E85qH",
+ "blockchain": "bitcoin",
+ "last_txid": "d87a22ebab3455b7399bfef8a41791935f94bc97aee55967edd5a87f22cce339",
+ "status": "registered_subdomain",
+ "zonefile_hash": "e7acc97fd42c48ed94fd4d41f674eddbee5557e3",
+ "zonefile_txt": "$ORIGIN 1yeardaily\n$TTL 3600\n_http._tcp URI 10 1 \"https://ph.dotpodcast.co/1yeardaily/head.json\"\n"
+}
+```
+
+This information was extracted from the `1yeardaily` `TXT` resource record in the zone file for `verified.podcast`.
+
+Subdomain lifecycle
+
+{% stepper %}
+{% step %}
+**Creation**
+
+A subdomain-creation operation is created by the subdomain owner and encoded into a `TXT` record in an on-chain name owner's zone file. The on-chain name owner broadcasts the zone file by issuing a `NAME_UPDATE` transaction, which anchors the subdomain-creation on-chain.
+{% endstep %}
+
+{% step %}
+**Update**
+
+Subdomain updates are done off-chain by creating signed operations from the subdomain owner's private key. Any on-chain name owner can include these signed operations in their zone file and broadcast via `NAME_UPDATE`. Operations are ordered by a sequence number and require a valid signature that links to the previous operation's public key.
+{% endstep %}
+
+{% step %}
+**Transfer**
+
+To change the address (public key hash) owning a subdomain, the subdomain owner signs a subdomain-transfer operation and asks an on-chain name owner (typically the one who created the subdomain) to broadcast it via `NAME_UPDATE`. The broadcasting on-chain name owner's zone file must be present in the Atlas network to prove absence of conflicting operations.
+{% endstep %}
+{% endstepper %}
+
+Sequence and validation rules
+
+* Subdomain operations are ordered by sequence number, starting at 0. Each new operation must include:
+ * The next sequence number
+ * The public key that hashes to the previous subdomain transaction's address
+ * A signature from the corresponding private key over the entire subdomain operation
+* If two correctly signed but conflicting operations have the same sequence number, the one earlier in blockchain history is accepted. Invalid operations are ignored.
+
+Subdomain creation and management rules
+
+* A subdomain-creation transaction can only be processed by the owner of the on-chain name that shares its suffix (e.g., only the owner of `res_publica.id` can broadcast creations for `*.res_publica.id`).
+* A subdomain-transfer transaction can only be broadcast by the owner of the on-chain name that created it.
+* To send a subdomain-creation or subdomain-transfer, all of an on-chain name owner's zone files must be present in the Atlas network. This allows proving the absence of conflicting operations.
+* A subdomain update can be broadcast by any on-chain name owner, but the subdomain owner needs to find a cooperating on-chain name owner to include and broadcast it.
+
+To create a subdomain, the subdomain owner generates the creation operation and gives it to the on-chain name owner. Once created, the subdomain owner can use any on-chain name owner to broadcast updates by providing signed operations packaged into zone files.
+
+Subdomain registrars
+
+Because subdomain names are cheap, developers may run subdomain registrars for their applications. For example, the name `personal.id` is used to register usernames without requiring users to spend Bitcoin.
+
+A reference implementation is available: https://github.com/stacks-network/subdomain-registrar. Users still own their subdomain names; the registrar helps developers broadcast subdomain operations.
+
+### BNS and DID Standards
+
+BNS names are compliant with the emerging Decentralized Identity Foundation (DIF) protocol specification for decentralized identifiers (DIDs): http://identity.foundation
+
+Each name in BNS has an associated DID. The DID format for BNS is:
+
+```bash
+did:stack:v0:{address}-{index}
+```
+
+Where:
+
+* `{address}` is an on-chain public key hash (for example a Bitcoin address).
+* `{index}` refers to the `nth` name this address created.
+
+Examples:
+
+* `personal.id` → `did:stack:v0:1dARRtzHPAFRNE7Yup2Md9w18XEQAtLiV-0` (first name created by that address)
+* `jude.id` → `did:stack:v0:16EMaNw3pkn3v6f2BgnSSs53zAKH4Q8YJg-1` (the address had created one earlier name before this one)
+
+Purpose: a DID provides an eternal identifier for a public key. The public key may change, but the DID will not.
+
+For a DID to be resolvable, all of the following must be true for a name:
+
+* The name must exist
+* The name's zone file hash must be the hash of a well-formed DNS zone file
+* The DNS zone file must be present in the Stacks node's data
+* The DNS zone file must contain a `URI` resource record that points to a signed JSON Web Token
+* The public key that signed the JSON Web Token (and is included with it) must hash to the address that owns the name
+
+Not all names will have DIDs that resolve to public keys. Names created by standard tooling will have DIDs that do.
+
+A RESTful API is under development.
+
+### DID Encoding for Subdomains
+
+Every name and subdomain in BNS has a DID. Encoding differs so software can determine which code-path to take.
+
+* For on-chain BNS names, the `{address}` is the same as the Bitcoin address that owns the name. Currently, both version byte 0 and version byte 5 addresses are supported (addresses starting with `1` or `3`, meaning `p2pkh` and `p2sh` addresses).
+* For off-chain BNS subdomains, the `{address}` has version byte 63 for subdomains owned by a single private key, and version byte 50 for subdomains owned by an m-of-n set of private keys. That is, subdomain DID addresses start with `S` or `M`, respectively.
+
+The `{index}` field for a subdomain's DID is distinct from the `{index}` field for a BNS name's DID, even if the same address created both names and subdomains. Example:
+
+* The name `abcdefgh123456.id` → `did:stack:v0:16EMaNw3pkn3v6f2BgnSSs53zAKH4Q8YJg-0` (first name created by that address)
+* The subdomain `jude.statism.id` created by the same address → `did:stack:v0:SSXMcDiCZ7yFSQSUj7mWzmDcdwYhq97p2i-0`
+
+Note: The address `SSXMcDiCZ7yFSQSUj7mWzmDcdwYhq97p2i` encodes the same public key hash as `16EMaNw3pkn3v6f2BgnSSs53zAKH4Q8YJg`—the difference is base58check version byte (63 vs 0).
diff --git a/docs/learn/network-fundamentals/mainnet-and-testnets.md b/docs/learn/network-fundamentals/mainnet-and-testnets.md
new file mode 100644
index 0000000000..66e8ecdcec
--- /dev/null
+++ b/docs/learn/network-fundamentals/mainnet-and-testnets.md
@@ -0,0 +1,45 @@
+# Mainnet and Testnets
+
+image source: Hiro blog
+
+Stacks has both a mainnet and a testnet for different purposes. Mainnet and testnet are two completely different networks and tokens cannot be transferred between one or the other.
+
+### Mainnet
+
+Stacks mainnet is directly connected to the Bitcoin mainnet and its the network where tokens have actual monetary worth. This is the production network and should be treated as such.
+
+You can view mainnet activity using the official [Stacks explorer](https://explorer.hiro.so/).
+
+### Testnet
+
+The Stacks testnet serves as a live public sandbox for developers, allowing them to build, test, and iterate on apps and smart contracts in an environment that mimics the mainnet. It provides a risk-free space to experiment with changes or new features before deploying them on the Stacks mainnet, ensuring that everything functions correctly without the risk of real financial loss.
+
+You can view testnet activity using the official [Stacks explorer](https://explorer.hiro.so/?chain=testnet).
+
+#### Testnet Faucets
+
+Testnet faucets provide you with mock Stacks (STX) tokens to test with. These testnet STX have no value and are not the same as STX on mainnet. There are a couple of different options for getting testnet STX.
+
+{% tabs %}
+{% tab title="Hiro" %}
+You can get testnet STX from the [Hiro Platform](https://platform.hiro.so/faucet), which is the recommended way.
+
+To get STX tokens from within the Hiro Platform, navigate to the "Faucet" tab at the top. You can then choose either testnet STX or sBTC, and then paste in your desired testnet STX address to receive.
+
+
+{% endtab %}
+
+{% tab title="Sandbox" %}
+Using the faucet provided by the [Explorer Sandbox](https://explorer.hiro.so/sandbox/deploy?chain=testnet) is another option.
+
+You'll first need to connect your wallet to the Explorer Sandbox and hit 'Request STX'. Be sure your wallet is on the testnet network before requesting.
+
+
+{% endtab %}
+
+{% tab title="LearnWeb3" %}
+Alternatively, you can use the [LearnWeb3 faucet](https://learnweb3.io/faucets).
+
+
+{% endtab %}
+{% endtabs %}
diff --git a/docs/learn/network-fundamentals/network-basics.md b/docs/learn/network-fundamentals/network-basics.md
new file mode 100644
index 0000000000..c419ab54ef
--- /dev/null
+++ b/docs/learn/network-fundamentals/network-basics.md
@@ -0,0 +1,97 @@
+# Network Basics
+
+image source: Hiro blog
+
+### Tokens
+
+Stacks (STX) tokens are the native tokens on the Stacks blockchain. The smallest fraction is one micro-STX. 1,000,000 micro-STX make one Stacks (STX).
+
+STX amounts should be stored as integers (8 bytes long), and represent the amount of micro-STX.
+
+### Fees
+
+Fees are used to incentivize miners to confirm transactions on the Stacks blockchain. The fee is calculated based on the estimate fee rate and the size of the raw transaction in bytes. The fee rate is a market determined variable. For the testnet, it is set to 1 micro-STX.
+
+Fee estimates can obtained through the [`GET /v2/fees/transfer`](https://docs.hiro.so/api#operation/get_fee_transfer) endpoint of the API.
+
+{% hint style="info" %}
+Note that this example uses an external tool, [Hiro's Stacks API](https://www.hiro.so/stacks-api). You can also use the native [Stacks API ](https://app.gitbook.com/u/ZrQItu6D9bMKmf1HfsLTnGc05WZ2)if you would rather run your own node or connect to one.
+{% endhint %}
+
+{% code title="terminal" %}
+```bash
+# for mainnet, replace `testnet` with `mainnet`
+curl 'https://api.testnet.hiro.so/v2/fees/transfer'
+```
+{% endcode %}
+
+The API will respond with the fee rate (as integer):
+
+```json
+1
+```
+
+[The Stacks Transactions JS library](https://github.com/stx-labs/stacks.js/tree/master/packages/transactions) supports fee estimation for:
+
+* token transfers (`estimateTransfer`)
+* contract deploys (`estimateContractDeploy`)
+* non read-only contract calls (`estimateContractFunctionCall`)
+
+{% hint style="info" %}
+For an implementation using a different language than JavaScript, please review [this reference implementation](https://github.com/stx-labs/stacks.js/blob/master/packages/transactions/src/builders.ts#L97).
+{% endhint %}
+
+### Nonces
+
+Every account carries a [nonce property](https://en.wikipedia.org/wiki/Cryptographic_nonce) that indicates the number of transactions processed for the given account. Nonces are one-time codes, starting at `0` for new accounts, and incremented by 1 on every transaction.
+
+Nonces are added to all transactions and help identify them in order to ensure transactions are processed in order and to avoid duplicated processing.
+
+{% hint style="info" %}
+The consensus mechanism also ensures that transactions aren't "replayed" in two ways. First, nodes query its unspent transaction outputs (UTXOs) in order to satisfy their spending conditions in a new transaction. Second, messages sent between nodes review sequence numbers.
+{% endhint %}
+
+When a new token transfer transaction is constructed, the most recent nonce of the account needs to be fetched and set.
+
+{% hint style="info" %}
+The API provides an endpoint to [simplify nonce handling](https://docs.hiro.so/get-started/stacks-blockchain-api#nonce-handling).
+{% endhint %}
+
+### Querying
+
+Stacks network details can be queried using the [Stacks Blockchain API](https://docs.hiro.so/get-started/stacks-blockchain-api).
+
+#### Health check
+
+The [status checker](https://status.stacks.org/) is a service that provides a user interface to quickly review the health of the Stacks blockchain.
+
+#### Network info
+
+The network information can be obtained using the [`GET /v2/info`](https://docs.hiro.so/api#operation/get_core_api_info) endpoint:
+
+{% code title="curl (testnet)" %}
+```bash
+# for mainnet, replace `testnet` with `mainnet`
+curl 'https://api.testnet.hiro.so/v2/info'
+```
+{% endcode %}
+
+Sample response:
+
+```js
+{
+ "peer_version": 385875968,
+ "burn_consensus": "826401d65cf3671210a3fb135d827d549c0b4d37",
+ "burn_block_height": 1972,
+ "stable_burn_consensus": "e27ea23f199076bc41a729d76a813e125b725f64",
+ "stable_burn_block_height": 1971,
+ "server_version": "blockstack-core 0.0.1 => 23.0.0.0 (master:bdd042242+, release build, linux [x86_64]",
+ "network_id": 2147483648,
+ "parent_network_id": 3669344250,
+ "stacks_tip_height": 933,
+ "stacks_tip": "1f601823fbcc5b6b2215b2ff59d2818fba61ee4a3cea426d8bc3dbb268005d8f",
+ "stacks_tip_burn_block": "54c56a9685545c45accf42b5dcb2787c97eda8185a1c794daf9b5a59d4807abc",
+ "unanchored_tip": "71948ee211dac3b241eb65d881637f649d0d49ac08ee4a41c29217d3026d7aae",
+ "exit_at_block_height": 28160
+}
+```
diff --git a/docs/learn/network-fundamentals/sips.md b/docs/learn/network-fundamentals/sips.md
new file mode 100644
index 0000000000..cba8ae7098
--- /dev/null
+++ b/docs/learn/network-fundamentals/sips.md
@@ -0,0 +1,56 @@
+# SIPs
+
+source: Hiro blog
+
+### Stacks Improvement Proposals (SIPs)
+
+Stacks improvement proposals (SIPs) are aimed at describing the implementation of the Stacks blockchain, as well as proposing improvements.
+
+The SIP process [(SIP-000)](https://github.com/stacksgov/sips/blob/main/sips/sip-000/sip-000-stacks-improvement-proposal-process.md) describes how to make a SIP and get it ratified.
+
+They should contain concise technical specifications of features or standards and the rationale behind it. SIPs are intended to be the primary medium for proposing new features, for collecting community input on a system-wide issue, and for documenting design decisions.
+
+The SIPs are located in the [stacksgov/sips](https://github.com/stacksgov/sips) repository as part of the [Stacks Community Governance organization](https://github.com/stacksgov).
+
+Anyone in the Stacks community can submit a SIP.
+
+{% hint style="info" %}
+Stacks Improvement Proposals Community Calls Add the [weekly community SIP call](https://www.addevent.com/event/wS15955379) to your calendar.
+
+SIP Meeting calls are recorded and available [here](https://www.youtube.com/playlist?list=PLg717Ri_rTnx5kuaWqp3cUAtwQk_yzslT)
+
+More details of the meetings are available [here](https://github.com/stacksgov/sips/issues/79)
+{% endhint %}
+
+### Ratified SIPSs
+
+* [x] [SIP 000: Improvement Proposal Process](https://github.com/stacksgov/sips/blob/main/sips/sip-000/sip-000-stacks-improvement-proposal-process.md)
+* [x] [SIP 001: Burn Election](https://github.com/stacksgov/sips/blob/main/sips/sip-001/sip-001-burn-election.md)
+* [x] [SIP 002: Clarity, a language for predictable smart contracts](https://github.com/stacksgov/sips/blob/main/sips/sip-002/sip-002-smart-contract-language.md)
+* [x] [SIP 003: Peer Network](https://github.com/stacksgov/sips/blob/main/sips/sip-003/sip-003-peer-network.md)
+* [x] [SIP 004: Cryptographic Commitment to Materialized Views](https://github.com/stacksgov/sips/blob/main/sips/sip-004/sip-004-materialized-view.md)
+* [x] [SIP 005: Blocks, Transactions, and Accounts](https://github.com/stacksgov/sips/blob/main/sips/sip-005/sip-005-blocks-and-transactions.md)
+* [x] [SIP 006: Clarity Execution Cost Assessment](https://github.com/stacksgov/sips/blob/main/sips/sip-006/sip-006-runtime-cost-assessment.md)
+* [x] [SIP 007: Stacking Consensus](https://github.com/stacksgov/sips/blob/main/sips/sip-007/sip-007-stacking-consensus.md)
+* [x] [SIP 008: Clarity Parsing and Analysis Cost Assessment](https://github.com/stacksgov/sips/blob/main/sips/sip-008/sip-008-analysis-cost-assessment.md)
+* [x] [SIP 009: Standard Trait Definition for Non-Fungible Tokens](https://github.com/stacksgov/sips/blob/main/sips/sip-009/sip-009-nft-standard.md)
+* [x] [SIP 010: Standard Trait Definition for Fungible Tokens](https://github.com/stacksgov/sips/blob/main/sips/sip-010/sip-010-fungible-token-standard.md)
+* [x] [SIP 012: Burn Height Selection for a Network Upgrade to Introduce New Cost-Limits](https://github.com/stacksgov/sips/blob/main/sips/sip-012/sip-012-cost-limits-network-upgrade.md)
+* [x] [SIP 013: Standard Trait Definition for Semi-Fungible Tokens](https://github.com/stacksgov/sips/blob/main/sips/sip-013/sip-013-semi-fungible-token-standard.md)
+* [x] [SIP-015: Stacks Upgrade of Proof-of-Transfer and Clarity](https://github.com/stacksgov/sips/blob/main/sips/sip-015/sip-015-network-upgrade.md)
+* [x] [SIP-016: Metadata for Tokens](https://github.com/stacksgov/sips/blob/main/sips/sip-016/sip-016-token-metadata.md)
+* [x] [SIP-018: Signed Structured Data](https://github.com/stacksgov/sips/blob/main/sips/sip-018/sip-018-signed-structured-data.md)
+* [x] [SIP-019: Notifications for Token Metadata Updates](https://github.com/stacksgov/sips/blob/main/sips/sip-019/sip-019-token-metadata-update-notifications.md)
+* [x] [SIP-020: Bitwise Operations in Clarity](https://github.com/stacksgov/sips/blob/main/sips/sip-020/sip-020-bitwise-ops.md)
+* [x] [SIP-022: Emergency Fix to PoX Stacking Increases](https://github.com/stacksgov/sips/blob/main/sips/sip-022/sip-022-emergency-pox-fix.md)
+* [x] [SIP-023: Emergency Fix to Trait Invocation Behavior](https://github.com/stacksgov/sips/blob/main/sips/sip-023/sip-023-emergency-fix-traits.md)
+* [x] [SIP-024: Emergency Fix to Data Validation and Serialization Behavior](https://github.com/stacksgov/sips/blob/main/sips/sip-024/sip-024-least-supertype-fix.md)
+
+### How to Get Involved
+
+There are several ways you can get involved with the SIP process:
+
+* **Join the weekly SIP Meeting call** listed [here](https://community.stacks.org/events).
+* **SIP Editor**. SIP editors help SIP authors make sure their SIPs are well-formed and follow the right process. They help get SIPs ready for deep review by advancing it them from Draft to Accepted status. If you want to become a SIP editor, open an issue with your name and email to ask to be added to the list of SIP editors.
+* **Join a CAB** (Consideration Advisory Board). SIPs fall under the purview of one or more considerations. A full list is in [this github](https://github.com/stacksgov/sips/tree/main/considerations) directory. Currently they are: Diversity, Economics, Ethics, Governance and Technical. Members of SIP consideration advisory boards use their domain expertise to give Accepted SIPs a deep read, and give the authors any/all feedback to help make the SIP workable. If you want to join a board, reach out to the board's chairperson via the listed contact information.
+* **Steering Committee**. The Steering Committee organizes the consideration advisory boards and votes to advance Recommended SIPs to Activation-in-Progress status, and then to either Ratified or Rejected status. Once they are in the process of being activated, they use a SIP's Activation section to determine whether or not the Stacks ecosystem has ratified or rejected the SIP. Joining this committee requires the consent of the Stacks Foundation board.
diff --git a/docs/learn/network-fundamentals/technical-specifications/README.md b/docs/learn/network-fundamentals/technical-specifications/README.md
new file mode 100644
index 0000000000..79cd50fdf7
--- /dev/null
+++ b/docs/learn/network-fundamentals/technical-specifications/README.md
@@ -0,0 +1,95 @@
+# Technical Specifications
+
+### Consensus
+
+* Proof of Transfer (PoX) as described in [SIP-007](https://github.com/stacksgov/sips/blob/main/sips/sip-007/sip-007-stacking-consensus.md)
+* Network will transition to Proof of Burn (PoB) as described in [SIP-001](https://github.com/stacksgov/sips/blob/main/sips/sip-001/sip-001-burn-election.md) after 10 years. [Learn more about Proof-of-Burn in SIP-001](https://github.com/stacksgov/sips/blob/main/sips/sip-001/sip-001-burn-election.md).
+* Threat model
+ * 51% of malicious Bitcoin mining power can reorg the Stacks chain or perform a double-spend attack
+ * Chain can halt if Stackers cannot meet 70% consensus on block validity
+* Different actors and their roles
+ * Stacks Miners package transactions into blocks and propose them to stackers
+ * Stacks Holders may alter the calculation of block limits (subject to a miner veto) and may vote to disable Proof-of-Transfer rewards for a reward cycle.
+ * Stackers validate and append blocks to the chain and validate sBTC deposit and withdrawal transactions
+
+### Proof of Transfer Mining
+
+* Coinbase reward schedule:
+ * 1000 STX/block for first 4 years
+ * 500 STX/block for following 4 years
+ * 250 STX/block for subsequent 4 years
+ * 125 STX/block in perpetuity after that
+* Coinbase rewards accumulate for "missed sortitions": If a Bitcoin block has no sortition (at height N), then any Stacks block mined in a subsequent sortition that builds off of any Stacks chain tip that existed at the penultimate sortition (at height N-1) may claim its coinbase. This encourages miners to keep mining even if Bitcoin fees are high.
+* Initial mining bonus: This is a special case of the above to incentivize early miners. Coinbase for all burnchain blocks between the first burn block height (to be chosen by independent miners as part of the Stacks 2.0 launch) and the first sortition winner accumulate and are distributed to miners over a fixed window (to be determined). For instance, say burn block height is 10,000 and first sortition is at block 10500 and distribution window is 100 blocks, then coinbase for the first 500 blocks (10,500 - 10,000) will be distributed evenly to miners who win sortition over the subsequent 100 blocks.
+* Reward maturity window: 100 blocks, meaning leaders will earn the coinbase reward 100 blocks after the block they successfully mine.
+* Block interval: Stacks blockchain produces fast blocks roughly every 10 seconds with a miner tenure change occurring every Bitcoin block
+* BTC commitment: Miners must commit at least 11,000 satoshis (5,500 sats / [UTXO output](https://learnmeabitcoin.com/technical/utxo)); 2 outputs / block) to avoid "dust."
+* For more details, see Block Production.
+
+### Stacking
+
+{% stepper %}
+{% step %}
+#### Prepare phase
+
+An "anchor block" is chosen. The qualifying set of addresses ("reward set") is determined based on the snapshot of the chain at the anchor block. Length of prepare phase is 100 blocks. Stacking commitments need to be confirmed before this phase starts.
+{% endstep %}
+
+{% step %}
+#### Reward phase
+
+Miner BTC commitments are distributed amongst the reward set. Reward cycle length is 2000 BTC blocks (\~2 weeks).
+{% endstep %}
+{% endstepper %}
+
+* Two reward addresses / block, for a total of 4000 addresses every reward cycle. The addresses are chosen using a VRF (verifiable random function), so each node can deterministically arrive at the same reward addresses for a given block.
+* Stacking threshold: 0.025% of the participating amount of STX when participation is between 25% and 100% and when participation is below 25%, the threshold level is always 0.00625 of the liquid supply of STX.
+* Delegation: An STX address can designate another address to participate in Stacking on its behalf. [Relevant section in SIP-007](https://github.com/stacksgov/sips/blob/main/sips/sip-007/sip-007-stacking-consensus.md#stacker-delegation).
+* Pooling: STX holders that individually do not meet the Stacking threshold can pool together their holdings to participate in Stacking. To do this, STX holders must set the (optional) reward address to the "delegate address." For more details, see [this reference](https://docs.stacks.co/references/stacking-contract#delegate-stx).
+* Legacy, SegWit, Native Segwit, and Taproot addresses are supported
+
+### Accounts and Addresses
+
+* Transactions in the Stacks blockchain originate from, are paid for by, and execute under the authority of accounts
+* An account is fully specified by its address + nonce + assets
+* Address contains 2 or 3 fields: 1 byte version, 20 byte public key hash (RIPEMD160(SHA256(input))), optional name (variable length, max 128 bytes)
+* Two types of accounts: standard accounts are owned by one or more private keys; contract accounts are materialized when a smart-contract is instantiated (specified by the optional name field above)
+* Nonce counts number of times an account has authorized a transaction. Starts at 0, valid authorization must include the _next_ nonce value.
+* Assets are a map of all asset types -- STX, any on-chain assets specified by a Clarity contract (for example NFTs) -- to quantities owned by that account.
+* Accounts need not be explicit "created" or registered; all accounts implicitly exist and are instantiated on first-use.
+
+### Transactions
+
+* Transaction types: coinbase, token-transfer, contract-deploy, contract-call, tenure-change.
+* Only standard accounts (not contracts) can pay transaction fees.
+* Transaction execution is governed by:
+
+{% stepper %}
+{% step %}
+#### Originating account
+
+The account that creates, authorizes and sends the transaction.
+{% endstep %}
+
+{% step %}
+#### Paying account
+
+The account that is billed by the leader for the cost of validating and executing the transaction.
+{% endstep %}
+
+{% step %}
+#### Sending account
+
+The account that identifies who is currently executing the transaction: this can change as a transaction executes via the `as-contract` Clarity function.
+{% endstep %}
+{% endstepper %}
+
+* Transactions can be batched or streamed into blocks. The behavior can be controlled by the anchor mode of a transaction. With streaming (microblocks), a faster confirmation time is possible.
+* Two types of authorizations: standard authorization is where originating account is the same as paying account. _Sponsored_ authorization is where originating account and paying account are distinct. For instance, developers or service providers could pay for users to call their smart-contracts.
+* For sponsored authorization, first a user signs with the originating account and then a sponsor signs with the paying account.
+* Mempool limit for concurrent pending transactions is 25 per account
+* Pending mempool transactions will be garbage-collected [256 blocks after receipt](https://github.com/stacks-network/stacks-blockchain/blob/master/src/core/mempool.rs#L62). With 10 minutes target block time, this would equal \~42 hours
+* [Learn more about transaction encoding in SIP-005](https://github.com/stacksgov/sips/blob/main/sips/sip-005/sip-005-blocks-and-transactions.md#transaction-encoding)
+* [Transaction signing and verification are described in SIP-005](https://github.com/stacksgov/sips/blob/main/sips/sip-005/sip-005-blocks-and-transactions.md#transaction-signing-and-verifying)
+* All transactions impacting account balance are atomic, a transfer operation can not increment one account’s balance without decrementing another’s. However, transactions that perform multiple account actions (for example, transferring from multiple accounts) may partially complete.
+* Transactions can include a memo string (max 34 bytes)
diff --git a/docs/learn/network-fundamentals/technical-specifications/audits.md b/docs/learn/network-fundamentals/technical-specifications/audits.md
new file mode 100644
index 0000000000..7e6b4478d6
--- /dev/null
+++ b/docs/learn/network-fundamentals/technical-specifications/audits.md
@@ -0,0 +1,47 @@
+# Audits
+
+source: Hiro blog
+
+#### Audits are just part of the story
+
+For any project, layers of security are crucial. Audits represent one layer, while core developers and contributors collaborate to provide many more. Notable security programs, designs, and partners beyond audits include:
+
+* Embedded security researchers [via Asymmetric Research](https://stacks.org/asymmetric-joins-stacks-ecosystem)
+* Attackathon programs in partnership with Immunefi
+* sBTC’s decentralized [network of validators/signers](https://www.stacks.co/sbtc) (removing the need to entrust a single entity and mitigating counterparty risk)
+* Stacks’ underlying design that offers 100% Bitcoin finality, securing sBTC at the consensus level of a $2.5 billion network.
+* Support at the app layer via [Hypernative](https://hackernoon.com/hypernative-bolsters-bitcoin-l2-security-as-stacks-ecosystem-gets-real-time-protection)
+* Bitcoin L2 Labs' [whitehat security program](https://bitcoinl2-labs.github.io/2024/06/04/orange-hats.html)
+* Stacks Foundation's partnership with Staking Defense League
+* Stacks Founation's ongoing [Immunefi bug bounty program](https://immunefi.com/bug-bounty/stacks/information/)
+* Dedicated Stacks Foundation Residents focused exclusively on fuzz and penetration testing (created [Rendezvous](https://stacks-network.github.io/rendezvous/))
+
+{% hint style="warning" %}
+_All 'high' or 'critical' issues listed in audits have either been mitigated or otherwise made obsolete, even if the report states otherwise._
+{% endhint %}
+
+#### Stacks Core
+
+Audits on Stacks Core
+
+{% file src="../../.gitbook/assets/Quantstamp - Network State Machine.pdf" %}
+
+{% file src="../../.gitbook/assets/CoinFabrik - Stacks Signer Audit.pdf" %}
+
+{% file src="../../.gitbook/assets/Coinfabrik - Stacks PoX.pdf" %}
+
+{% file src="../../.gitbook/assets/CoinFabrik - Stacks LibSigner.pdf" %}
+
+{% file src="../../.gitbook/assets/CoinFabrik - StackerDB.pdf" %}
+
+{% file src="../../.gitbook/assets/CoinFabrik - Signer Binary.pdf" %}
+
+#### Other audits
+
+{% file src="../../.gitbook/assets/NCC_Group_Stacks_Wallet_Report_2020-11-17_v1.0.pdf" %}
+
+{% file src="../../.gitbook/assets/NCC_Group_Stacks_Blockchain_Audit_Report_2020-11-23_v1.0.pdf" %}
+
+{% file src="../../.gitbook/assets/Blockstack_Desktop_Wallet_Pentest_Report_11-12-2020.pdf" %}
+
+Trail of Bits Report, Stacks Blockchain (No PDF, [Github Issues List provided](https://github.com/diwakergupta/stacks-blockchain-tob-audit/issues))
diff --git a/docs/learn/network-fundamentals/wallets-and-accounts.md b/docs/learn/network-fundamentals/wallets-and-accounts.md
new file mode 100644
index 0000000000..47031ef667
--- /dev/null
+++ b/docs/learn/network-fundamentals/wallets-and-accounts.md
@@ -0,0 +1,160 @@
+# Wallets & Accounts
+
+
+
+{% hint style="info" %}
+For the technical breakdown and standard for how wallets/accounts are generated in Stacks, check out [**SIP-005 standard**](https://github.com/stacksgov/sips/blob/main/sips/sip-005/sip-005-blocks-and-transactions.md) that outlines all of this.
+{% endhint %}
+
+### Introduction
+
+Stacks wallets are software or hardware tools for storing cryptocurrencies, NFTs, and other digital assets. They are also used for establishing on-chain identity in decentralized applications (dApps). These wallets cryptographically store and manage each user’s identity and funds through a single blockchain address, which leverage public-key cryptography.
+
+#### Purpose of a Stacks wallet
+
+* Establish User Identity
+* Store Assets
+* Display Balances
+* Sign Transactions
+* Sign Messages
+* Participate in the Bitcoin Economy
+
+Wallets in Stacks consists of accounts, which uses an accounts-based model, rather than a UTXO model like Bitcoin. This model is simpler than the UTXO model and has a more traditional concept of “balance”, similar to what you would encounter at a bank. In this model, each address has a single “balance” figure for a given token that increases/decreases as transactions are sent to/from that account. This is what most Web3 ecosystems use. In a UTXO model, the network operates as a ledger, with each UTXO being analogous to a cash bill.
+
+#### Components of a Stacks account
+
+* **Private Key** - The private key is an alphanumeric code that is paired to a single public key on a 1:1 basis. Never share your private key with anyone. A private key is how you prove ownership of a public key and how you can spend assets held by that particular key-pair.\
+ \
+ Example private key in Stacks (32 bytes appended with a 0x01 byte):\
+ `5a4133fec2cf923d37238d3ba2fcd2ee9c8dce882c22218fd210d8a02ceb2c7401`
+* **Public Key** - The public key is derived mathematically from the private key. It can be shared safely and is used by the network to verify signatures created by the private key, without revealing the private key itself.\
+ \
+ Example public key in Stacks (compressed format):\
+ `02e8eb87862945d369511fdcce326ffef9a01b68c7d070e3ce685a5cbb9b1ecfc5`
+* **Address (Principal)** - The address is a shorter, user-friendly representation derived from the public key. It’s what you share to receive sBTC, STX, tokens, or NFTs on Stacks, and it acts as the on-chain identifier for the user.\
+ \
+ Example public address in Stacks (c32check encoding):\
+ `SPM9G3CNGSCTB4956290NESM0MR9W9CCEPVEPSQC`
+
+{% hint style="info" %}
+The private/public key generation uses the cryptographic **secp256k1** curve.
+
+The cryptographic signature algorithm used in Stacks is **ECDSA** over **secp256k1**.
+{% endhint %}
+
+Stacks accounts are entities that own assets, like Stacks (STX) tokens. An account has an address, private key, nonce, and one or more asset balances. Assets cannot leave an account without an action from the account owner. All changes to assets (and the balances of the account) require a corresponding transaction.
+
+All Stacks wallets also support Bitcoin addresses, enabling seamless participation across both the Stacks and Bitcoin ecosystems.
+
+***
+
+### Creation
+
+An wallet's accounts are generated from a 24-word mnemonic phrase conforming to the BIP39 standard. This is often referred to as the **seed phrase**. The seed phrase provides access to Stacks accounts.
+
+{% hint style="danger" %}
+If the seed phrase is lost, access to the associated account cannot be restored. No person or organization can recover a lost seed phrase.
+{% endhint %}
+
+The easiest way to generate a new Stacks account is to use the [Stacks CLI](https://github.com/stx-labs/stacks.js/tree/master/packages/cli):
+
+{% code title="Generate a new account (CLI)" %}
+```bash
+# install CLI globally
+npm install --global @stacks/cli
+
+# generate a new account and store details in a new file
+
+# '-t' option makes this a testnet account
+stx make_keychain -t > cli_keychain.json
+```
+{% endcode %}
+
+`make_keychain` creates the following file:
+
+```js
+{
+ "mnemonic": "aaa bbb ccc ddd ...",
+ "keyInfo": {
+ "privateKey": "5a3f1f15245bb3fb...",
+ "address": "STJRM2AMVF90ER6G3RW1QTF85E3HZH37006D5ER1",
+ "btcAddress": "biwSd6KTEvJcyX2R8oyfgj5REuLzczMYC1",
+ "wif": "L4HXn7PLmzoNW...",
+ "index": 0
+ }
+}
+```
+
+{% hint style="info" %}
+Check out the [Stacks CLI reference](https://docs.hiro.so/references/stacks-cli) for more details
+{% endhint %}
+
+| Field | Description |
+| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| `mnemonic` | A 24-word seed phrase used to access the account, generated using [BIP39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki) with 256 bits of entropy |
+| `keyInfo.privateKey` | Private key for the account. Required for token transfers and often referred to as `senderKey` |
+| `keyInfo.address` | Stacks address for the account |
+| `keyInfo.btcAddress` | Corresponding BTC address for the account. |
+| `keyInfo.wif` | Private key of the btcAddress in compressed format. |
+| `keyInfo.index` | Nonce for the account, starting at 0 |
+
+Note that a new account automatically exists for each new private key. There is no need to manually instantiate an account on the Stacks blockchain.
+
+{% hint style="info" %}
+Addresses are created by generating the [RIPEMD-160 hash](https://en.wikipedia.org/wiki/RIPEMD#RIPEMD-160_hashes) of the [SHA256](https://en.bitcoinwiki.org/wiki/SHA-256) of the public key. BTC addresses are encoded with [Base58Check](https://bitcoin.it/wiki/Base58Check_encoding). For Stacks addresses, [c32check](https://github.com/stacks-network/c32check) is used. Deriving an address from a public key can be done without internet access, for instance using the c32check `c32addressDecode` method.
+{% endhint %}
+
+Alternatively to the CLI creation, the [Stacks Transactions JS](https://github.com/stx-labs/stacks.js/tree/master/packages/transactions) library can be used:
+
+{% code title="Generate a private key & derive address (transactions library)" %}
+```js
+import {
+ makeRandomPrivKey,
+ privateKeyToString,
+ getAddressFromPrivateKey,
+ TransactionVersion,
+ getPublicKey,
+} from "@stacks/transactions";
+
+const privateKey = makeRandomPrivKey();
+
+// Get public key from private
+const publicKey = getPublicKey(privateKey);
+
+const stacksAddress = getAddressFromPrivateKey(
+ privateKeyToString(privateKey),
+ TransactionVersion.Testnet // remove for Mainnet addresses
+);
+```
+{% endcode %}
+
+Finally, you can generate new account using a Stacks-enabled wallet like [Leather](https://leather.io/), [Xverse](https://www.xverse.app/), or [Asigna](https://asigna.io/).
+
+***
+
+### Handling different formats
+
+It's common for new Stacks developers to get tripped up on the different ways when specifying Stacks' principals (aka addresses) in their development.
+
+Here's a breakdown of dealing with principals in 3 different use cases.
+
+
+
+***
+
+### The Stacks and Bitcoin address connection
+
+What makes Stacks beautifully connected to its L1 settlement layer, Bitcoin, is their many shared aspects. One being how both utilize a similar address generation scheme based on the P2PKH format, which allows for both a Bitcoin & Stacks address to share the same public key hash. If you base58check decode a legacy bitcoin address, you can reveal the public key hash, which can then be used to generate its respective c32check encoded Stacks address.
+
+Programmatically, you could also use a method called `b58ToC32`, from the `c32check` javascript library, which can abstract the conversion for you.
+
+
+
+***
+
+### Additional Resources
+
+* \[[Hiro Blog](https://www.hiro.so/blog/understanding-the-differences-between-bitcoin-address-formats-when-developing-your-app)] Understanding the Differences Between Bitcoin Address Formats When Developing Your App
+* \[[Hiro Blog](https://www.hiro.so/blog/how-every-stacks-address-has-a-corresponding-bitcoin-address)] How Every Stacks Address Has a Corresponding Bitcoin Address
+* \[[Hiro Blog](https://www.hiro.so/blog/an-intro-to-web3-wallets-for-web3-founders)] An Intro to Web3 Wallets for Web3 Founders
+* \[[Hiro Blog](https://www.hiro.so/blog/why-web3-needs-bitcoin-centric-wallet-standards)] Why Web3 Needs Bitcoin-Centric Wallet Standards
diff --git a/docs/learn/sbtc/README.md b/docs/learn/sbtc/README.md
new file mode 100644
index 0000000000..60a3c64318
--- /dev/null
+++ b/docs/learn/sbtc/README.md
@@ -0,0 +1,83 @@
+---
+description: Design of a Trustless Two-way Peg for Bitcoin
+---
+
+# sBTC
+
+
+
+{% hint style="info" %}
+For builders and developers, head to the [sBTC guides](https://app.gitbook.com/s/Zz9BLmTU9oydDpL3qiUh/more-guides/sbtc) under the Build section to start integrating sBTC into your Clarity smart contracts and front-end application.
+{% endhint %}
+
+### Introduction
+
+sBTC is a SIP-010 token on the Stacks blockchain that represents Bitcoin (BTC) in a 1:1 ratio. It enables Bitcoin holders to participate in DeFi applications and other smart contract functionalities while maintaining a peg to the underlying Bitcoin.
+
+#### Purpose
+
+The primary purpose of sBTC is to bridge Bitcoin to DeFi via the Stacks blockchain, providing Bitcoin holders with access to the rich functionality of smart contracts without sacrificing the security and value of their BTC holdings.
+
+> _Unlocking Bitcoin to be a fully programmable, productive asset would allow Bitcoin to be the_\
+> NAN;_backbone of DeFi and a more secure web3. The ability to move Bitcoin assets in and out of_\
+> NAN;_smart contracts freely and for these contracts to trustlessly write to the Bitcoin blockchain can_\
+> NAN;_unlock hundreds of billions of dollars of passive BTC for web3._\
+> \
+> \- sBTC: Design of a Trustless Two-way Peg for Bitcoin
+
+#### Key Benefits
+
+1. **Bitcoin Compatibility**: Allows Bitcoin holders to participate in the Stacks ecosystem without selling their BTC.
+2. **Quick Conversions**: Facilitates rapid movement between BTC and sBTC (within 3 Bitcoin blocks for deposit, 6 for withdrawal).
+3. **Decentralized Management**: Initially utilizes a set of 15 community-chosen signers for maintaining the peg wallet.
+4. **Community Governance**: Involves the community in key decisions, such as selecting the initial signing set.
+
+### Key Concepts
+
+Understanding sBTC requires familiarity with several key concepts:
+
+**sBTC**
+
+sBTC is a [SIP-010](https://github.com/stacksgov/sips/blob/main/sips/sip-010/sip-010-fungible-token-standard.md) token on the Stacks Blockchain that can be converted back to BTC on the Bitcoin Blockchain. The key property of sBTC is its 1:1 peg to Bitcoin, meaning 1 sBTC is always equivalent to 1 BTC.
+
+**sBTC UTXO**
+
+The sBTC UTXO is the single unspent transaction output (UTXO) on the Bitcoin blockchain that holds the entire BTC balance pegged into sBTC. This UTXO is managed and maintained by the set of sBTC Signers.
+
+This UTXO resides in a secure multi-signature taproot address controlled by the sBTC Signers:\
+[bc1prcs82tvrz70jk8u79uekwdfjhd0qhs2mva6e526arycu7fu25zsqhyztuy](https://mempool.space/address/bc1prcs82tvrz70jk8u79uekwdfjhd0qhs2mva6e526arycu7fu25zsqhyztuy)
+
+**sBTC Signer**
+
+In sBTC, the sBTC Signer is a signer entity separate from the Stacks Nakamoto signer. sBTC signer responsibilities include:
+
+* Signing sBTC operations
+* Communicating with the sBTC contracts on the Stacks chain
+* Managing the sBTC UTXO
+
+**sBTC Signer Set**
+
+The sBTC Signer Set is the group of all sBTC signers. This set has full democratic access to the sBTC UTXO and is responsible for maintaining the security of the peg wallet. The signers also have the ability to rotate their private keys for enhanced security.
+
+For more info on who the sBTC Signers are, check out this section on the Bitcoin L2 Labs website [here](https://bitcoinl2labs.com/sbtc-rollout#sbtc-signers).
+
+**Emily API**
+
+Emily is an API that helps facilitate and supervise the sBTC Bridge in addition to serving as a programmatic liaison between sBTC users and signers.
+
+**SIP-010 Token**
+
+sBTC adheres to the [SIP-010](https://github.com/stacksgov/sips/blob/main/sips/sip-010/sip-010-fungible-token-standard.md) standard for fungible tokens on the Stacks blockchain. This ensures compatibility with wallets and applications that support the SIP-010 standard.
+
+
+
+Understanding these concepts is crucial for grasping the overall architecture and functionality of sBTC. In the following sections, we'll explore how these concepts come together to create sBTC.
+
+***
+
+#### Additional Resources
+
+* \[[sBTC Whitepaper](https://stacks-network.github.io/stacks/sbtc.pdf)] The official sBTC whitepaper
+* \[[Stacks Foundation](https://stacks.org/sbtc-on-mainnet)] Official sBTC launch announcement (December 2024)
+* \[[Bitcoin Writes](https://www.bitcoinwrites.com/)] Weekly sBTC Updates (last update: August 2024)
+* \[[Hiro Blog](https://www.hiro.so/blog/who-are-the-sbtc-signers-breaking-down-sip-028)] Who Are the sBTC Signers: Breaking Down SIP-028
diff --git a/docs/learn/sbtc/auxiliary-features/README.md b/docs/learn/sbtc/auxiliary-features/README.md
new file mode 100644
index 0000000000..e795198e36
--- /dev/null
+++ b/docs/learn/sbtc/auxiliary-features/README.md
@@ -0,0 +1,17 @@
+# Auxiliary Features
+
+This section covers additional features that enhance the functionality and security of the sBTC system. These auxiliary features contribute to the overall robustness and user-friendliness of the sBTC ecosystem.
+
+{% stepper %}
+{% step %}
+#### Transaction Fee Sponsorship
+
+Allowing sBTC transactions to be sponsored.
+{% endstep %}
+
+{% step %}
+#### Signer Wallet Rotation
+
+Enabling secure key rotation for sBTC Signers.
+{% endstep %}
+{% endstepper %}
diff --git a/docs/learn/sbtc/auxiliary-features/signer-wallet-rotation.md b/docs/learn/sbtc/auxiliary-features/signer-wallet-rotation.md
new file mode 100644
index 0000000000..3d381e9a89
--- /dev/null
+++ b/docs/learn/sbtc/auxiliary-features/signer-wallet-rotation.md
@@ -0,0 +1,53 @@
+# Signer Wallet Rotation
+
+Signer wallet rotation allows sBTC signers to update their private keys and modify the signer set composition. This mechanism is how the network maintains security over time and adapts to changing participants.
+
+## How it works
+
+The sBTC system uses a multi-signature wallet on Bitcoin to custody BTC deposits. When the system needs to change who controls this wallet—either by rotating keys or changing the signer set—it uses the rotation mechanism.
+
+As of v1.1.0, the system supports:
+
+* Adding new signers to the set
+* Removing existing signers
+* Replacing specific signers
+* Rotating keys for current signers
+
+When signers agree on a new configuration, the system automatically runs a Distributed Key Generation (DKG) protocol to create new signing shares for the updated group. Once complete, control of the sBTC wallet transfers to the new configuration.
+
+## The rotation process
+
+{% stepper %}
+{% step %}
+#### Signers coordinate off-chain
+
+Signers agree on the new signer set.
+{% endstep %}
+
+{% step %}
+#### Update configuration
+
+Each signer operator updates their configuration with the newly decided set.
+{% endstep %}
+
+{% step %}
+#### DKG runs automatically
+
+Once all signers have configured the exact same set of signers, DKG occurs automatically to generate new signing shares.
+{% endstep %}
+
+{% step %}
+#### New signer set takes control
+
+The new signer set takes control of the sBTC wallet.
+{% endstep %}
+{% endstepper %}
+
+The Bitcoin UTXOs remain under continuous control throughout this process—there's no moment where funds are unsecured.
+
+## When rotation occurs
+
+Key rotation typically happens when:
+
+* **Signer changes**: When someone leaves the signer set or new participants join, the configuration must be updated to reflect the new membership.
+* **Security events**: If a key might be compromised, an emergency rotation can be initiated to secure the system.
diff --git a/docs/learn/sbtc/auxiliary-features/transaction-fee-sponsorship.md b/docs/learn/sbtc/auxiliary-features/transaction-fee-sponsorship.md
new file mode 100644
index 0000000000..70362e2aa4
--- /dev/null
+++ b/docs/learn/sbtc/auxiliary-features/transaction-fee-sponsorship.md
@@ -0,0 +1,56 @@
+# Transaction Fee Sponsorship
+
+Transaction Fee Sponsorship is a feature in sBTC that allows users to pay for Stacks transaction fees using sBTC instead of STX.
+
+## Overview
+
+* sBTC transactions on Stacks can be sponsored in return for some sBTC.
+* This feature improves user experience by allowing sBTC holders to use their tokens for gas fees.
+
+## Implementation
+
+The fee sponsorship system is implemented using the approach suggested in [stacks-network/stacks-core#4235](https://github.com/stacks-network/stacks-core/issues/4235).
+
+{% stepper %}
+{% step %}
+#### Sponsor support for fees
+
+sBTC users can get support from existing STX holders for transaction fees.
+{% endstep %}
+
+{% step %}
+#### Sponsor receives sBTC
+
+The sponsor pays the STX fee and receives sBTC in return.
+{% endstep %}
+{% endstepper %}
+
+## User Experience
+
+From a user's perspective:
+
+{% stepper %}
+{% step %}
+#### Opt into fee sponsorship
+
+When initiating an sBTC transaction, they can opt for fee sponsorship.
+{% endstep %}
+
+{% step %}
+#### Agree to sponsorship terms
+
+The user agrees to pay a small amount of sBTC for the sponsorship.
+{% endstep %}
+
+{% step %}
+#### Transaction processed
+
+The transaction is then processed with the fees paid in STX by the sponsor.
+{% endstep %}
+{% endstepper %}
+
+## Benefits
+
+* Improved UX: Users don't need to hold STX to use sBTC.
+* Lower Barrier to Entry: New users can start using sBTC without first acquiring STX.
+* Flexibility: Provides an additional option for handling transaction fees.
diff --git a/docs/learn/sbtc/clarity-contracts/README.md b/docs/learn/sbtc/clarity-contracts/README.md
new file mode 100644
index 0000000000..7df1ad6d36
--- /dev/null
+++ b/docs/learn/sbtc/clarity-contracts/README.md
@@ -0,0 +1,51 @@
+---
+description: The Clarity contracts responsible for sBTC's logic and interactions on Stacks.
+---
+
+# Clarity Contracts
+
+### Deployed Mainnet Contracts
+
+* [sbtc-token](https://explorer.hiro.so/txid/SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token?chain=mainnet)
+* [sbtc-registry](https://explorer.hiro.so/txid/SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-registry?chain=mainnet)
+* [sbtc-deposit](https://explorer.hiro.so/txid/SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-deposit?chain=mainnet)
+* [sbtc-withdrawal](https://explorer.hiro.so/txid/SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-withdrawal?chain=mainnet)
+* [sbtc-bootstrap-signers](https://explorer.hiro.so/txid/SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-bootstrap-signers?chain=mainnet)
+
+This graph summarizes the Clarity portion of the sBTC protocol.
+
+
+
+### sBTC Clarity Contracts
+
+At a high level, the sBTC Clarity contracts are responsible for the following:
+
+#### sbtc-bootstrap signers
+
+Core contract for meta signer functionality such as registration & the rotation process.
+
+#### sbtc-deposit
+
+Processing contract called by the signers to record a consumed Bitcoin transaction & mint some amount of sBTC to a principal contained in the payload.
+
+#### sbtc-registry
+
+State storage for maintaining upgradability across protocol.
+
+#### sbtc-withdrawal
+
+Interaction points for users and signers to update withdrawal request state.
+
+
+
+### User Types
+
+In addition to the contracts themselves, there are two main user types that will interact with these contracts.
+
+#### Signer
+
+A signer that is part of the current sBTC signer set. More information on signers and their role in sBTC can be found in the [Signer Process Walkthrough](../walkthroughs/signer-process-walkthrough.md).
+
+#### Wallet
+
+A participant in the Stacks/Bitcoin ecosystem that wants to deposit/withdraw/use sbtc.
diff --git a/docs/learn/sbtc/clarity-contracts/sbtc-bootstrap-signers.md b/docs/learn/sbtc/clarity-contracts/sbtc-bootstrap-signers.md
new file mode 100644
index 0000000000..a891e962c3
--- /dev/null
+++ b/docs/learn/sbtc/clarity-contracts/sbtc-bootstrap-signers.md
@@ -0,0 +1,89 @@
+---
+hidden: true
+---
+
+# sbtc bootstrap signers
+
+I can convert and optimize that page for GitBook — please paste the full page content (or provide the page URL) you want imported.
+
+If you don't have it ready, here are two quick options I can produce now to get started — tell me which you want or paste the content:
+
+1. Empty GitBook-ready markdown template for "sBTC Bootstrap Signers" you can fill in.
+2. Full conversion if you paste the original page content or URL.
+
+Template (choose 1 or paste content):
+
+***
+
+## sBTC Bootstrap Signers
+
+Short description: Briefly describe the purpose of this page and what a bootstrap signer is.
+
+### Signer list
+
+Provide signer identities, keys, and any relevant metadata here.
+
+* Signer name
+ * Public key:
+ * Contact:
+ * Notes:
+
+(Repeat for each signer)
+
+### Setup / Installation
+
+Use a stepper for multi-step setup instructions.
+
+{% stepper %}
+{% step %}
+#### Prepare environment
+
+Describe prerequisites and environment setup.
+{% endstep %}
+
+{% step %}
+#### Install dependencies
+
+Commands and configuration.
+{% endstep %}
+
+{% step %}
+#### Start the signer
+
+Service start commands, verification steps.
+{% endstep %}
+{% endstepper %}
+
+### Configuration examples
+
+Include config file examples and code blocks.
+
+{% code title="signer-config.toml" %}
+```toml
+# Example config
+[signer]
+key = "-----BEGIN PUBLIC KEY-----..."
+```
+{% endcode %}
+
+### Security and key handling
+
+Best practices for key generation, storage, and rotation.
+
+{% hint style="warning" %}
+Never share private keys. Use hardware security modules (HSMs) or secure enclaves where possible.
+{% endhint %}
+
+### FAQ
+
+
+
+How do I rotate a signer key?
+
+Describe key rotation steps.
+
+
+
+***
+
+If you paste the original content, I'll convert it exactly into GitBook-optimized markdown (tabs, steppers, expandables, etc.) preserving all links and URLs. Which would you like?
diff --git a/docs/learn/sbtc/clarity-contracts/sbtc-deposit.md b/docs/learn/sbtc/clarity-contracts/sbtc-deposit.md
new file mode 100644
index 0000000000..63fa3940ee
--- /dev/null
+++ b/docs/learn/sbtc/clarity-contracts/sbtc-deposit.md
@@ -0,0 +1,130 @@
+# sBTC Deposit
+
+## Overview
+
+The [sBTC Deposit contract](https://github.com/stacks-network/sbtc/blob/main/contracts/contracts/sbtc-deposit.clar) (`sbtc-deposit.clar`) manages the deposit process for the sBTC system. It handles the validation and minting of sBTC tokens when users deposit Bitcoin, and interacts with the sBTC Registry contract to update the protocol state.
+
+## Constants
+
+* `txid-length`: The required length of a transaction ID (32 bytes).
+* `dust-limit`: The minimum amount for a valid deposit (546 satoshis).
+
+## Error Constants
+
+* `ERR_TXID_LEN` (u300): Indicates that the provided transaction ID is not the correct length.
+* `ERR_DEPOSIT_REPLAY` (u301): Signifies an attempt to replay a deposit that has already been completed.
+* `ERR_LOWER_THAN_DUST` (u302): Indicates that the deposit amount is below the dust limit.
+* `ERR_DEPOSIT_INDEX_PREFIX`: Used as a prefix for deposit-related errors in batch processing.
+* `ERR_DEPOSIT` (u303): General deposit error.
+* `ERR_INVALID_CALLER` (u304): Indicates that the caller is not authorized to perform the operation.
+
+***
+
+## Public Functions
+
+### complete-deposit-wrapper
+
+Processes a single deposit request.
+
+* Parameters:
+ * `txid`: `(buff 32)` - The Bitcoin transaction ID
+ * `vout-index`: `uint` - The output index of the deposit transaction
+ * `amount`: `uint` - The amount of sBTC to mint (in satoshis)
+ * `recipient`: `principal` - The Stacks address to receive the minted sBTC
+* Returns: `(response bool uint)`
+
+{% stepper %}
+{% step %}
+#### Validation and authorization
+
+1. Verifies that the caller is the current signer principal.
+2. Checks that the deposit amount is above the dust limit.
+3. Validates the transaction ID length.
+{% endstep %}
+
+{% step %}
+#### Replay protection
+
+4. Ensures the deposit hasn't been processed before (prevents replay).
+{% endstep %}
+
+{% step %}
+#### Execution
+
+5. Mints sBTC tokens to the recipient via `.sbtc-token`'s `protocol-mint`.
+6. Updates the deposit state in the sBTC Registry contract via `.sbtc-registry`'s `complete-deposit`.
+{% endstep %}
+{% endstepper %}
+
+***
+
+### complete-deposits-wrapper
+
+Processes multiple deposit requests in a single transaction.
+
+* Parameters:
+ * `deposits`: `(list 650 {txid: (buff 32), vout-index: uint, amount: uint, recipient: principal})` - List of deposit data
+* Returns: `(response uint uint)`
+
+{% stepper %}
+{% step %}
+#### Authorization
+
+1. Verifies that the caller is the current signer principal.
+{% endstep %}
+
+{% step %}
+#### Batch processing
+
+2. Iterates through the list of deposits, processing each one using the `complete-individual-deposits-helper` function.
+{% endstep %}
+{% endstepper %}
+
+***
+
+## Private Functions
+
+### complete-individual-deposits-helper
+
+Helper function to process individual deposits within the batch operation.
+
+* Parameters:
+ * `deposit`: `{txid: (buff 32), vout-index: uint, amount: uint, recipient: principal}` - Single deposit data
+ * `helper-response`: `(response uint uint)` - Accumulator for tracking processed deposits
+* Returns: `(response uint uint)`
+
+{% stepper %}
+{% step %}
+#### Call deposit wrapper
+
+1. Calls `complete-deposit-wrapper` for the individual deposit.
+{% endstep %}
+
+{% step %}
+#### Success handling
+
+2. If successful, increments the processed deposit count.
+{% endstep %}
+
+{% step %}
+#### Error handling
+
+3. If an error occurs, it's propagated with additional index information (using `ERR_DEPOSIT_INDEX_PREFIX` or related error constants).
+{% endstep %}
+{% endstepper %}
+
+***
+
+## Interactions with Other Contracts
+
+* `.sbtc-registry`: Calls `get-current-signer-data`, `get-completed-deposit`, and `complete-deposit` to manage deposit state.
+* `.sbtc-token`: Calls `protocol-mint` to create new sBTC tokens.
+
+***
+
+## Security Considerations
+
+1. Access Control: Only the current signer principal can call the deposit completion functions.
+2. Replay Prevention: The contract checks for previously processed deposits to prevent replay attacks.
+3. Dust Limit: Enforces a minimum deposit amount to prevent spam and ensure economic viability.
+4. Transaction ID Validation: Ensures the provided transaction ID is the correct length.
diff --git a/docs/learn/sbtc/clarity-contracts/sbtc-registry.md b/docs/learn/sbtc/clarity-contracts/sbtc-registry.md
new file mode 100644
index 0000000000..54bf2f0efa
--- /dev/null
+++ b/docs/learn/sbtc/clarity-contracts/sbtc-registry.md
@@ -0,0 +1,224 @@
+# sBTC Registry
+
+## Overview
+
+The [sBTC Registry contract](https://github.com/stacks-network/sbtc/blob/main/contracts/contracts/sbtc-registry.clar) (`sbtc-registry.clar`) serves as the central registry for the sBTC system. It manages withdrawal requests, completed deposits, and the current signer set. This contract is crucial for maintaining the state and coordinating operations within the sBTC ecosystem.
+
+## Error Constants
+
+* `ERR_UNAUTHORIZED` (u400): Indicates unauthorized access.
+* `ERR_INVALID_REQUEST_ID` (u401): Signifies an invalid withdrawal request ID.
+* `ERR_AGG_PUBKEY_REPLAY` (u402): Indicates an attempt to replay an aggregate public key.
+* `ERR_MULTI_SIG_REPLAY` (u403): Signifies an attempt to replay a multi-signature address.
+
+## State Variables
+
+* `last-withdrawal-request-id`: Tracks the latest withdrawal request ID.
+* `current-signature-threshold`: Stores the current threshold for required signatures.
+* `current-signer-set`: Maintains a list of current signer public keys.
+* `current-aggregate-pubkey`: Holds the current aggregate public key.
+* `current-signer-principal`: Stores the current signer's principal address.
+
+## Data Maps
+
+### withdrawal-requests
+
+Stores withdrawal request details indexed by request ID.
+
+* Fields:
+ * `amount`: Amount of sBTC being withdrawn (in sats)
+ * `max-fee`: Maximum fee for the withdrawal
+ * `sender`: Principal of the sender
+ * `recipient`: BTC recipient address (version and hashbytes)
+ * `block-height`: Burn block height where the request was created
+
+### withdrawal-status
+
+Tracks the status of withdrawal requests indexed by request ID.
+
+* Value: `bool` (true if accepted, false if rejected, none if pending)
+
+### completed-deposits
+
+Records completed deposit transactions to prevent replay attacks.
+
+* Key: `{txid: (buff 32), vout-index: uint}`
+* Value: `{amount: uint, recipient: principal}`
+
+### aggregate-pubkeys
+
+Tracks used aggregate public keys to prevent replay attacks.
+
+* Key: `(buff 33)` (aggregate public key)
+* Value: `bool`
+
+### multi-sig-address
+
+Tracks used multi-signature addresses to prevent replay attacks.
+
+* Key: `principal` (multi-sig address)
+* Value: `bool`
+
+### protocol-contracts
+
+Stores authorized protocol contract addresses.
+
+* Key: `principal` (contract address)
+* Value: `bool`
+
+## Read-only Functions
+
+### get-withdrawal-request
+
+Retrieves a withdrawal request by its ID.
+
+* Parameters:
+ * `id`: `uint`
+* Returns: `(optional {amount: uint, max-fee: uint, sender: principal, recipient: {version: (buff 1), hashbytes: (buff 32)}, block-height: uint, status: (optional bool)})`
+
+### get-completed-deposit
+
+Fetches a completed deposit by transaction ID and output index.
+
+* Parameters:
+ * `txid`: `(buff 32)`
+ * `vout-index`: `uint`
+* Returns: `(optional {amount: uint, recipient: principal})`
+
+### get-current-signer-data
+
+Returns current signer set information.
+
+* Returns: `{current-signer-set: (list 128 (buff 33)), current-aggregate-pubkey: (buff 33), current-signer-principal: principal, current-signature-threshold: uint}`
+
+### get-current-aggregate-pubkey
+
+Returns the current aggregate public key.
+
+* Returns: `(buff 33)`
+
+### get-current-signer-principal
+
+Returns the current signer's principal.
+
+* Returns: `principal`
+
+### get-current-signer-set
+
+Returns the current set of signer public keys.
+
+* Returns: `(list 128 (buff 33))`
+
+## Public Functions
+
+### create-withdrawal-request
+
+Creates a new withdrawal request. Only callable by protocol contracts.
+
+* Parameters:
+ * `amount`: `uint`
+ * `max-fee`: `uint`
+ * `sender`: `principal`
+ * `recipient`: `{version: (buff 1), hashbytes: (buff 32)}`
+ * `height`: `uint`
+* Returns: `(response uint uint)`
+
+### complete-withdrawal-accept
+
+Marks a withdrawal request as accepted.
+
+* Parameters:
+ * `request-id`: `uint`
+ * `bitcoin-txid`: `(buff 32)`
+ * `output-index`: `uint`
+ * `signer-bitmap`: `uint`
+ * `fee`: `uint`
+* Returns: `(response bool uint)`
+
+### complete-withdrawal-reject
+
+Marks a withdrawal request as rejected.
+
+* Parameters:
+ * `request-id`: `uint`
+ * `signer-bitmap`: `uint`
+* Returns: `(response bool uint)`
+
+### complete-deposit
+
+Records a completed deposit transaction.
+
+* Parameters:
+ * `txid`: `(buff 32)`
+ * `vout-index`: `uint`
+ * `amount`: `uint`
+ * `recipient`: `principal`
+* Returns: `(response bool uint)`
+
+### rotate-keys
+
+Updates the signer set, multi-sig principal, and aggregate public key.
+
+* Parameters:
+ * `new-keys`: `(list 128 (buff 33))`
+ * `new-address`: `principal`
+ * `new-aggregate-pubkey`: `(buff 33)`
+ * `new-signature-threshold`: `uint`
+* Returns: `(response (buff 33) uint)`
+
+## Private Functions
+
+### increment-last-withdrawal-request-id
+
+Increments and returns the next withdrawal request ID.
+
+* Returns: `uint`
+
+### is-protocol-caller
+
+Checks if the caller is an authorized protocol contract.
+
+* Returns: `(response bool uint)`
+
+### validate-protocol-caller
+
+Validates if a given principal is an authorized protocol contract.
+
+* Parameters:
+ * `caller`: `principal`
+* Returns: `(response bool uint)`
+
+## Events
+
+The contract emits events (via `print`) for important actions:
+
+* Withdrawal request creation: "withdrawal-create"
+* Withdrawal acceptance: "withdrawal-accept"
+* Withdrawal rejection: "withdrawal-reject"
+* Deposit completion: "completed-deposit"
+
+{% hint style="info" %}
+Events are emitted via `print` statements in the contract for the actions listed above.
+{% endhint %}
+
+## Security Considerations
+
+{% stepper %}
+{% step %}
+#### Access Control
+
+Only authorized protocol contracts can call certain functions.
+{% endstep %}
+
+{% step %}
+#### Replay Prevention
+
+The contract prevents replay attacks on deposits, aggregate public keys, and multi-signature addresses.
+{% endstep %}
+
+{% step %}
+#### State Management
+
+The contract carefully manages the state of withdrawals and the current signer set.
+{% endstep %}
+{% endstepper %}
diff --git a/docs/learn/sbtc/clarity-contracts/sbtc-signers.md b/docs/learn/sbtc/clarity-contracts/sbtc-signers.md
new file mode 100644
index 0000000000..45dc00181f
--- /dev/null
+++ b/docs/learn/sbtc/clarity-contracts/sbtc-signers.md
@@ -0,0 +1,148 @@
+# sBTC Signers
+
+### Overview
+
+The [sBTC Signers contract](https://github.com/stacks-network/sbtc/blob/main/contracts/contracts/sbtc-bootstrap-signers.clar) (`sbtc-bootstrap-signers.clar`) manages the signer set for the sBTC system. It handles rotation of signer keys and provides utilities for generating multisig addresses.
+
+**Constants**
+
+* `key-size`: The required length of public keys (33 bytes).
+
+**Error Constants**
+
+* `ERR_KEY_SIZE_PREFIX`: Prefix for key size errors in batch processing.
+* `ERR_KEY_SIZE` (u200): Indicates that a provided key is not the correct length.
+* `ERR_INVALID_CALLER` (u201): Signifies that the function caller is not the current signer principal.
+* `ERR_SIGNATURE_THRESHOLD` (u202): Indicates an invalid signature threshold (must be >50% and ≤100% of total signer keys).
+
+#### Public Functions
+
+**`rotate-keys-wrapper`**
+
+Rotates the keys of the signers. Called when the signer set is updated.
+
+* Parameters:
+ * `new-keys`: `(list 128 (buff 33))` - List of new signer public keys
+ * `new-aggregate-pubkey`: `(buff 33)` - New aggregate public key
+ * `new-signature-threshold`: `uint` - New signature threshold
+* Returns: `(response (buff 33) uint)`
+
+Function flow:
+
+{% stepper %}
+{% step %}
+**Validate signature threshold**
+
+Ensure the new signature threshold is valid (must be >50% and ≤100% of total signer keys).
+{% endstep %}
+
+{% step %}
+**Verify caller**
+
+Verify that the caller is the current signer principal.
+{% endstep %}
+
+{% step %}
+**Validate keys**
+
+Check the length of each new key and the aggregate public key (must be 33 bytes).
+{% endstep %}
+
+{% step %}
+**Update registry**
+
+Call the sBTC Registry contract to update the keys and address.
+{% endstep %}
+{% endstepper %}
+
+#### Read-only Functions
+
+**`pubkeys-to-spend-script`**
+
+Generates the p2sh redeem script for a multisig.
+
+* Parameters:
+ * `pubkeys`: `(list 128 (buff 33))` - List of public keys
+ * `m`: `uint` - Number of required signatures
+* Returns: `(buff 1024)` - The p2sh redeem script
+
+**`pubkeys-to-hash`**
+
+Computes the hash160 of the p2sh redeem script.
+
+* Parameters:
+ * `pubkeys`: `(list 128 (buff 33))` - List of public keys
+ * `m`: `uint` - Number of required signatures
+* Returns: `(buff 20)` - The hash160 of the redeem script
+
+**`pubkeys-to-principal`**
+
+Generates a principal (Stacks address) from a set of pubkeys and an m-of-n threshold.
+
+* Parameters:
+ * `pubkeys`: `(list 128 (buff 33))` - List of public keys
+ * `m`: `uint` - Number of required signatures
+* Returns: `principal` - The generated Stacks address
+
+**`pubkeys-to-bytes`**
+
+Concatenates a list of pubkeys into a buffer with length prefixes.
+
+* Parameters:
+ * `pubkeys`: `(list 128 (buff 33))` - List of public keys
+* Returns: `(buff 510)` - Concatenated pubkeys with length prefixes
+
+**`concat-pubkeys-fold`**
+
+Concatenates a pubkey buffer with a length prefix.
+
+* Parameters:
+ * `pubkey`: `(buff 33)` - A single public key
+ * `iterator`: `(buff 510)` - Accumulator for concatenation
+* Returns: `(buff 510)` - Updated concatenated buffer
+
+**`bytes-len`**
+
+Returns the length of a byte buffer as a single byte.
+
+* Parameters:
+ * `bytes`: `(buff 33)` - Input byte buffer
+* Returns: `(buff 1)` - Length as a single byte
+
+**`uint-to-byte`**
+
+Converts a uint to a single byte.
+
+* Parameters:
+ * `n`: `uint` - Input number
+* Returns: `(buff 1)` - Number as a single byte
+
+#### Private Functions
+
+**`signer-key-length-check`**
+
+Checks that the length of each key is exactly 33 bytes.
+
+* Parameters:
+ * `current-key`: `(buff 33)` - Public key to check
+ * `helper-response`: `(response uint uint)` - Accumulator for error handling
+* Returns: `(response uint uint)` - Updated accumulator or error
+
+#### Constants
+
+**`BUFF_TO_BYTE`**
+
+A constant list mapping uint values (0-255) to their corresponding byte representations.
+
+Interactions with Other Contracts
+
+* `.sbtc-registry`: Calls `get-current-signer-data` and `rotate-keys` to manage signer data.
+
+Security Considerations
+
+{% hint style="warning" %}
+* Access Control: Only the current signer principal can call the key rotation function.
+* Key Validation: Ensures all provided keys are the correct length.
+* Signature Threshold: Enforces a minimum threshold of over 50% of signers and a maximum of 100%.
+* Multisig Generation: Provides utilities for secure generation of multisig addresses.
+{% endhint %}
diff --git a/docs/learn/sbtc/clarity-contracts/sbtc-token.md b/docs/learn/sbtc/clarity-contracts/sbtc-token.md
new file mode 100644
index 0000000000..df2d87b3b5
--- /dev/null
+++ b/docs/learn/sbtc/clarity-contracts/sbtc-token.md
@@ -0,0 +1,158 @@
+# sBTC Token
+
+## Overview
+
+The [sBTC Token contract](https://github.com/stacks-network/sbtc/blob/main/contracts/contracts/sbtc-token.clar) (`sbtc-token.clar`) implements the fungible token functionality for sBTC. It manages both unlocked and locked sBTC tokens and provides functions for minting, burning, transferring, and querying token information. sBTC is a SIP-010 standard fungible token.
+
+## Constants
+
+* `ERR_NOT_OWNER` (u4): Error when the sender tries to move a token they don't own.
+* `ERR_NOT_AUTH` (u5): Error when the caller is not an authorized protocol caller.
+* `token-decimals` (u8): The number of decimal places for the token.
+
+## Fungible Tokens
+
+* `sbtc-token`: The main sBTC fungible token.
+* `sbtc-token-locked`: Represents locked sBTC tokens.
+
+## Data Variables
+
+* `token-name`: The name of the token (default: "sBTC").
+* `token-symbol`: The symbol of the token (default: "sBTC").
+* `token-uri`: An optional URI for token metadata.
+
+## Protocol Functions
+
+These functions can only be called by authorized protocol contracts:
+
+### protocol-transfer
+
+* Parameters: `amount: uint`, `sender: principal`, `recipient: principal`
+* Returns: `(response bool uint)`
+
+### protocol-lock
+
+* Parameters: `amount: uint`, `owner: principal`
+* Returns: `(response bool uint)`
+
+### protocol-unlock
+
+* Parameters: `amount: uint`, `owner: principal`
+* Returns: `(response bool uint)`
+
+### protocol-mint
+
+* Parameters: `amount: uint`, `recipient: principal`
+* Returns: `(response bool uint)`
+
+### protocol-burn
+
+* Parameters: `amount: uint`, `owner: principal`
+* Returns: `(response bool uint)`
+
+### protocol-burn-locked
+
+* Parameters: `amount: uint`, `owner: principal`
+* Returns: `(response bool uint)`
+
+### protocol-set-name
+
+* Parameters: `new-name: (string-ascii 32)`
+* Returns: `(response bool uint)`
+
+### protocol-set-symbol
+
+* Parameters: `new-symbol: (string-ascii 10)`
+* Returns: `(response bool uint)`
+
+### protocol-set-token-uri
+
+* Parameters: `new-uri: (optional (string-utf8 256))`
+* Returns: `(response bool uint)`
+
+### protocol-mint-many
+
+* Parameters: `recipients: (list 200 {amount: uint, recipient: principal})`
+* Returns: `(response (list 200 (response bool uint)) uint)`
+
+## Public Functions (SIP-010 Trait)
+
+### transfer
+
+* Parameters: `amount: uint`, `sender: principal`, `recipient: principal`, `memo: (optional (buff 34))`
+* Returns: `(response bool uint)`
+
+### get-name
+
+* Returns: `(response (string-ascii 32) uint)`
+
+### get-symbol
+
+* Returns: `(response (string-ascii 10) uint)`
+
+### get-decimals
+
+* Returns: `(response uint uint)`
+
+### get-balance
+
+Returns the total balance (locked + unlocked) for a principal.
+
+* Parameters: `who: principal`
+* Returns: `(response uint uint)`
+
+### get-balance-available
+
+Returns the available (unlocked) balance for a principal.
+
+* Parameters: `who: principal`
+* Returns: `(response uint uint)`
+
+### get-balance-locked
+
+Returns the locked balance for a principal.
+
+* Parameters: `who: principal`
+* Returns: `(response uint uint)`
+
+### get-total-supply
+
+* Returns: `(response uint uint)`
+
+### get-token-uri
+
+* Returns: `(response (optional (string-utf8 256)) uint)`
+
+## Private Functions
+
+### protocol-mint-many-iter
+
+* Helper function for minting tokens to multiple recipients.
+* Parameters: `item: {amount: uint, recipient: principal}`
+* Returns: `(response bool uint)`
+
+## Security Considerations
+
+{% stepper %}
+{% step %}
+#### Access Control
+
+Protocol functions can only be called by authorized contracts, enforced through the `sbtc-registry` contract.
+{% endstep %}
+
+{% step %}
+#### Ownership Verification
+
+The `transfer` function checks that the sender owns the tokens being transferred.
+{% endstep %}
+
+{% step %}
+#### Separate Token Tracking
+
+The contract maintains separate tracking for locked and unlocked tokens, ensuring proper accounting.
+{% endstep %}
+{% endstepper %}
+
+## Interactions with Other Contracts
+
+* `.sbtc-registry`: Used to validate protocol callers for privileged operations.
diff --git a/docs/learn/sbtc/clarity-contracts/sbtc-withdrawal.md b/docs/learn/sbtc/clarity-contracts/sbtc-withdrawal.md
new file mode 100644
index 0000000000..1450be7611
--- /dev/null
+++ b/docs/learn/sbtc/clarity-contracts/sbtc-withdrawal.md
@@ -0,0 +1,141 @@
+# sBTC Withdrawal
+
+## Overview
+
+The [sBTC Withdrawal contract](https://github.com/stacks-network/sbtc/blob/main/contracts/contracts/sbtc-withdrawal.clar) (`sbtc-withdrawal.clar`) manages the withdrawal process for the sBTC system. It handles the initiation, acceptance, and rejection of withdrawal requests, ensuring proper validation and interaction with other sBTC contracts.
+
+## Constants
+
+### Error Codes
+
+* `ERR_INVALID_ADDR_VERSION` (u500): Invalid address version.
+* `ERR_INVALID_ADDR_HASHBYTES` (u501): Invalid address hashbytes.
+* `ERR_DUST_LIMIT` (u502): Withdrawal amount below dust limit.
+* `ERR_INVALID_REQUEST` (u503): Invalid withdrawal request ID.
+* `ERR_INVALID_CALLER` (u504): Caller is not the current signer principal.
+* `ERR_ALREADY_PROCESSED` (u505): Withdrawal request already processed.
+* `ERR_FEE_TOO_HIGH` (u505): Paid fee higher than requested.
+* `ERR_WITHDRAWAL_INDEX_PREFIX`: Prefix for withdrawal index errors.
+* `ERR_WITHDRAWAL_INDEX` (u506): General withdrawal index error.
+
+### Other Constants
+
+* `MAX_ADDRESS_VERSION` (u6): Maximum value of an address version.
+* `MAX_ADDRESS_VERSION_BUFF_20` (u4): Maximum version for 20-byte hashbytes.
+* `MAX_ADDRESS_VERSION_BUFF_32` (u6): Maximum version for 32-byte hashbytes.
+* `DUST_LIMIT` (u546): Minimum amount of sBTC for withdrawal.
+
+## Public Functions
+
+### initiate-withdrawal-request
+
+Initiates a new withdrawal request.
+
+* Parameters:
+ * `amount`: `uint` - Amount of sBTC to withdraw
+ * `recipient`: `{ version: (buff 1), hashbytes: (buff 32) }` - Bitcoin address details
+ * `max-fee`: `uint` - Maximum fee for the withdrawal
+* Returns: `(response uint uint)`
+
+### accept-withdrawal-request
+
+Accepts a withdrawal request.
+
+* Parameters:
+ * `request-id`: `uint` - Withdrawal request ID
+ * `bitcoin-txid`: `(buff 32)` - Bitcoin transaction ID
+ * `signer-bitmap`: `uint` - Bitmap of signers
+ * `output-index`: `uint` - Output index in the Bitcoin transaction
+ * `fee`: `uint` - Actual fee paid
+* Returns: `(response bool uint)`
+
+### reject-withdrawal-request
+
+Rejects a withdrawal request.
+
+* Parameters:
+ * `request-id`: `uint` - Withdrawal request ID
+ * `signer-bitmap`: `uint` - Bitmap of signers
+* Returns: `(response bool uint)`
+
+### complete-withdrawals
+
+Processes multiple withdrawal requests (accept or reject).
+
+* Parameters:
+ * `withdrawals`: `(list 600 {...})` - List of withdrawal details
+* Returns: `(response uint uint)`
+
+## Read-only Functions
+
+### validate-recipient
+
+Validates the recipient's Bitcoin address format.
+
+* Parameters:
+ * `recipient`: `{ version: (buff 1), hashbytes: (buff 32) }` - Bitcoin address details
+* Returns: `(response bool uint)`
+
+## Private Functions
+
+### complete-individual-withdrawal-helper
+
+Helper function to process individual withdrawals in the batch operation.
+
+* Parameters:
+ * `withdrawal`: `{...}` - Individual withdrawal details
+ * `helper-response`: `(response uint uint)` - Accumulator for processing
+* Returns: `(response uint uint)`
+
+## Interactions with Other Contracts
+
+* `.sbtc-token`: Calls `protocol-lock`, `protocol-burn-locked`, `protocol-mint`, and `protocol-unlock` for token operations.
+* `.sbtc-registry`: Calls `create-withdrawal-request`, `get-withdrawal-request`, `get-current-signer-data`, `complete-withdrawal-accept`, and `complete-withdrawal-reject` for managing withdrawal requests and signer data.
+
+## Security Considerations
+
+{% stepper %}
+{% step %}
+#### Access Control
+
+Only the current signer principal can accept or reject withdrawal requests.
+{% endstep %}
+
+{% step %}
+#### Dust Limit
+
+Enforces a minimum withdrawal amount to prevent spam and ensure economic viability.
+{% endstep %}
+
+{% step %}
+#### Fee Management
+
+Ensures that the actual fee doesn't exceed the maximum fee set by the user.
+{% endstep %}
+
+{% step %}
+#### Address Validation
+
+Implements thorough validation of Bitcoin address formats.
+{% endstep %}
+
+{% step %}
+#### State Management
+
+Prevents double-processing of withdrawal requests.
+{% endstep %}
+{% endstepper %}
+
+## Bitcoin Address Types
+
+The contract supports various Bitcoin address types, including:
+
+* P2PKH (Pay-to-Public-Key-Hash)
+* P2SH (Pay-to-Script-Hash)
+* P2SH-P2WPKH (P2SH nested P2WPKH)
+* P2SH-P2WSH (P2SH nested P2WSH)
+* P2WPKH (Pay-to-Witness-Public-Key-Hash)
+* P2WSH (Pay-to-Witness-Script-Hash)
+* P2TR (Pay-to-Taproot)
+
+Each address type is represented by a specific version byte and hashbytes format in the recipient structure.
diff --git a/docs/learn/sbtc/core-features.md b/docs/learn/sbtc/core-features.md
new file mode 100644
index 0000000000..6a3df40e62
--- /dev/null
+++ b/docs/learn/sbtc/core-features.md
@@ -0,0 +1,50 @@
+# Core Features
+
+sBTC offers several core features that make it a powerful trust-minimized Bitcoin bridge between Stacks and Bitcoin:
+
+{% stepper %}
+{% step %}
+#### 1:1 Bitcoin Backing
+
+Each sBTC token is backed by an equivalent amount of Bitcoin in the peg wallet. This ensures that sBTC maintains a stable value relative to BTC.
+{% endstep %}
+
+{% step %}
+#### Decentralized Management
+
+The sBTC peg wallet is maintained and managed by a set of sBTC signers. This decentralized approach enhances security and reduces single points of failure.
+{% endstep %}
+
+{% step %}
+#### Quick Conversions
+
+sBTC facilitates rapid movement between BTC and sBTC:
+
+* BTC to sBTC conversion can be completed within 3 Bitcoin blocks
+* sBTC to BTC conversion can be completed within 6 Bitcoin blocks
+{% endstep %}
+
+{% step %}
+#### SIP-010 Compatibility
+
+sBTC adheres to the SIP-010 fungible token standard on the Stacks blockchain. This ensures wide compatibility with Stacks wallets and applications.
+{% endstep %}
+
+{% step %}
+#### Community Governance
+
+The initial sBTC signing set is determined by a community vote, weighted by STX holdings. This approach ensures that the community has a say in the management of the sBTC system.
+{% endstep %}
+
+{% step %}
+#### Signer Key Rotation
+
+sBTC signers have the ability to rotate their private keys, enhancing long-term security of the system.
+{% endstep %}
+
+{% step %}
+#### Transaction Fee Sponsorship
+
+sBTC transactions on Stacks can be sponsored, allowing users to pay transaction fees in sBTC instead of STX.
+{% endstep %}
+{% endstepper %}
diff --git a/docs/learn/sbtc/emily-api.md b/docs/learn/sbtc/emily-api.md
new file mode 100644
index 0000000000..8712877546
--- /dev/null
+++ b/docs/learn/sbtc/emily-api.md
@@ -0,0 +1,63 @@
+# Emily API
+
+[Emily](https://github.com/stacks-network/sbtc/tree/main/emily) is an API that helps facilitate and supervise the sBTC Bridge, serving as a programmatic liaison between sBTC users and signers.
+
+## Overview
+
+The Emily API is designed to track deposits and withdrawals, providing information about the status of in-flight sBTC operations. It serves two primary user groups: sBTC users and sBTC app developers.
+
+### Why Call it Emily?
+
+The Emily API is given an indirect name because it handles more than just Deposits and Withdrawals; it can detect the health of the system and will likely be extended to handle more as user requirements mature. It was once called the “Revealer API”, which stopped making sense after a few design changes, and then “Deposit API” which also stopped making sense after a few changes. The most obvious choice “sBTC API” gives the wrong impression of what the API is responsible for as well, since the API itself isn’t managing the entirety of the protocol.
+
+Large companies name their APIs after something loosely related but ambiguous enough that extensions of the API don’t make the original name of the API misleading. Following this, we chose “Emily” after Emily Warren Roebling who was the liaison between the builders and chief engineer, her husband, of the Brooklyn bridge. She was, in effect, the supervisor of the bridge’s construction; similarly, the Emily API supervises the sBTC bridge and liaises between the users of the protocol and the sBTC signers.
+
+### Key Features
+
+* Track Deposits: Monitor the process of converting BTC to sBTC.
+* Track Withdrawals: Monitor the process of converting sBTC back to BTC.
+* Provide Operation Status: Offer real-time status updates for ongoing sBTC operations.
+* Retrieve Historical Data: Allow querying of past sBTC operations.
+
+## Core Concepts
+
+#### sBTC Operations
+
+sBTC operations are the fundamental processes tracked by Emily:
+
+* Deposits: Converting BTC to sBTC
+* Withdrawals: Converting sBTC back to BTC
+
+#### Operation States
+
+Each sBTC operation goes through several states:
+
+* PENDING: The operation has been initiated.
+* ACCEPTED: The operation has been approved by the signers.
+* CONFIRMED: The operation has been completed and confirmed on the blockchain.
+* FAILED: The operation could not be completed.
+
+### Where Emily is involved in the sBTC flows
+
+In each of the deposit and withdrawal flows for sBTC, Emily plays a vital role. Here's where Emily sits in both the Deposit and Withdrawal flows.
+
+#### **During the Deposit Flow**
+
+1. User creates a deposit transaction on Bitcoin
+2. User submits proof of deposit to the Deposit API
+3. **Emily records the deposit as PENDING**
+4. Signers validate and vote on the deposit
+5. **If accepted, Emily updates status to ACCEPTED**
+6. Signers process the Bitcoin transaction
+7. Signers mint sBTC on Stacks
+8. **Emily updates the deposit status to CONFIRMED**
+
+#### **During the Withdrawal Flow**
+
+1. User initiates withdrawal through the sBTC Clarity contract
+2. **Emily records the withdrawal as PENDING**
+3. Signers decide to accept or reject the withdrawal
+4. **If accepted, Emily updates status to ACCEPTED**
+5. Signers process the Bitcoin transaction
+6. Signers burn sBTC on Stacks
+7. **Emily updates the withdrawal status to CONFIRMED**
diff --git a/docs/learn/sbtc/peg-wallet-utxo.md b/docs/learn/sbtc/peg-wallet-utxo.md
new file mode 100644
index 0000000000..8ced4b19b5
--- /dev/null
+++ b/docs/learn/sbtc/peg-wallet-utxo.md
@@ -0,0 +1,65 @@
+# Peg Wallet UTXO
+
+The Peg Wallet UTXO is a fundamental element of the sBTC system, serving as the Bitcoin backing for all sBTC tokens in circulation. The system uses a Single UTXO Model: the sBTC peg wallet is consistently represented as a single Unspent Transaction Output (UTXO) on the Bitcoin blockchain. This design offers simplicity and improved efficiency in managing the peg wallet.
+
+{% hint style="info" %}
+This UTXO resides in a secure multi-signature taproot address controlled by the sBTC Signers:\
+[bc1prcs82tvrz70jk8u79uekwdfjhd0qhs2mva6e526arycu7fu25zsqhyztuy](https://mempool.space/address/bc1prcs82tvrz70jk8u79uekwdfjhd0qhs2mva6e526arycu7fu25zsqhyztuy)
+{% endhint %}
+
+## Overview
+
+* Single UTXO Model: the peg wallet is always a single UTXO.
+* Responsibility: UTXO management is performed by the Signer set.
+* Purpose: simplify tracking and management, reduce Bitcoin transactions required for sBTC operations, and centralize funds in a single, well-secured output.
+
+## How the Single UTXO is maintained
+
+{% stepper %}
+{% step %}
+**Constructing the new UTXO**
+
+A Signer coordinator constructs the UTXO by creating a new Bitcoin output that will represent the peg wallet going forward.
+{% endstep %}
+
+{% step %}
+**Consolidating requests into a batch**
+
+The Signer set collectively consolidates all deposit and withdrawal requests and creates optimized batches that can be processed within a single UTXO.
+{% endstep %}
+
+{% step %}
+**Creating the new UTXO from the previous UTXO**
+
+The new UTXO is created by:
+
+* spending the amount from the previous UTXO,
+* adding confirmed deposits,
+* subtracting confirmed withdrawals.
+{% endstep %}
+
+{% step %}
+**Optimizing batching with approval sets**
+
+When multiple sBTC operation requests are present, the Signer coordinator groups them by approval sets. If differing approval sets exist across active operations, the coordinator batches deposit UTXOs into groups with the maximum size per approval set to preserve the single UTXO invariant while maximizing batch efficiency.
+{% endstep %}
+{% endstepper %}
+
+## Benefits
+
+* Simplified tracking and management of peg funds.
+* Fewer Bitcoin transactions for sBTC operations.
+* Centralized funds in a single, well-secured output improves operational efficiency.
+
+{% hint style="info" %}
+The Single UTXO Model is designed to balance simplicity and operational efficiency for the sBTC peg wallet.
+{% endhint %}
+
+## Security considerations
+
+* The single UTXO is managed by the sBTC Bootstrap Signer Set, which requires a threshold of signers to approve any spending (multi-signature).
+* Regular audits and continuous monitoring are essential to ensure the UTXO accurately represents the total sBTC in circulation at all times.
+
+{% hint style="warning" %}
+Security is paramount: multi-signature approval, audits, and monitoring are core controls to protect the peg wallet.
+{% endhint %}
diff --git a/docs/learn/sbtc/sbtc-faq.md b/docs/learn/sbtc/sbtc-faq.md
new file mode 100644
index 0000000000..ab40b0c43f
--- /dev/null
+++ b/docs/learn/sbtc/sbtc-faq.md
@@ -0,0 +1,192 @@
+# sBTC FAQ
+
+### sBTC Basics
+
+
+
+What is sBTC?
+
+sBTC is a decentralizedl 1:1 Bitcoin-backed asset on the Stacks Bitcoin Layer. Read more about Stacks [here](https://www.stacks.co/) and sBTC [here](https://www.stacks.co/sbtc).
+
+
+
+
+
+How does sBTC work?
+
+sBTC as a SIP-010 tokensBTC is a SIP-010 token on the Stacks blockchain that represents Bitcoin (BTC) in a 1:1 ratio. sBTC is always backed 1:1 against BTC.Peg wallet and signersThe sBTC peg wallet is maintained and managed by a set of sBTC signers. This decentralized approach enhances security and reduces single points of failure. Read more about Stacker Signing here.
+
+
+
+
+
+What is Bitcoin Finality, and why is it important?
+
+Stacks and sBTC state automatically fork with Bitcoin. As such, all transactions settle to Bitcoin with 100% Bitcoin Finality. This protects users against attacks to sBTC via a hard fork. This is a critical security measure that aligns sBTC security with Bitcoin. Read more in [the Stacks Documentation](https://docs.stacks.co/concepts/block-production/bitcoin-finality).
+
+
+
+
+
+How does the Stacks Signer network improve security?
+
+Signers are responsible for approving all sBTC deposit and withdrawal operations, ensuring the integrity of the system. With a requirement of 70% consensus for transaction approval, Signers maintain the protocol's liveness and security.
+
+To launch sBTC, the Stacks community approved [SIP-028](https://github.com/stacksgov/sips/blob/69d40a5f4f0ad98eb448ba44e7c31ca054820aa3/sips/sip-028-sbtc_peg.md), defining the criteria for selecting signers based on factors such as technical expertise, reliability, performance, and decentralization. An initial group of 15 institutional Signers has been chosen for Phase 1 to maintain simplicity and reduce operational risks. This group will expand over time as the protocol matures.
+
+The list of sBTC signers is public and listed [here](https://bitcoinl2labs.com/sbtc-rollout#sbtc-signers).
+
+
+
+
+
+What security measures have been put in place to ensure sBTC is safe?
+
+sBTC is always backed 1:1 against BTC, and it's verifiably secure through threshold cryptography. sBTC removes the need for 3rd party custodian or trusted setup. Instead, BTC is secured by a decentralized signer set.
+
+Partnerships with top-tier security experts have been established to ensure the protocol is fortified at every level:
+
+Asymmetric Research is a core security contributor. Known for their rigorous research and protocol audits, Asymmetric brings security expertise to sBTC to identify and mitigate potential vulnerabilities. ImmuneFiA robust bug bounty program incentivizes ethical hackers to uncover and address potential issues, adding an additional layer of defense. 3rd Party AuditsSeveral third-party security audits have been conducted on the sBTC system and can be referenced on the sBTC Audits page.
+
+
+
+
+
+What sets sBTC apart?
+
+Here are the main differentiating characteristics of sBTC:
+
+* sBTC is a true Bitcoin native product
+* sBTC is backed by respected leaders in the Bitcoin community (signer network)
+* sBTC's security is provided by a decentralized network of validators/signers rather than a single custodian, removing the need to trust a single entity or exchange
+* sBTC leverages 100% Bitcoin finality
+* sBTC's technology offers optimal UX and DevEx for an L2
+* sBTC is a fully transparent project/product working in the open with public code
+
+
+
+
+
+Where can I learn more about the sBTC signers?
+
+Read the "[Selection of sBTC Signer Set](https://github.com/stacks-network/sbtc/discussions/624)" post for more information about each signer and their qualifications.
+
+
+
+### Using sBTC
+
+
+
+When will sBTC be available?
+
+sBTC deposits first went live on December 16, 2024, quickly hitting the 1,000 BTC cap. The second cap will go live on February 25th, 2025, quickly hitting the 3,000 BTC cap. Withdrawals went live on April 30, 2025.
+
+Full decentralization of the Signer set will follow in [a subsequent phase](https://bitcoinl2labs.com/sbtc-rollout), gradually expanding beyond the initial 15 community-elected signers.
+
+
+
+
+
+What wallets are supported for sBTC?
+
+[Xverse](https://www.xverse.app/) and [Leather](https://leather.io/) wallets are supported — two leading wallets with seamless integrations designed for Bitcoin and Stacks users.
+
+In addition, [Ledger](https://www.ledger.com/) and [Asigna](https://www.asigna.io/) support sBTC.
+
+We are actively working with institutional custodians, staking providers, and other 3rd party wallets to support sBTC. More will be announced.
+
+
+
+
+
+Why is there a .001 BTC minimum for BTC to sBTC deposits?
+
+A .001 BTC minimum is imposed for BTC to sBTC deposits to ensure the system does not get spammed by many smaller transactions. We are exploring reducing the deposit minimum for future phases.
+
+
+
+
+
+What are the steps to use the sBTC Bridge and earn rewards?
+
+In the Stacks Documentation, find a [video](https://www.youtube.com/watch?v=XZruuDgTo4k\&t=1s) and a more detailed [walkthrough](using-the-sbtc-bridge-app/).
+
+
+
+
+
+How long will it take for my BTC deposit to confirm?
+
+sBTC facilitates rapid movement between BTC and sBTC.
+
+BTC to sBTCBTC to sBTC conversion can be completed within 3 Bitcoin blocks (under an hour).sBTC to BTCsBTC to BTC conversion can be completed within 6 Bitcoin blocks (Approximately two hours)
+
+Read more in the [Stacks Documentation](https://docs.stacks.co/concepts/sbtc/operations/deposit-withdrawal-times).
+
+
+
+
+
+Why is there a cap on the total BTC pegged in?
+
+A BTC cap will be implemented to ensure a smooth rollout process with a focus on security.
+
+In addition, the BTC cap will give developers the time to focus on the sBTC user experience and integration with DeFi applications across the Stacks ecosystem prior to opening sBTC for all users.
+
+
+
+
+
+Are there any associated fees with minting sBTC?
+
+There are two transaction fees required to mint your sBTC. The first is set by the user manually when they initiate the deposit transaction within their wallet.
+
+The second is a fee used to consolidate the deposit UTXOs into the single signer UTXO. This separate transaction fee happens automatically and is set to a max of 80k sats. This is automatically deducted from your minted sBTC. This is not a signer fee but a regular Bitcoin transaction fee.
+
+
+
+
+
+Are there multi-signature solutions for sBTC?
+
+Yes. [Asigna](https://www.asigna.io/) provides a multi-signature solution for sBTC users.
+
+
+
+
+
+Are custodians available to support sBTC?
+
+At the moment, there is no custodian support for sBTC. However, we are actively working with institutional custodians to support sBTC.
+
+Copper and BitGo already support Stacks and Stacking; however, we are working to prioritize SIP-10 and sBTC integration.
+
+
+
+### sBTC Troubleshooting
+
+
+
+My Bitcoin transaction confirmed, but I'm not seeing the sBTC token in my wallet.
+
+You may need to enable the display of the sBTC token within your wallet by clicking on 'Manage Tokens' and enabling sBTC.
+
+
+
+
+
+I received an "Errors.Invalid_Transaction" error when using an Xverse Wallet
+
+If you received a "Errors.Invalid\_Transaction" error when using an Xverse Wallet, you may be using a "Nested SegWit" wallet. To resolve the issue, change your Xverse wallet to use the "Native SegWit".
+
+
+
+
+
+sBTC still isn't showing up in wallet after 3 Bitcoin blocks. How much longer do I have to wait?
+
+BTC to sBTC conversions are typically completed within 3 Bitcoin blocks. Due to the speed of Bitcoin blocks, deposits can take up to two hours to see sBTC in your wallet.
+
+However, there may be a lag with your Leather or Xverse wallet where the sBTC will take another 20 minutes to show up in the wallet.
+
+
diff --git a/docs/learn/sbtc/sbtc-operations/README.md b/docs/learn/sbtc/sbtc-operations/README.md
new file mode 100644
index 0000000000..1a6284bbf6
--- /dev/null
+++ b/docs/learn/sbtc/sbtc-operations/README.md
@@ -0,0 +1,28 @@
+# sBTC Operations
+
+This section covers the main operations in the sBTC system. These operations form the core functionality of sBTC, allowing users to permissionlessly move value between the Bitcoin and Stacks ecosystems.
+
+{% stepper %}
+{% step %}
+#### Deposit
+
+Converting BTC to sBTC.
+
+* **Increased Utility**: Users can leverage their Bitcoin on the Stacks network by converting BTC to sBTC, providing access to smart contracts and decentralized applications (dApps) that are not natively possible on the Bitcoin network.
+* **DeFi Opportunities**: By utilizing sBTC, users can participate in decentralized finance (DeFi) activities such as lending, borrowing, and earning yield on their assets.
+* **Cost Efficiency**: Operating on the Stacks network might offer lower transaction fees compared to the Bitcoin network, making it cost-effective for conducting transactions and executing smart contracts.
+* **Interoperability**: sBTC allows users to enjoy the benefits of blockchain interoperability, moving their value seamlessly between the Bitcoin and Stacks ecosystems.
+* **Network Security**: Stacks enhance security by building on Bitcoin's robustness, providing an added layer of trust and reliability when using sBTC.
+{% endstep %}
+
+{% step %}
+#### Withdrawal
+
+Converting sBTC back to BTC.
+
+* **Liquidity Needs**: Users might want to convert sBTC back to BTC to access the deep liquidity available on the Bitcoin network, facilitating easier and potentially faster transactions.
+* **Off-Ramping**: Converting sBTC to BTC can allow users to withdraw their funds from the cryptocurrency ecosystem into fiat currency through exchanges that primarily support Bitcoin.
+* **Security Preferences**: Some users might prefer holding their assets directly on the Bitcoin network due to its reputation for security and decentralization.
+* **Network Preference**: Individuals may choose to operate exclusively within the Bitcoin network for its simplicity and widespread acceptance as a method of payment.
+{% endstep %}
+{% endstepper %}
diff --git a/docs/learn/sbtc/sbtc-operations/deposit-vs-withdrawal-times.md b/docs/learn/sbtc/sbtc-operations/deposit-vs-withdrawal-times.md
new file mode 100644
index 0000000000..ee00b98efb
--- /dev/null
+++ b/docs/learn/sbtc/sbtc-operations/deposit-vs-withdrawal-times.md
@@ -0,0 +1,51 @@
+---
+description: >-
+ Understanding why the time is takes to deposit BTC to sBTC is different than
+ withdrawing sBTC back into BTC.
+---
+
+# Deposit vs Withdrawal Times
+
+### Why are Deposits So Fast and Withdrawals So Slow?
+
+sBTC allows users to use their BTC on the Stacks L2 by using a wrapped token called sBTC. Moving sBTC onto the Stacks L2 can take as little time as 1 Bitcoin block, but moving sBTC off the Stacks L2 into the native Bitcoin blockchain takes 6 Bitcoin blocks. Why is that?
+
+> To understand why moving onto the Stacks layer can be so fast and yet moving off must be so slow, we need to first understand the consensus mechanism of the Stacks blockchain.
+
+The Stacks blockchain uses a consensus mechanism called Proof of Transfer, or PoX, in order to mint new blocks. On each Bitcoin block, miners, on the Stacks blockchain, each sacrifice some amount of Bitcoin in a bid to win the right to make the next few Stacks blocks, where they retain the right to keep making Stacks blocks until the next Bitcoin block occurs and the latest bidding round elects a new Stacks miner.
+
+#### Determining which Stacks blocks should be tied to which Bitcoin block
+
+Signers (validators equivalents for the Stacks Blockchain) look at the Bitcoin blocks and approve new Stacks blocks based on which miner currently has the right to make Stacks blocks, and they only approve new blocks from the miner that won the most recent bid on the Bitcoin block within the fork that they collectively consider to be the “best”. The Stacks blockchain can only have new blocks added if the Signers agree that the miner who proposed it is the winner of the bid on the Bitcoin blockchain, and all the Signers are voting on which block should be added, effectively collectively deciding which Bitcoin fork is the best one.
+
+**Here’s an important part**: if the Signers believe that there’s a new and better Bitcoin fork that differs from the one that the last several Stacks blocks had been mined on, they’ll then only approve new Stacks blocks that build off of existing Stacks blocks that are tied to that new Bitcoin fork. As in, every Stacks block that was built on Bitcoin blocks in the other Bitcoin fork that aren’t in this new canonical fork are considered invalid; thus the Stacks blockchain forks too.
+
+> “The Stacks blockchain forks with the Bitcoin blockchain.”
+
+Now that we understand this forking mechanism, let's take a look at why moving off the Stacks layer must be so slow.
+
+#### **Why moving from sBTC to BTC takes more time**
+
+sBTC exists on the Stacks layer as a token that smart contracts can interact with. To move sBTC over from the Stacks layer to the Bitcoin layer, the owner of the sBTC calls a smart contract to initiate what we call the “withdrawal” sequence. This lets the “sBTC Signers” (these are different from the earlier Signers mentioned) know that they need to create a transaction on the Bitcoin blockchain to distribute the BTC back to the user.
+
+If the sBTC Signers create a Bitcoin transaction to enact the withdrawal, they can’t take it back, and it will be valid on every fork of the Bitcoin blockchain. So what happens if, say, the Bitcoin blockchain forks and the withdrawal on the Stacks layer got reorganized out? Then there’s an irretrievable withdrawal transaction on the Bitcoin blockchain giving precious BTC to a user who never withdrew their sBTC on the Stacks layer.
+
+
+
+Can the Signers that maintain the original chain force miners to replay all previously confirmed transactions?
+
+The Stacks blockchain is a true Layer 2 on top of Bitcoin, and you can write a smart contract to have different behavior based on observations of the Bitcoin blockchain underneath. You can, for example, write a Stacks contract that says “Pay to Jeff if the latest Bitcoin block hash ends in an even hex digit, and pay to Abigail if it’s an odd hex digit.” Now when there’s a reorg of the Bitcoin blockchain you can replay this transaction which originally paid to Jeff, but it now pays to Abigail, and what happens if this contract was giving out sBTC, and further what happens if Jeff then immediately executed a withdrawal?
+
+
+
+So in the end, to process a withdrawal safely you need to be sufficiently sure it won’t get reorganized out. That means it can only be processed 6 Bitcoin blocks (the finality criteria the sBTC Signers are comfortable with) after the sBTC withdrawal transaction was made on the Stacks blockchain.
+
+#### But then, why can deposits be done in one Bitcoin block at its fastest?
+
+Remember how Stacks forks with Bitcoin? Let's say someone makes a deposit on the Bitcoin blockchain in an attempt to mint sBTC, and then lets say the sBTC Signers immediately mint sBTC. What happens if the Bitcoin chain forks causing the Stacks blockchain to fork? The mint gets reorganized out! Sure, the deposit is no longer on the Bitcoin blockchain, but it’s not on the Stacks blockchain either. If that deposit doesn’t ever arrive on the Bitcoin blockchain the sBTC signers will never mint sBTC, so there’s nothing to take back!
+
+#### The Bitcoin chain gets the final say
+
+So all in all, for movements of sBTC from the Stacks layer into the Bitcoin layer the protocol needs to wait for Bitcoin to be sufficiently final, but movements from the Bitcoin layer to the Stacks layer don’t need to wait for finality to mint because the Stacks layer will just reorganize itself if the Bitcoin layer reorganizes too.
+
+But then conceptually remember, the mint call on the Stacks blockchain is just as final as the Bitcoin block that contains the deposit of BTC onto the Stacks layer. If you’re minting sBTC on the Stacks layer and you want to wait for it to be final you’ll need to wait a suitable number of Bitcoin blocks to consider it finally minted, but that’s up to you and not the sBTC Signers.
diff --git a/docs/learn/sbtc/sbtc-operations/deposit.md b/docs/learn/sbtc/sbtc-operations/deposit.md
new file mode 100644
index 0000000000..bb2bbbb8c3
--- /dev/null
+++ b/docs/learn/sbtc/sbtc-operations/deposit.md
@@ -0,0 +1,47 @@
+---
+description: Converting BTC to sBTC.
+---
+
+# Deposit
+
+The deposit operation enables users to mint sBTC, anchored to the BTC they have placed in the threshold wallet on the Bitcoin chain. This process can be completed within a single Bitcoin block, streamlining the user experience.
+
+## Process Overview
+
+
+
+The deposit process begins when a user initiates a specific Bitcoin transaction that has two outputs. The depositor (usually through the application they are using to deposit) then initiates an API call referencing that Bitcoin transaction. This call triggers the Emily API, which relays deposit information to the sBTC Signers. These signers verify and process the deposit. Once verified, an equivalent amount of sBTC is minted on the Stacks blockchain.
+
+{% stepper %}
+{% step %}
+**Script output**
+
+A script that lets the signers spend the funds.
+{% endstep %}
+
+{% step %}
+**Time-locked output**
+
+A time lock that allows the depositor to reclaim the funds if necessary.
+{% endstep %}
+{% endstepper %}
+
+The deposit is usually completed within a single Bitcoin block, but is guaranteed to be completed within 3. For more information on deposit and withdrawal confirmation times and why deposits can be so fast, check out the [Deposit and Withdrawal Times](deposit-vs-withdrawal-times.md) doc.
+
+## Bitcoin Deposit Requirements
+
+For a deposit to be considered valid, it must adhere to specific requirements:
+
+* The deposit must be made to a taproot address.
+* The output must be spendable by a consensus threshold of signers.
+* The deposit must follow a format that prevents short-term clawbacks, ensuring the security and integrity of the system.
+
+## User Experience
+
+From a user's perspective, the deposit process is straightforward:
+
+1. Initiate a BTC transaction to the specified address.
+2. Wait for the transaction to be confirmed on the Bitcoin blockchain.
+3. Receive the equivalent amount of sBTC in the Stacks wallet once the deposit is verified and processed.
+
+To enhance the user experience, an sBTC bridge web application is currently in development which will provide an intuitive interface for users to track the status of their deposit operations, allowing users to stay informed throughout the process from initiation to completion.
diff --git a/docs/learn/sbtc/sbtc-operations/withdrawal.md b/docs/learn/sbtc/sbtc-operations/withdrawal.md
new file mode 100644
index 0000000000..b1ee7a4af8
--- /dev/null
+++ b/docs/learn/sbtc/sbtc-operations/withdrawal.md
@@ -0,0 +1,77 @@
+---
+description: Converting sBTC back to BTC.
+---
+
+# Withdrawal
+
+The sBTC withdrawal operation enables users to convert their sBTC back to BTC. This process involves burning sBTC on the Stacks blockchain and releasing an equivalent amount of BTC on the Bitcoin blockchain.
+
+## Process Overview
+
+
+
+
+
+{% stepper %}
+{% step %}
+**Initiate withdrawal**
+
+A user initiates a Clarity contract call (via a Stacks wallet or dApp) specifying:
+
+* the amount of sBTC to withdraw
+* the destination Bitcoin address
+{% endstep %}
+
+{% step %}
+**Stacks transaction finality**
+
+The Stacks transaction must reach finality. The protocol requires six Bitcoin block confirmations before proceeding to the next step.
+{% endstep %}
+
+{% step %}
+**Signer verification and BTC release**
+
+After confirmations, sBTC Signers verify the withdrawal request and create the withdrawal transaction on the Bitcoin network, releasing the equivalent BTC to the specified Bitcoin address.
+{% endstep %}
+{% endstepper %}
+
+The withdrawal process requires six Bitcoin block confirmations to complete. After these confirmations, sBTC Signers create the withdrawal transaction on the Bitcoin network.
+
+## Withdrawal Confirmation
+
+The six-block confirmation requirement serves multiple purposes:
+
+* Ensures finality of the Stacks transaction and prevents potential reversals or conflicts.
+* Mitigates issues from potential Bitcoin forks by allowing time for network stability.
+* Gives sBTC Signers sufficient time to verify and process the withdrawal request accurately.
+
+For more information on deposit and withdrawal confirmation times and why deposits can be faster than withdrawals, see the [Deposit and Withdrawal Times](deposit-vs-withdrawal-times.md) doc.
+
+## Failure Cases
+
+Some withdrawal failures can be identified and resolved before the six confirmations are complete. Other failures may only become apparent after the sBTC Bootstrap Signer attempts to create the withdrawal transaction on the Bitcoin network. These delays stem from the complexity of cross-chain operations and the need for thorough verification at each step.
+
+
+
+More about failure detection timing
+
+Because cross-chain operations involve verification on both Stacks and Bitcoin, certain issues (for example: insufficient signer consensus, malformed Bitcoin transaction construction, or Bitcoin network conditions) may only be detectable when the signer attempts to broadcast the Bitcoin transaction. This can cause failure detection to occur after confirmations on Stacks are already complete.
+
+
+
+## Security Considerations
+
+{% hint style="info" %}
+The multi-block confirmation process is a critical security measure to help prevent double-spending attempts. Requiring multiple block confirmations ensures the withdrawal request is valid and final before processing on the Bitcoin network. Additionally, sBTC Signers perform verification of each withdrawal request prior to creating the Bitcoin transaction, providing an extra security layer.
+{% endhint %}
+
+## User Experience
+
+From a user's perspective:
+
+* Initiate a withdrawal through a Stacks wallet or dApp.
+* Specify the sBTC amount and destination Bitcoin address.
+* Wait for the required six Bitcoin blocks to confirm.
+* Once confirmations complete and signers process the request, BTC is sent to the specified Bitcoin address.
+
+The sBTC bridge web application offers a user-friendly interface that lets users track the status of their withdrawal operations in real time, providing updates at each stage so users can understand progress and estimate when they will receive BTC.
diff --git a/docs/learn/sbtc/security-model-of-sbtc/README.md b/docs/learn/sbtc/security-model-of-sbtc/README.md
new file mode 100644
index 0000000000..21a198de16
--- /dev/null
+++ b/docs/learn/sbtc/security-model-of-sbtc/README.md
@@ -0,0 +1,52 @@
+---
+description: Explaining the security model of sBTC
+---
+
+# Security Model of sBTC
+
+### sBTC Security: A Multi-layered Approach
+
+Security is the foundation of this rollout. Partnerships with top-tier security experts have been established to ensure the protocol is fortified at every level:
+
+1. **Asymmetric Research**: Known for their rigorous research and top embedded security researchers, Asymmetric brings security expertise to sBTC to identify and mitigate potential vulnerabilities.
+2. **ImmuneFi**: A robust bug bounty program incentivizes ethical hackers to uncover and address potential issues, adding an additional layer of defense. ImmuneFi is the [leading crowdsource bounty platform for DeFi](https://stacks.org/best-and-brightest-sbtc#immunefi).
+3. **3rd Party Audits**: Independent audit reports have been made for additional security reviews, ensuring the protocol is thoroughly vetted by external experts.
+
+### The components that make up the security model of sBTC
+
+#### **sBTC Signer Network**
+
+The sBTC Signer network is a decentralized group of entities responsible for managing the locking and unlocking of BTC during the minting and redemption of sBTC. This network operates in a distributed manner to enhance security and reduce the risks associated with centralized custodians.
+
+Signers are responsible for approving all sBTC deposit and withdrawal operations, ensuring the integrity of the system. With a requirement of 70% consensus for transaction approval, Signers maintain the protocol's liveness and security.\
+\
+As approved by the Stacks community via [SIP-028](https://github.com/stacksgov/sips/blob/69d40a5f4f0ad98eb448ba44e7c31ca054820aa3/sips/sip-028/sip-028-sbtc_peg.md), the criteria for selecting signers include technical expertise, reliability, performance, and decentralization. An initial set of 15 institutional Signers will be used in Phase 1 to maintain simplicity and minimize operational risks. This group will grow as the protocol evolves.\
+\
+As sBTC evolves, the Signer set will transition to a fully decentralized model, further strengthening the protocol's resilience.
+
+
+
+For more info on who the sBTC Signers are, check out this section on the Bitcoin L2 Labs website [here](https://bitcoinl2labs.com/sbtc-rollout#sbtc-signers).
+
+#### **Trust-Minimized Bridge Model**
+
+The trust-minimized bridge model for sBTC ensures that the exchange between BTC and sBTC happens without relying on a single entity. Instead, it leverages cryptographic proofs and smart contracts on the Stacks blockchain, allowing for secure and transparent conversion processes.
+
+The permissionless nature of the sBTC model empowers Bitcoin holders to freely peg their BTC into sBTC and vice versa. This process utilizes a decentralized network of Signers along with smart contracts, eliminating the need for centralized custody or intermediaries. Bitcoin holders initiate a peg by sending BTC to a predetermined address, automatically triggering the issuance of an equivalent amount of sBTC on the Stacks blockchain. Similarly, holders can burn their sBTC, prompting the smart contracts to release BTC back to their control. This model enhances user autonomy and aligns with the decentralized ethos of Bitcoin.
+
+#### **Bitcoin Finality and Stacks**
+
+Stacks' Bitcoin Finality mechanism aligns sBTC's security closely with Bitcoin itself. By anchoring blocks and transactions to the Bitcoin blockchain, this ensures that the finality and security of asset holdings on Stacks are as robust as those on the Bitcoin network. This integration helps maintain trust and stability for sBTC within the broader Bitcoin ecosystem.
+
+### How sBTC's security contrasts with other wrapped Bitcoin alternatives
+
+While the sBTC model leverages decentralization to minimize trust, other wrapped Bitcoin solutions often face centralization risks. Typically, these alternatives rely on a centralized custodian to hold the underlying BTC, introducing a significant point of failure. Such custodians act as the trust anchor in the conversion process, which can potentially lead to issues such as censorship, mismanagement, or even security breaches. As a result, these models may not fully align with the decentralized principles of Bitcoin, posing challenges to the security and autonomy intended for Bitcoin holders.
+
+
+
+***
+
+#### Resources
+
+* \[[Stacks Roadmap](https://stacksroadmap.com/#sbtc)] Upcoming technical advancements and security designs for sBTC
+* \[[Hiro Blog](https://www.hiro.so/blog/sbtc-vs-wbtc-a-comparison-of-tokenized-bitcoin)] sBTC vs WBTC: A Comparison of Tokenized Bitcoin
diff --git a/docs/learn/sbtc/security-model-of-sbtc/sbtc-audits.md b/docs/learn/sbtc/security-model-of-sbtc/sbtc-audits.md
new file mode 100644
index 0000000000..c50fc22b4a
--- /dev/null
+++ b/docs/learn/sbtc/security-model-of-sbtc/sbtc-audits.md
@@ -0,0 +1,22 @@
+# sBTC Audits
+
+Several third-party security audits have been conducted on the sBTC protocol and can be referenced here.
+
+### Ottersec Audit Reports
+
+{% file src="../../.gitbook/assets/Ottersec - WSTS (1).pdf" %}
+
+{% file src="../../.gitbook/assets/Ottersec - sBTC Withdrawal (1).pdf" %}
+
+### Immunefi Audit Reports
+
+* [https://reports.immunefi.com/stacks-i-attackathon](https://reports.immunefi.com/stacks-i-attackathon)
+* [https://reports.immunefi.com/stacks-ii-attackathon](https://reports.immunefi.com/stacks-ii-attackathon)
+
+### CoinFabrik Audit Reports
+
+{% file src="../../.gitbook/assets/CoinFabrik_WSTS (1).pdf" %}
+
+### Clarity Alliance Audit Reports
+
+{% file src="../../.gitbook/assets/Clarity Alliance - sBTC (1).pdf" %}
diff --git a/docs/learn/sbtc/using-the-sbtc-bridge-app/README.md b/docs/learn/sbtc/using-the-sbtc-bridge-app/README.md
new file mode 100644
index 0000000000..31f495625d
--- /dev/null
+++ b/docs/learn/sbtc/using-the-sbtc-bridge-app/README.md
@@ -0,0 +1,21 @@
+---
+description: >-
+ Start bridging over your BTC into sBTC on Stacks with the official sBTC Bridge
+ app.
+---
+
+# Using the sBTC Bridge App
+
+
+
+The purpose of the user-facing sBTC Bridge app is to facilitate seamless and secure conversion between BTC and sBTC. You can deposit (peg-in) your BTC into sBTC. Or you can withdraw (peg-out) your sBTC back into BTC. The app also provides an intuitive interface for safely managing the history of your transactions.
+
+{% hint style="info" %}
+The official sBTC Bridge app is found at [https://sbtc.stacks.co/](https://sbtc.stacks.co/)
+{% endhint %}
+
+Refer to the following guides below to learn how you can securely convert your BTC into sBTC.
+
+* [How to Use the sBTC Bridge with Xverse/Leather](how-to-use-the-sbtc-bridge.md)
+* [How to Use the sBTC Bridge with Fordefi](how-to-use-the-sbtc-bridge-with-fordefi.md)
+* [How to Use the sBTC Bridge with Asigna](how-to-use-the-sbtc-bridge-with-asigna.md)
diff --git a/docs/learn/sbtc/using-the-sbtc-bridge-app/how-to-use-the-sbtc-bridge-with-asigna.md b/docs/learn/sbtc/using-the-sbtc-bridge-app/how-to-use-the-sbtc-bridge-with-asigna.md
new file mode 100644
index 0000000000..9f7cbba6fb
--- /dev/null
+++ b/docs/learn/sbtc/using-the-sbtc-bridge-app/how-to-use-the-sbtc-bridge-with-asigna.md
@@ -0,0 +1,128 @@
+# How to Use the sBTC Bridge with Asigna
+
+{% hint style="warning" %}
+This guide is specifically for entities or teams that use [Asigna](https://www.asigna.io/) as it will demonstrate the flow for a multi-signature setup. This assumes you have the Asigna web wallet setup with its browser extension.
+{% endhint %}
+
+The sBTC Bridge is a web application allowing you to convert your BTC into sBTC on the Stacks chain. If you aren't familiar with sBTC, be sure to check out the [sBTC Conceptual Guide](../) to understand how it works.
+
+{% hint style="danger" %}
+Asigna has the sBTC Bridge as an embedded app within its web wallet. This guide will be using that embedded app.
+{% endhint %}
+
+The sBTC Bridge has been designed to be as simple as possible to use. But specifically for this guide, a **2-of-2 multi-signature setup of a Bitcoin vault AND a separate Stacks vault**. It is assumed you have a similar setup as this guide will walkthrough the different steps needed to take in such a scenario where 2 parties of this 2-of-2 multi-signature setup need to sign transactions.
+
+### Walkthrough for minting sBTC
+
+Here are the necessary steps to convert your BTC to sBTC using Asigna:
+
+{% stepper %}
+{% step %}
+**Confirm your BTC and STX vaults**
+
+First, you'll need to make sure you have a vault for Bitcoin, and a separate vault for Stacks. In this scenario, the same 2-of-2 signature setup are applied for both vaults. Throughout the guide, we'll refer to each party of this setup as Member\_1 and Member\_2.
+
+Member_2's POV of both its Bitcoin vault and Stacks vault setup.
+{% endstep %}
+
+{% step %}
+**Navigate and open the embedded sBTC Bridge app in Bitcoin vault**
+
+Click into the Bitcoin vault and scroll down to the 'Trending Apps' section where you'll locate the sBTC Bridge embedded app. Open this embedded app and choose the 'Asigna Multisig' wallet to connect with.
+
+Locate the sBTC Bridge embedded app and open it.
+
+Connect with the Asigna Multisig wallet option. This app will auto connect with the Bitcoin vault that is being using in this context of the embedded app. You won't need to connect to a Stacks vault but you will need a Stacks vault address to use as the receiving address of the minted sBTC.
+{% endstep %}
+
+{% step %}
+**Choose the amount of BTC to deposit**
+
+After your Bitcoin vault is connected, choose how much BTC you would like to convert to sBTC.
+
+{% hint style="info" %}
+There are two transaction fees required to mint your sBTC. The first is when they initiate the bitcoin deposit transaction within their wallet. The second is a fee used to consolidate the deposit UTXOs into the single Signer's UTXO. This separate transaction fee happens automatically and is set to a max of 80k sats. This is automatically deducted from your minted sBTC. This is not a Signer fee but a regular bitcoin transaction fee.
+{% endhint %}
+
+Currently the minimum to peg-in is 0.001 BTC.
+{% endstep %}
+
+{% step %}
+**Choose the Stacks address from the Stacks vault**
+
+Next, enter the Stacks address you would like your sBTC minted to. For this guide, we'll be using the Stacks address of the Stacks vault that is assumed to be setup by both Member\_1 and Member\_2.
+
+Copy the multi-signature Stacks address from the Stacks vault setup.
+
+Review the inputted STX address, hit 'NEXT', and then 'CONFIRM'.
+{% endstep %}
+
+{% step %}
+**Select Fee Rate**
+
+Depending on congestion of the Bitcoin network, choose the appropriate fee rate based on your vault's preferences for timely confirmation.
+
+
+{% endstep %}
+
+{% step %}
+**Confirm the transaction creation**
+
+Whomever member, of the 2-of-2 multi-signature setup, is currently acting as the context of the sBTC Bridge embedded app, a popup modal of that member's wallet will appear for confirmation. In this guide, is it Member\_1 that is acting as the context and is currently connected with the Bitcoin vault using Xverse. Therefore, the Xverse wallet popup will appear for confirmation.
+
+Remember, this transaction is the initial peg-in transfer for your BTC to the sBTC Signers.
+
+{% hint style="info" %}
+If you have a multi-signature setup with certain signatures required, hitting 'Confirm' will not broadcast the bitcoin transaction, it will simply store this partially signed transaction in your Bitcoin vault until all required signatures are met.
+{% endhint %}
+
+Review the transaction and hit confirm to create the partially signed bitcoin transaction where it will be waiting for the other members to sign in their respective Asigna Bitcoin vaults.
+{% endstep %}
+
+{% step %}
+**Sign and approve transaction by other members**
+
+Upon notice of transaction to the other members of the multi-signature setup, each necessary member will need to approve the pending transaction in their own respective Asigna Bitcoin vaults.
+
+In our case, Member\_2 will navigate to their own Bitcoin vault and find the pending partially signed bitcoin transaction waiting for signature.
+
+Member_2 will locate the pending transaction and complete signature as their approval.
+
+Member_2 will see their connected wallet, in this case Leather, popup for them to confirm transaction.
+{% endstep %}
+
+{% step %}
+**Broadcasting of transaction**
+
+Once all transaction policies are satisfied and approved, the sBTC Bridge embedded app will appear with a prompt confirming that all signatures have been gathered successfully which will then automatically prompt the broadcasting of the transaction.
+
+Great! All signatures have been gathered for the transaction to be broadcasted.
+{% endstep %}
+
+{% step %}
+**Receive your sBTC**
+
+Back in the sBTC Bridge app UI, you can monitor the status of your transaction to see when it has been completed, at which point you can see the sBTC in your Fordefi wallet. It will go through three stages:
+
+* Pending - Your [Bitcoin transaction](https://mempool.space/tx/838ebd2c78091ca805ff00c2a2182d2e9c652bd9b43ef286c3af33d1a414f587) is processing
+* Minting - Your Bitcoin transaction has processed and the [sBTC signers are minting](https://explorer.hiro.so/txid/fef3dd3f6d4e6c89f3482fdec3816822261f29739ee81d1af6deb01d11e43961?chain=mainnet) your sBTC
+* Completed - Your sBTC has been minted to your Asigna Stacks vault wallet
+
+The bitcoin and subsequent sBTC mint transaction will take some time to be completely processed by the Signers
+
+Once both the bitcoin and sBTC mint transactions are confirmed, the sBTC Bridge app will show a 'Completed' status
+
+You'll then be able to see the sBTC balance in your Asigna Stacks vault.
+{% endstep %}
+{% endstepper %}
+
+### Reclaiming BTC
+
+If your sBTC mint fails, you can reclaim your sBTC. You can do this via the bridge by visiting the reclaim page at https://sbtc.stacks.co/\/reclaim and replacing the bracketed text with your transaction ID as shown below:\
+[https://sbtc.stacks.co/8f37f750b6646f0a217121201967170bd3cfef5f2ebd4f30f359b5e9308470c4/reclaim](https://sbtc.stacks.co/8f37f750b6646f0a217121201967170bd3cfef5f2ebd4f30f359b5e9308470c4/reclaim)
+
+There is an intermediate step in between depositing BTC and the sBTC signers consolidating it into the single signer UTXO. If the transaction is not picked up by signers, you can reclaim it using this UI. Note there is a 'Lock Time' field on the Reclaim page. That indicates the amount of blocks that must have passed in order to reclaim your BTC.
+
+
+
+This initiates a Bitcoin transaction that will transfer your BTC back to you.
diff --git a/docs/learn/sbtc/using-the-sbtc-bridge-app/how-to-use-the-sbtc-bridge-with-fordefi.md b/docs/learn/sbtc/using-the-sbtc-bridge-app/how-to-use-the-sbtc-bridge-with-fordefi.md
new file mode 100644
index 0000000000..cdf14b1e7b
--- /dev/null
+++ b/docs/learn/sbtc/using-the-sbtc-bridge-app/how-to-use-the-sbtc-bridge-with-fordefi.md
@@ -0,0 +1,130 @@
+# How to Use the sBTC Bridge with Fordefi
+
+{% hint style="warning" %}
+This guide is specifically for entities or teams that use [Fordefi](https://fordefi.com/) as it will demonstrate the flow for a multi-approval transaction policy setup. This assumes you have the Fordefi wallet setup with its browser extension and with its mobile app.
+{% endhint %}
+
+The sBTC Bridge is a web application allowing you to convert your BTC into sBTC on the Stacks chain. If you aren't familiar with sBTC, be sure to check out the [sBTC Conceptual Guide](../) to understand how it works.
+
+{% hint style="danger" %}
+Ensure that you are using the bridge located at [sbtc.stacks.co](https://sbtc.stacks.co/). This is the only official sBTC bridge.
+{% endhint %}
+
+The sBTC Bridge has been designed to be as simple as possible to use. But specifically for this guide, a **2-of-2 approval transaction policy**, targeting Bitcoin transactions, has already been setup in the Fordefi UI. It is assumed you have a similar setup as this guide will walkthrough the different steps needed to take in such a scenario where multiple parties need to approve a transaction.
+
+If you need assistance in setting up such a transaction policy in Fordefi, check out their dedicated [docs](https://docs.fordefi.com/user-guide/policies).
+
+### Walkthrough for minting sBTC
+
+Here are the necessary steps to convert your BTC to sBTC using Fordefi:
+
+{% stepper %}
+{% step %}
+**Confirm your BTC and STX vaults**
+
+First, you'll need to make sure you have a vault for Bitcoin, and a separate vault for Stacks. Both of these vaults will be used later when connecting with the sBTC Bridge app.
+
+A vault for native Bitcoin assets
+
+A vault for native Stacks assets
+{% endstep %}
+
+{% step %}
+**Connect your Fordefi wallet extension**
+
+First, you'll need to connect your Fordefi wallet to the sBTC Bridge app.
+
+Choose the option for Fordefi in the wallet selector modal
+{% endstep %}
+
+{% step %}
+**Choose which Bitcoin and Stacks vault you want to use**
+
+Next, the Fordefi extension will want you to select which Bitcoin vault, and then which Stacks vault you'd want to use. The reasoning for this is because you'll be needing to send a bitcoin transaction first from your Bitcoin vault, then you'll be receiving sBTC to your Stacks vault.
+
+The selected Bitcoin vault needs to have at least the minimum required amount (0.001 BTC) of bitcoin to peg-in
+
+When both vaults are selected, you'll be able to see both at the top of the Fordefi extension when connected
+{% endstep %}
+
+{% step %}
+**Choose the amount of BTC to deposit**
+
+After your wallet is connected, choose how much BTC you would like to convert to sBTC.
+
+{% hint style="info" %}
+There are two transaction fees required to mint your sBTC. The first is when they initiate the bitcoin deposit transaction within their wallet. The second is a fee used to consolidate the deposit UTXOs into the single Signer's UTXO. This separate transaction fee happens automatically and is set to a max of 80k sats. This is automatically deducted from your minted sBTC. This is not a Signer fee but a regular bitcoin transaction fee.
+{% endhint %}
+
+
+{% endstep %}
+
+{% step %}
+**Choose the Stacks address to mint the sBTC to**
+
+Next, enter the Stacks address you would like your sBTC minted to. This will just be the Stacks address associated with the Stacks vault that you selected earlier when connecting your Fordefi wallet extension.
+
+Review the inputted STX address and then confirm
+{% endstep %}
+
+{% step %}
+**Create initial BTC transfer**
+
+Your Fordefi wallet extension will pop up prompting you to create the BTC transaction. This transaction is the initial peg-in transfer for your BTC to the sBTC Signers. Hit 'Create' after you confirm the transaction details and necessary approval details.
+
+{% hint style="info" %}
+If you have a transaction policy setup with certain approvals required, hitting 'Create' will not initiate the bitcoin transaction, it will simply store this unsigned transaction in your Fordefi wallet until all necessary approvals are met and then finally signed.
+{% endhint %}
+
+You'll notice near the bottom of the Create Transaction view of the Fordefi extension is the required approval details. Be certain the other approvers are available to approve the transaction in a timely manner.
+
+If you ever navigate back to your Fordefi web UI or extension UI, you'll notice this transaction will be marked as 'Pending approval'.
+{% endstep %}
+
+{% step %}
+**Approve transaction by approvers**
+
+Upon notice of transaction to approvers, each approver will need to approve transaction in their Fordefi mobile wallets before the completion of the final step, which is signing the transaction by the initiator.
+
+Each approver will need to pull up the pending transaction in their Fordefi mobile wallet and hit 'Approve'.
+
+POV of approving transaction by approver
+{% endstep %}
+
+{% step %}
+**Sign approved transaction**
+
+Once all transaction policies are satisfied and approved, the initiator will need to officially sign the transaction in their Fordefi mobile wallet.
+
+This mobile signature action will then notify the sBTC Bridge app.
+
+The initiator will need to hit 'Sign' once approvals and transaction details are confirmed
+{% endstep %}
+
+{% step %}
+**Receive your sBTC**
+
+Back in the sBTC Bridge app UI, you can monitor the status of your transaction to see when it has been completed, at which point you can see the sBTC in your Fordefi wallet. It will go through three stages:
+
+* Pending - Your [Bitcoin transaction](https://mempool.space/tx/6b5e63fbe4e4a4835dcf096ca2d2a8c112898692e28a4c5b38cb39e3e9837604) is processing
+* Minting - Your Bitcoin transaction has processed and the [sBTC signers are minting](https://explorer.hiro.so/txid/a9e232289d2c6e50150b034894182d341343e7064b27c8dccbd25ebca79b2947?chain=mainnet) your sBTC
+* Completed - Your sBTC has been minted to your wallet
+
+The bitcoin and sBTC transactions will take some time to be completely processed by the Signers
+
+Once both the bitcoin and sBTC mint transactions are confirmed, the sBTC Bridge app will show a 'Complete' status
+
+You'll be able to see the results of these transactions in your Fordefi wallet
+{% endstep %}
+{% endstepper %}
+
+### Reclaiming BTC
+
+If your sBTC mint fails, you can reclaim your sBTC. You can do this via the bridge by visiting the reclaim page at https://sbtc.stacks.co/\/reclaim and replacing the bracketed text with your transaction ID as shown below:\
+[https://sbtc.stacks.co/8f37f750b6646f0a217121201967170bd3cfef5f2ebd4f30f359b5e9308470c4/reclaim](https://sbtc.stacks.co/8f37f750b6646f0a217121201967170bd3cfef5f2ebd4f30f359b5e9308470c4/reclaim)
+
+There is an intermediate step in between depositing BTC and the sBTC signers consolidating it into the single signer UTXO. If the transaction is not picked up by signers, you can reclaim it using this UI. Note there is a 'Lock Time' field on the Reclaim page. That indicates the amount of blocks that must have passed in order to reclaim your BTC.
+
+
+
+This initiates a Bitcoin transaction that will transfer your BTC back to you.
diff --git a/docs/learn/sbtc/using-the-sbtc-bridge-app/how-to-use-the-sbtc-bridge.md b/docs/learn/sbtc/using-the-sbtc-bridge-app/how-to-use-the-sbtc-bridge.md
new file mode 100644
index 0000000000..8f854f10d8
--- /dev/null
+++ b/docs/learn/sbtc/using-the-sbtc-bridge-app/how-to-use-the-sbtc-bridge.md
@@ -0,0 +1,83 @@
+# How to Use the sBTC Bridge with Xverse/Leather
+
+The sBTC bridge is a web application allowing you to convert your BTC into sBTC on the Stacks chain.
+
+{% hint style="danger" %}
+Ensure that you are using the bridge located at [sbtc.stacks.co](https://sbtc.stacks.co/). This is the only official sBTC bridge.
+{% endhint %}
+
+If you aren't familiar with sBTC, be sure to check out the [sBTC Conceptual Guide](../) to understand how it works.
+
+The bridge has been designed to be as simple as possible to use. In order to utilize sBTC, all you need to do is send a Bitcoin transaction using a supported wallet (like [Leather](https://leather.io/) or [Xverse](https://www.xverse.app/)). This guide will show screenshots of Xverse but the flow is the same if using Leather as well.
+
+Below you'll find both a video and written walkthrough of using the bridge.
+
+### Video Walkthrough
+
+{% embed url="https://youtu.be/XZruuDgTo4k" %}
+
+### Written Walkthrough
+
+There are 5 simple steps to convert your BTC to sBTC.
+
+{% stepper %}
+{% step %}
+**Connect your wallet**
+
+First, you'll need to connect your wallet to the bridge UI. Currently Leather and Xverse are supported, with more on the way.
+
+
+{% endstep %}
+
+{% step %}
+**Choose the amount to deposit**
+
+After your wallet is connected, choose how much BTC you would like to convert to sBTC.
+
+
+
+{% hint style="info" %}
+There are two transaction fees required to mint your sBTC. The first is set by the user manually when they initiate the deposit transaction within their wallet. The second is a fee used to consolidate the deposit UTXOs into the single signer UTXO. This separate transaction fee happens automatically and is set to a max of 80k sats. This is automatically deducted from your minted sBTC. This is not a signer fee but a regular Bitcoin transaction fee.
+{% endhint %}
+{% endstep %}
+
+{% step %}
+**Choose the Stacks address to mint to**
+
+Next, enter the Stacks address you would like your sBTC minted to.
+
+
+{% endstep %}
+
+{% step %}
+**Initiate the transaction**
+
+After you choose your Stacks address, you'll use your connected wallet to transfer the BTC.
+
+
+{% endstep %}
+
+{% step %}
+**Receive your sBTC**
+
+In the UI, you can monitor the status of your transaction to see when it has been completed, at which point you can see the sBTC in your wallet. It will go through three stages:
+
+* Pending - Your Bitcoin transaction is processing
+* Minting - Your Bitcoin transaction has processed and the sBTC signers are minting your sBTC
+* Completed - Your sBTC has been minted to your wallet
+
+Note that you may need to enable the display of the sBTC token within your wallet by clicking on 'Manage Tokens' and enabling sBTC.
+
+
+{% endstep %}
+{% endstepper %}
+
+### Reclaiming BTC
+
+If your sBTC mint fails, you can reclaim your sBTC. You can do this via the bridge by visiting the reclaim page at https://sbtc.stacks.co/\/reclaim and replacing the bracketed text with your transaction ID, eg. [https://sbtc.stacks.co/8f37f750b6646f0a217121201967170bd3cfef5f2ebd4f30f359b5e9308470c4/reclaim](https://sbtc.stacks.co/8f37f750b6646f0a217121201967170bd3cfef5f2ebd4f30f359b5e9308470c4/reclaim)
+
+There is an intermediate step in between depositing BTC and the sBTC signers consolidating it into the single signer UTXO. If the transaction is not picked up by signers, you can reclaim it using this UI. Note there is a 'Lock Time' field on the Reclaim page. That indicates the amount of blocks that must have passed in order to reclaim your BTC.
+
+
+
+This initiates a Bitcoin transaction that will transfer your BTC back to you.
diff --git a/docs/learn/sbtc/walkthroughs/README.md b/docs/learn/sbtc/walkthroughs/README.md
new file mode 100644
index 0000000000..b3862d07e7
--- /dev/null
+++ b/docs/learn/sbtc/walkthroughs/README.md
@@ -0,0 +1,5 @@
+# Walkthroughs
+
+These walkthroughs describe at a high level exactly how users and signers can expect to interact with the sBTC system.
+
+Read these to get a firm understanding of what is actually happening under the hood of the sBTC system.
diff --git a/docs/learn/sbtc/walkthroughs/sbtc-transaction-walkthrough.md b/docs/learn/sbtc/walkthroughs/sbtc-transaction-walkthrough.md
new file mode 100644
index 0000000000..7e9dff979b
--- /dev/null
+++ b/docs/learn/sbtc/walkthroughs/sbtc-transaction-walkthrough.md
@@ -0,0 +1,145 @@
+# sBTC Transaction Walkthrough
+
+Let's follow the journey of 1 BTC as it moves through the sBTC system, from initial deposit to final withdrawal.
+
+## Part 1: Deposit (BTC → sBTC)
+
+{% stepper %}
+{% step %}
+#### Initiation
+
+* Alice decides to convert 1 BTC to sBTC to participate in Stacks DeFi.
+* Alice creates a deposit transaction on the Bitcoin network (typically via a UI such as the sBTC bridge or a DeFi application).
+* The transaction enters the Bitcoin mempool.
+{% endstep %}
+
+{% step %}
+#### Proof Submission
+
+* Alice submits proof of her deposit to the Deposit API (usually via the application's UI).
+* The Deposit API sets the deposit status to PENDING.
+{% endstep %}
+
+{% step %}
+#### Signer Validation
+
+The sBTC Signer Set:
+
+* Detects the deposit.
+* Validates the UTXO format.
+* Votes on the deposit.
+
+If the deposit is rejected:
+
+* Signers notify the API of the rejection.
+* The Deposit API updates the status to FAILED.
+
+If the deposit is accepted:
+
+* The Deposit API updates the status to ACCEPTED.
+{% endstep %}
+
+{% step %}
+#### Bitcoin Transaction
+
+If accepted, the sBTC Signer Set:
+
+* Creates a new Bitcoin transaction consuming Alice's deposited BTC.
+* Broadcasts this transaction to the Bitcoin network.
+
+If this transaction fails:
+
+* Signers notify the API of the failure.
+* The Deposit API updates the status to FAILED.
+{% endstep %}
+
+{% step %}
+#### sBTC Minting
+
+Upon successful Bitcoin transaction:
+
+* The sBTC Signer Set interacts with the Stacks blockchain.
+* They fulfill the deposit by minting 1 sBTC to Alice's Stacks address.
+{% endstep %}
+
+{% step %}
+#### Confirmation
+
+* The Deposit API updates the deposit status to CONFIRMED.
+* Alice now has 1 sBTC in her Stacks wallet.
+{% endstep %}
+{% endstepper %}
+
+***
+
+## Part 2: sBTC Usage
+
+Alice can now use her 1 sBTC in the Stacks ecosystem:
+
+* Transfer it to other users via the `sbtc-token` contract (typically via an application UI).
+* Participate in DeFi applications.
+* Use it in any application that supports SIP-010 tokens.
+
+***
+
+## Part 3: Withdrawal (sBTC → BTC)
+
+{% stepper %}
+{% step %}
+#### Initiation
+
+* Alice initiates a withdrawal by interacting with the Clarity contract on the Stacks blockchain.
+* She specifies her Bitcoin address for the withdrawal.
+* If successful, the contract locks her sBTC and the withdrawal status is set to PENDING.
+* If the transaction fails, no withdrawal occurs.
+{% endstep %}
+
+{% step %}
+#### Signer Validation
+
+The sBTC Signer Set:
+
+* Detects the withdrawal request.
+* Decides whether to accept or reject the withdrawal.
+
+If the withdrawal is rejected:
+
+* Signers unlock the sBTC.
+* The withdrawal status is updated to FAILED.
+
+If the withdrawal is accepted:
+
+* The withdrawal status is updated to ACCEPTED.
+* Signers wait for 6 Bitcoin block confirmations (for security purposes).
+{% endstep %}
+
+{% step %}
+#### Bitcoin Transaction
+
+After the waiting period, if accepted:
+
+* The sBTC Signer Set creates a new Bitcoin transaction fulfilling Alice's withdrawal.
+* They broadcast this transaction to the Bitcoin network.
+
+If this transaction fails:
+
+* Signers unlock the sBTC.
+* The withdrawal status is updated to FAILED.
+{% endstep %}
+
+{% step %}
+#### sBTC Burning and Confirmation
+
+Upon successful Bitcoin transaction:
+
+* The sBTC Signer Set burns the locked 1 sBTC on the Stacks blockchain.
+* The withdrawal status is updated to CONFIRMED.
+{% endstep %}
+
+{% step %}
+#### Completion
+
+* Alice now has her 1 BTC back in her specified Bitcoin address.
+* The withdrawn sBTC has been permanently removed from circulation.
+{% endstep %}
+{% endstepper %}
diff --git a/docs/learn/sbtc/walkthroughs/signer-process-walkthrough.md b/docs/learn/sbtc/walkthroughs/signer-process-walkthrough.md
new file mode 100644
index 0000000000..b4bfeab4cf
--- /dev/null
+++ b/docs/learn/sbtc/walkthroughs/signer-process-walkthrough.md
@@ -0,0 +1,76 @@
+# Signer Process Walkthrough
+
+## Introduction
+
+This document provides a detailed overview of the sBTC system, focusing on the operations of an sBTC signer node. We'll explore the automated processes and software interactions that occur in the sBTC ecosystem.
+
+A step-by-step guide for setting up and running a sBTC signer node is in the works. This is a conceptual guide to help signers understand what their role looks like in the sBTC system.
+
+## Signer Node Setup
+
+As an sBTC signer, your primary responsibility is to run and maintain a signer node. Here's what that entails:
+
+{% stepper %}
+{% step %}
+#### Hardware setup
+
+Ensure your node has sufficient computational power and storage.
+{% endstep %}
+
+{% step %}
+#### Software installation
+
+Install the sBTC signer node software and its dependencies.
+{% endstep %}
+
+{% step %}
+#### Key management
+
+The node software securely generates and stores the Bitcoin private key and corresponding public key.
+{% endstep %}
+
+{% step %}
+#### Node registration
+
+Upon first run, the node automatically registers its public key with the sBTC Registry contract on the Stacks blockchain.
+{% endstep %}
+{% endstepper %}
+
+## Day-to-Day Operations
+
+Once set up, your signer node operates autonomously, performing the following tasks:
+
+{% stepper %}
+{% step %}
+#### Monitoring Deposit Requests
+
+Your node continuously monitors for sBTC minting requests:
+
+* The node connects to the Bitcoin network and the Stacks blockchain.
+* It watches for Bitcoin transactions sent to the sBTC UTXO address.
+* When a deposit is detected, the node verifies the transaction details.
+{% endstep %}
+
+{% step %}
+#### Processing Mint Requests
+
+Upon confirming a deposit:
+
+* The node automatically prepares a signature for the mint operation using its private key.
+* It submits this signature to the sBTC Deposit contract on the Stacks blockchain.
+* The contract verifies the signature and combines it with signatures from other signer nodes.
+* Once enough valid signatures are collected, the contract mints the corresponding amount of sBTC.
+{% endstep %}
+
+{% step %}
+#### Handling Withdrawal Requests
+
+For sBTC withdrawal requests:
+
+* The node monitors the sBTC Withdrawal contract for new requests.
+* Upon detecting a request, it verifies the user's sBTC balance and the request's validity.
+* The node automatically signs the withdrawal operation and submits its signature.
+* Once enough signatures are collected and the sBTC is burned, the node participates in creating and signing a Bitcoin transaction to fulfill the withdrawal.
+* The signed Bitcoin transaction is broadcast to the Bitcoin network.
+{% endstep %}
+{% endstepper %}
diff --git a/docs/learn/stacks-101/README.md b/docs/learn/stacks-101/README.md
new file mode 100644
index 0000000000..22bd03150b
--- /dev/null
+++ b/docs/learn/stacks-101/README.md
@@ -0,0 +1,7 @@
+# Stacks 101
+
+Stacks has a very unique technical model in the blockchain world. This section will help you get a high-level overview of the essential components to understand how Stacks works.
+
+We'll cover the basics of what Stacks is and how it works from both a philosophical and technical level, and you can dive into the further sections for more details.
+
+First up, let's get an overview of exactly what Stacks is.
diff --git a/docs/learn/stacks-101/bitcoin-connection.md b/docs/learn/stacks-101/bitcoin-connection.md
new file mode 100644
index 0000000000..e1032d52d8
--- /dev/null
+++ b/docs/learn/stacks-101/bitcoin-connection.md
@@ -0,0 +1,165 @@
+# The Bitcoin Connection
+
+
+
+In the previous section, we described Stacks as bringing smart contract functionality to Bitcoin, without modifying Bitcoin itself, and explained a bit about how the chain works.
+
+That's a big promise, but how does Stacks actually deliver on it? And what makes Stacks unique among other Bitcoin layers and other blockchains like Ethereum?
+
+Before we get into the technical details of how Stacks works, it's important to get a high-level overview of the problem it's solving and how it actually does that. We'll dive deeper into some of these topics as we go through the docs, but it's good to get a high-level picture to bring everything together.
+
+This topic is a bit of a rabbit hole, and this section is pretty long, but it will give you an in-depth understanding of exactly the problem Stacks is looking to solve, and how it solves it.
+
+Let's get into it.
+
+### Is Stacks a Bitcoin L2?
+
+Stacks is a Bitcoin layer for smart contracts. The classification as a layer-1 (L1) or layer-2 (L2) or sidechain really depends on the definition used. With that said, generally speaking L1 chains are sovereign meaning that (a) they have their own security budget, and (b) they can survive without the need for any other L1 chain. L2 chains typically do not have their own security budget and share the security of the underlying L1 chain, and they cannot live without the underlying L1 chain. There are many different design mechanisms that L2s can use, and we cover several of them and how Stacks compares in the [Stacks Among Other Bitcoin Layers](stacks-among-other-layers.md) section.
+
+The initial release of Stacks in early 2021 had a separate security budget from Bitcoin L1. Even though the Stacks layer could not function without Bitcoin L1, the developers working on the project described it as a different system that does not fit neatly into existing classifications, sometimes using the term layer 1.5 (see [this Decrypt article](https://decrypt.co/82019/bitcoin-defi-thing-says-stacks-founder-muneeb-ali) for example).
+
+The upcoming planned release of Stacks, called the Nakamoto release, will no longer have a separate security budget from Bitcoin. Instead, a 100% of Bitcoin hashpower will determine finality on Stacks layer. After the next upgrade, to reorg Stacks blocks/transactions the attacker will need to reorg Bitcoin L1 itself (which is very hard to do and therefore a great security property for a Bitcoin layer to have). More details in the [Stacks paper](https://stacks.co/stacks.pdf).
+
+The definition of [L2 used in Ethereum](https://ethereum.org/en/layer-2/) and other newer ecosystems is different and focuses on the ability to withdraw assets using only L1 security and L1 miners. According to that definition Stacks layer is not a clear L2, given the set of peg-out signers determine if users can withdraw sBTC. Bitcoin cannot support such verification without changes to Bitcoin L1 (which may happen in the future). The Ethereum L2 definition also does not apply that cleanly to Bitcoin L2s, given new assets are issued on L2s when it comes to Bitcoin and not issued on L1 (only BTC is the L1 asset). Therefore, using the definition of security of withdrawing assets is not directly applicable given assets are defined and used on L2s and not withdrawn out to Bitcoin L1 anyway (with the exception of BTC itself). Rather, what becomes more important is "settlement on Bitcoin" i.e., is contract data and state secured by 100% of Bitcoin's hashpower or not.
+
+Remember that L2s on Bitcoin also have to serve the additional purpose of expanding both functionality and scalability, which means L2s accomplish fundamentally different goals depending on the functionality of the L1.
+
+Users and developers organically call Stacks a Bitcoin L2, since it is a simpler concept to understand. There are certain properties of Stacks layer that also help the concept of Stacks as a Bitcoin L2:
+
+{% stepper %}
+{% step %}
+**Bitcoin finality**
+
+100% of the Bitcoin hashpower decides block ordering and transaction finality.
+{% endstep %}
+
+{% step %}
+**Consensus runs on Bitcoin L1**
+
+Stacks consensus runs on Bitcoin L1, and Stacks L2 cannot operate or survive without Bitcoin L1.
+{% endstep %}
+
+{% step %}
+**sBTC and economic unit**
+
+With the upcoming decentralized Bitcoin peg, called sBTC, most of the economy on Stacks layer will likely use BTC as the unit of economy. It is expected that most users will simply use Bitcoin in wallets and apps and then peg out their BTC to Bitcoin L1.
+{% endstep %}
+
+{% step %}
+**Data hashed and stored on Bitcoin L1**
+
+All data and transactions on Stacks are automatically hashed and permanently stored on Bitcoin L1 on every Bitcoin block. Anyone can verify that some data on Stacks is valid by checking the corresponding hash on Bitcoin L1. This compact storage of hashes on L1 is somewhat similar to rollups (although there are other differences). You can read more about this process in the [Block Production](../block-production/) section.
+{% endstep %}
+
+{% step %}
+**Contracts can read Bitcoin L1**
+
+Contracts on Stacks layer can read Bitcoin L1 transactions and respond to them. Assets on Stacks layer can be moved simply through Bitcoin L1 transactions.
+{% endstep %}
+{% endstepper %}
+
+Given all the details above, why would some people think that Stacks is not a Bitcoin L2? There are a couple of reasons this question comes up often:
+
+{% stepper %}
+{% step %}
+**Old security-budget material**
+
+The initial version of Stacks (released early 2021) had a separate security budget which changed to following 100% Bitcoin hashpower with the Nakamoto release. There is old material and blog posts floating around that still talk about the initial Stacks version. The old materials will likely get updated with time.
+{% endstep %}
+
+{% step %}
+**Ethereum L2 withdrawal definition doesn't map cleanly**
+
+According to the Ethereum definition of L2s a user should be able to withdraw their base-layer assets purely by doing an L1 transaction and relying only on L1 security (this is true for Lightning for example). This definition does not apply cleanly to Bitcoin L2s because assets are not defined at Bitcoin L1 but are defined in L2s instead. The only asset where this matters is the pegged BTC asset from Bitcoin L1, given all other assets are native to L2s anyway. In the upcoming Stacks release, users can withdraw their BTC by sending just a Bitcoin L1 transaction but Bitcoin L1 cannot validate that complex transaction and a majority of peg-out signers will need to sign on the peg-out request. In an ideal world Bitcoin miners can validate such transactions but that would require a change to Bitcoin L1. Therefore, Stacks design optimizes for a method that is decentralized and can be deployed without any changes to Bitcoin L1. If in the future it is possible to make changes to Bitcoin L1 then Stacks layer security can benefit from that as well.
+{% endstep %}
+
+{% step %}
+**Healthy Bitcoin skepticism**
+
+Bitcoin community members are generally skeptical of claims and on the lookout for people making any false marketing claims. This is generally a healthy thing for the Bitcoin ecosystem and builds up the immune system. Some such community members might be skeptical about Stacks as a Bitcoin layer or L2 until they fully read the technical details and reasoning. There is a good [Twitter thread](https://twitter.com/lopp/status/1623756872976158722?s=20) about this topic as well.
+{% endstep %}
+{% endstepper %}
+
+Why don't we use the term 'sidechain' for Stacks then? Sidechains in Bitcoin typically have a different security budget from Bitcoin L1, typically as a subset of Bitcoin miners who participate in the sidechain (they don't follow 100% Bitcoin finality), their consensus runs on the sidechain (vs running on Bitcoin L1), and they don't publish their data/hashes on Bitcoin L1. The Stacks layer does not fit that definition cleanly given the consensus runs on Bitcoin L1, it follows Bitcoin finality, and publishes data/hashes on L1.
+
+Can Stacks layer work with rollups?
+
+Yes! There is already an active R\&D effort to integrate rollups with the Stacks layer. Both with the Stacks layer and sovereign rollups the technically challenging part is how to get BTC in and out of the Stacks layer or the sovereign rollup. The decentralized BTC peg, [sBTC](../sbtc/), applies to both the Stacks layer and sovereign rollups. Without modifying Bitcoin L1, an sBTC-like design with a decentralized open-membership group of signers is the most trust-minimized way to move BTC in and out of Bitcoin layers. Once the necessary upgrades to Bitcoin L1 can be made to enable validity rollups i.e., Bitcoin L1 can enforce BTC withdrawal from a layer, then the Stacks layer can also upgrade to benefit from it.
+
+Given a trust-minimized asset like sBTC is needed for sovereign rollups, with the launch of sBTC such sovereign rollups become even more interesting to deploy. The Stacks layer can potentially provide the decentralized group of signers for a trust-minimized BTC asset that can be used in a sovereign rollup, and DA comes directly from Bitcoin L1 e.g., with Ordinals.
+
+### Why Does Stacks Need a Token?
+
+This brings us to a central philosophical conversation in the world of crypto and Bitcoin, whether or not blockchains need tokens.
+
+Let's start by looking at the fundamental reason why tokens exist: to fund the maintenance and forward progress of a blockchain.
+
+Bitcoin is a token. It is a cryptocurrency that is used to incentivize miners to add new blocks to the chain. In Bitcoin's case, mining rewards are set on a predefined schedule, and once those mining rewards run out, the chain will need to survive on transaction fees alone.
+
+The purpose of a blockchain is to have a permanent historical record of every transaction that has ever occurred on the chain. Blockchains are basically ledgers. The token aspect is used as an incentive mechanism to secure and maintain the chain.
+
+This is why networks like Lightning and other P2P networks don't need tokens, they don't need to maintain a historical record. Channel-based solutions like Lightning rely on users opening 2-of-2 multisigs with each other. Once those channels are closed, the state disappears. When we are talking about a system that is supposed to maintain a global financial system, it is important for the maintenance of that system to be incentivized correctly.
+
+Let's look at this concept in the context of Stacks and its goals. Stacks seeks to provide smart contract functionality to Bitcoin, to serve as the programming rails for building a decentralized economy on top of Bitcoin.
+
+Many Bitcoin community members are skeptical of new tokens and rightly so. There are countless projects out there that force the use of a token on their project and in many cases a token is actually not needed. The Stacks project was started by Bitcoin builders who have a long history of building apps & protocols on Bitcoin L1 without any token (e.g., BNS launched in 2015 on Bitcoin L1 which was one of the largest protocols using OP\_RETURN on Bitcoin L1). So why did a bunch of Bitcoin builders decide to have a separate token for Stacks L2? Great question! Let's dig into the details.
+
+The Stacks token (STX) is primarily meant to be used for two things:
+
+{% stepper %}
+{% step %}
+**Incentives for Stacks L2 miners**
+
+Newly minted STX are used to incentivize decentralized block production on Stacks L2.
+{% endstep %}
+
+{% step %}
+**Incentives for peg-out signers**
+
+Signers participating in peg-out operations receive incentives in STX to economically align them with protocol rules.
+{% endstep %}
+{% endstepper %}
+
+The only way to remove the token is to build Stacks as a federated network like Liquid. In a federation the pre-selected group of companies control the mining and block production and a pre-selected group of companies need to be trusted for peg-out transactions.
+
+Stacks developers wanted to design an open and permissionless system. The only way to have a decentralized mining process is through incentives. As mentioned above, this is how Bitcoin works as well, where newly minted BTC are used as incentives to mine new blocks and anyone in the world can decide to become a miner. Anyone with BTC can mine the Stacks L2 chain, it is open and permissionless.
+
+Similarly, the way sBTC is designed is that the group of signers is open and permissionless (unlike a federation). These signers have economic incentives to correctly follow the protocol for peg-out requests. In a federation, users need to blindly trust the pre-set federation members to get their BTC out of the federation and back on Bitcoin L1. Stacks developers wanted to have an open, permissionless, and decentralized way to move BTC from Bitcoin L1 to Stacks L2 and back. This is made possible through economic incentives i.e., need for a token.
+
+{% hint style="info" %}
+With more and more Bitcoin layers emerging, there is some nuance in this federated vs open network design. Some protocols like Botanix's Spiderchain offer an open network but have different incentive mechanisms. We dig into these in detail in the [Stacks Among Other Layers](stacks-among-other-layers.md) section.
+{% endhint %}
+
+Other than these two reasons, STX is also used to pay gas fees for transactions. However, once the upcoming sBTC peg is live most of the economy of Stacks L2 is expected to follow a Bitcoin standard and work using BTC as the economic unit. It is expected that users will mostly interact just with Bitcoin and use BTC in wallets and apps (gas fees can be paid with BTC using atomic swaps in the background). It is important to note that BTC cannot be used for mining incentives on Stacks L2 because the only way to incentivize decentralized block production is through newly minted assets by the protocol (similar to how Bitcoin works itself) i.e., need for a token.
+
+### The Symbiotic Relationship Between Stacks and Bitcoin
+
+Stacks and Bitcoin complement each other. Stacks leverages the extreme decentralization of Bitcoin, its PoW consensus mechanism, and its value as a cryptocurrency.
+
+But Stacks also complements Bitcoin by unlocking additional use cases, thereby increasing its value over time. This also helps to solve the additional problem of the future maintainability of Bitcoin after the coinbase rewards are gone and Bitcoin has to function on transaction fees alone.
+
+If Bitcoin is seen as only a store of value, the economic density, meaning how much value is being exchanged, of each transaction will be minimal. But if Bitcoin is the underlying foundation for an entire decentralized economy, those [transactions become much more valuable](https://twitter.com/muneeb/status/1506976317618728963), increasing transaction fees. This is a crucial incentive for miners to continue securing the network as coinbase rewards drop.
+
+### Reading from Bitcoin State
+
+One of the things that gives the Stacks chain its superpowers in connecting with Bitcoin is not only how it connects to Bitcoin at a protocol level, discussed above, but also how we can utilize that Bitcoin at a programmatic level.
+
+That's where Clarity comes in. Clarity is the smart contract language for Stacks, and is how we actually build out a lot of the functionality we are talking about here.
+
+One of the often-touted features of Clarity is that it has access to the state of the Bitcoin chain built in, but how does it actually do that? Because of Stacks' PoX mechanism, every Stacks block is connected to a Bitcoin block, and can query Bitcoin block header hashes with the [`get-burn-block-info?` function](https://github.com/stacksgov/sips/blob/feat/sip-015/sips/sip-015/sip-015-network-upgrade.md#new-method-get-burn-block-info).
+
+This function allows us to pass in a Bitcoin block height and get back the header hash. The [`burn-block-height` Clarity keyword](https://docs.stacks.co/docs/write-smart-contracts/clarity-language/language-keywords#burn-block-height) will give us the current block height of the Bitcoin chain.
+
+However, `get-burn-block-info?` only returns data of the Bitcoin block at that height if it has already been processed and was created after the launch of the Stacks chain. So if we want to evaluate whether or not something happened on Bitcoin, we have to wait at least one block later to do so.
+
+This is step 1 of Clarity contracts being able to serve as the programming layer for Bitcoin. When a BTC transaction is initiated, the first thing that needs to happen is that a Clarity contract needs to become aware of it. This can happen manually by utilizing Clarity functions discussed above with the [BTC library](https://explorer.stacks.co/txid/0x8b112f2b50c1fa864997b7496aaad1e3940700309a3fdcc6c07f1c6f8b9cfb7b?chain=mainnet), as [Catamaran Swaps](https://docs.catamaranswaps.org/en/latest/catamaran.html) do.
+
+{% hint style="info" %}
+Note that this process is made easier by the additional Clarity functions added in 2.1, like the `get-burn-block-info?` function we looked at above.
+{% endhint %}
+
+Or we can automate (albeit at a cost of some centralization in our dapp) using an event-based architecture using something like Hiro's [chainhooks](https://www.hiro.so/blog/meet-4-new-features-in-clarinet#setting-up-trigger-actions-with-chainhooks), which will allow us to automatically trigger a Clarity contract call when a certain BTC transaction is initiated.
+
+This is the first component of using Stacks to build Bitcoin dapps, the read access to Bitcoin chain.
+
+Next up, let's dig a bit deeper into how exactly Stacks is "built on Bitcoin" by taking a look at Stacks' block production mechanism, Proof of Transfer.
diff --git a/docs/learn/stacks-101/financial-incentive-and-security-budget.md b/docs/learn/stacks-101/financial-incentive-and-security-budget.md
new file mode 100644
index 0000000000..1bd58537e1
--- /dev/null
+++ b/docs/learn/stacks-101/financial-incentive-and-security-budget.md
@@ -0,0 +1,11 @@
+# Financial Incentive And Security Budget
+
+image source: Hiro blog
+
+In order to reorg the Stacks chain, someone must take control of at least 70% of the STX that are currently Stacked and conduct a 51% attack on Bitcoin itself. If acquired at market prices, then at the time of this writing, that amounts to spending nearly $1 billion USD in only the STX stacked.
+
+In addition to this, because of how Stacks achieves Bitcoin finality by not allowing forks, Stacks security budget reaches 51% of Bitcoin's mining power because in order to reverse the chain state you would need to reverse the Bitcoin chain state as well.
+
+Stackers have the new-found power to sign blocks in order to append them to the Stacks chain. However, some of them could refuse to sign, and ensure that no block ever reaches the 70% signature threshold. While this can happen by accident, this is not economically rational behavior -- if they stall the chain for too long, their STX loses their value, and furthermore, they cannot re-stack or liquidate their STX or activate PoX to earn BTC. Also, miners will stop mining if no blocks are getting confirmed, which eliminates their ongoing PoX payouts.
+
+The technical details of how this all works are discussed in the [Block Production](../block-production/) section.
diff --git a/docs/learn/stacks-101/proof-of-transfer.md b/docs/learn/stacks-101/proof-of-transfer.md
new file mode 100644
index 0000000000..ff325fea74
--- /dev/null
+++ b/docs/learn/stacks-101/proof-of-transfer.md
@@ -0,0 +1,61 @@
+# Proof of Transfer (PoX)
+
+
+
+In the previous sections, we took a look at the vision and ethos of Stacks and talked a lot about it being connected to Bitcoin and how it enables expanding functio nality without modifying Bitcoin itself.
+
+In this section, we'll run through the block production mechanism that makes that happen, Proof of Transfer.
+
+This section will be a conceptual overview of Proof of Transfer. For more details on exactly how block production happens at a technical level, check out the section on [Block Production](../block-production/).
+
+Consensus algorithms for blockchains require compute or financial resources to secure the blockchain. The general practice of decentralized consensus is to make it practically infeasible for any single malicious actor to have enough computing power or ownership stake to attack the network.
+
+Popular consensus mechanisms in modern blockchains include proof of work, in which nodes dedicate computing resources, and proof of stake, in which nodes dedicate financial resources to secure the network.
+
+Proof of burn is another, less-frequently used consensus mechanism where miners compete by ‘burning’ (destroying) a proof of work cryptocurrency as a proxy for computing resources.
+
+Proof of Transfer (PoX) is an extension of the proof of burn mechanism. PoX uses the proof of work cryptocurrency of an established blockchain (Bitcoin in this case) to secure a new blockchain. However, unlike proof of burn, rather than burning the cryptocurrency, miners transfer the committed cryptocurrency to some other participants in the network (Stackers in this case).
+
+
+
+This allows network participants to secure the PoX cryptocurrency network and earn a reward in the base cryptocurrency (BTC). Thus, PoX blockchains are anchored on their chosen PoW chain. Stacks uses Bitcoin as its anchor chain.
+
+
+
+### Why Bitcoin?
+
+There are a number of reasons that Stacks chose Bitcoin as the blockchain to power consensus. It's the oldest blockchain protocol, having launched in 2009, and has become a recognized asset outside of the cryptocurrency community. BTC has held the highest market capitalization of any cryptocurrency for the past decade.
+
+Bitcoin champions simplicity and stability, and has stood the test of time. Influencing or attacking the network is infeasible or impractical for any potential hackers. It's one of the only cryptocurrencies to capture public attention. Bitcoin is a household name, and is recognized as an asset by governments, large corporations, and legacy banking institutions. Lastly, Bitcoin is largely considered a reliable store of value, and provides extensive infrastructure to support the PoX consensus mechanism.
+
+SIP-001 provides a full [list of reasons why Bitcoin was chosen to secure Stacks](https://github.com/stacksgov/sips/blob/main/sips/sip-001/sip-001-burn-election.md).
+
+{% hint style="info" %}
+By the way, SIP stands for Stacks Improvement Proposal, and it's the process by which community members agree on making changes to the network. Reading the SIPs in detail is an excellent way to familiarize yourself with Stacks at the implementation level. All of the SIPs are available in the [SIPs section](../network-fundamentals/sips.md) of the docs.
+{% endhint %}
+
+### Unlocking Bitcoin capital
+
+In the previous section we talked about Stacks being able to allow us to build a decentralized economy on top of Bitcoin and that PoX was a key piece of being able to do that.
+
+The reason is two-fold. First, as a part of this PoX mining process we have covered here, a hash of each Stacks block is recorded to the OP\_RETURN opcode of a Bitcoin transaction. If you aren't familiar, the OP\_RETURN opcode allows us to store up to 40 bytes of arbitrary data in a Bitcoin transaction.
+
+{% hint style="info" %}
+This [Stack Exchange answer](https://bitcoin.stackexchange.com/questions/29554/explanation-of-what-an-op-return-transaction-looks-like) gives a good overview of the reasoning and history of this opcode.
+{% endhint %}
+
+This is the first part of how Stacks inherits Bitcoin's security: its history is anchored block-by-block to the Bitcoin chain. Anyone can use merkle roots to verify these hashes to determine if the history is correct.
+
+Additionally, after the Nakamoto Upgrade, Stacks no longer forks on its own. Miners are required at a protocol level to build atop the last mined Stacks blocks, meaning that **Stacks is secured by both 100% of Bitcoin's hashrate in addition to the Stacks security budget from its miners.** We'll get into this process in more detail in the [Block Production](../block-production/) section.
+
+Additionally, part of this PoX process involves each Stacks block also knowing which Bitcoin block it is anchored to. Clarity, Stacks' smart contract language, has built-in functions for reading this data, such as [`get-block-info`](https://docs.stacks.co/docs/write-smart-contracts/clarity-language/language-functions#get-block-info), which returns, among other things, a field called `burnchain-header-hash`, which gives us the hash of the Bitcoin header corresponding to this Stacks block.
+
+This allows us to do really interesting things like trigger certain things to happen in a Clarity contract by watching the chain and verifying whether or not certain transactions occurred. You can see this in action in [Catamaran Swaps](https://docs.catamaranswaps.org/en/latest/catamaran.html), with other interesting projects like [Zest](https://www.zestprotocol.com/) seeking to expand on this functionality.
+
+The ultimate goal of all this is to enable the vision of web3, building a decentralized economy and enabling true user ownership of assets and data, on top of Bitcoin as a settlement layer, and using Bitcoin as a base decentralized money.
+
+### Proof of Transfer Contracts and Technical Details
+
+The Proof of Transfer functionality is implemented on the Stacks chain via a [Clarity smart contract](https://explorer.hiro.so/txid/0xc6d6e6ec82cabb2d7a9f4b85fcc298778d01186cabaee01685537aca390cdb46?chain=mainnet). An overview of this contract is available in the docs.
+
+You can see the original design for stacking and proof of transfer by reading the relevant SIP, [SIP-007](https://github.com/stacksgov/sips/blob/main/sips/sip-007/sip-007-stacking-consensus.md). You can also utilize [Hiro's API](https://docs.hiro.so/api#tag/Info/operation/get_pox_info) to get proof of transfer details including the relevant contract address.
diff --git a/docs/learn/stacks-101/stacks-among-other-layers.md b/docs/learn/stacks-101/stacks-among-other-layers.md
new file mode 100644
index 0000000000..07a9f9ac64
--- /dev/null
+++ b/docs/learn/stacks-101/stacks-among-other-layers.md
@@ -0,0 +1,88 @@
+# Stacks Among Other Layers
+
+
+
+Recently, we have seen a flurry of new "Bitcoin layers" popping up across the ecosystem as the market has finally woken up to the idea.
+
+However, not all Bitcoin layers are made equal. While a large chunk of these projects are vaporware riding the hype train, there are several projects that are making a good faith effort to grow the Bitcoin economy and build on top of Bitcooin using various approaches.
+
+The [Bitcoin Layers project](https://www.bitcoinlayers.org/) is an excellent place to begin learning about these different layers. In addition, here we've broken down how Stacks compares to some of the most promising Bitcoin L2 solutions so you can begin to learn about them all and make an educated decision on which to use.
+
+### What is a Bitcoin Layer?
+
+It's important to define terms, especially in a new and evolving ecosystem like web3, and an even newer and more rapidly evolving subecosystem like Bitcoin layers.
+
+For the purpose of this document and comparison, we can use the following definition of a Bitcoin layer: A Bitcoin layer is a separate distributed computing system built either alongside or on top of Bitcoin for the purpose of enhancing its scalability, functionality, or both.
+
+That definition is intentionally general, and encompasses many different projects like L2s, sidechains, federated, open network, etc.
+
+#### Technical vs Economic Considerations
+
+It's important to understand that when designing blockchains, especially layer 2 systems, we have to consider both technical and economic factors. Since a core component of a blockchain system is money, we need to make sure that our systems are both technically robust and economically efficient. And we need to accomplish both of these things while maintaining decentralization.
+
+While it is trivial to create a trusted bridge to bridge BTC from the L1 to a L2, that defeats the purpose of blockchain technology in general, since the goal should be to create permissionless, trust-minimized systems.
+
+At the same time, a great technical solution that doesn't consider the economic incentives of the decentralized actors running the network will not have a sustainable path to long-term adoption and viability.
+
+This balance is why Stacks has chosen the design it has, to balance both achieving the technical features of a Bitcoin L2 like security inheritance and a trust-minimized BTC peg with the economic incentives for the participants in the ecosystem to maintain it in the long term.
+
+As an example of this, Galaxy recently [conducted research](https://www.galaxy.com/insights/research/exploring-bitcoin-for-data-availability/) on this topic and found that a Bitcoin rollup "will need to generate approximately between $1.9m and $9.63m in revenue from L2 transaction fees per month." That is a significant number and again highlights the need to consider both technical and economic factors when designing Bitcoin layers.
+
+### Popular Bitcoin Layers Compared
+
+#### Lightning
+
+Lightning is probably the most well-known Bitcoin layer, and is primarily designed to address scalability issues. Lightning functions as a separate P2P network from Bitcoin, allowing participants to move their BTC from the main chain to Lightning, conduct multiple transactions on Lightning, and then send the final result to the BTC chain where it is finalized.
+
+This is actually a completely separate problem from what Stacks is trying to address. Where Lightning takes the existing functionality of Bitcoin and makes it much more scalable, Stacks is seeking to expand Bitcoin's functionality to do things you can't do now.
+
+Crucially, Lightning is ephemeral, meaning it has no state management. There is no continuous record of what has happened on the Lightning network, only current channels. Once users close their channel and their transactions are written back to the Bitcoin chain, they are gone.
+
+A key component of fully-expressive smart contracts is that they maintain a permanent historical record of all transactions that have happened on the chain.
+
+Bitcoin does this now, but its scripting language is very limited. So where Lightning seeks to make existing Bitcoin functionality happen faster, Stacks seeks to add new functionality.
+
+#### RSK
+
+Like Stacks, [RSK](https://www.rsk.co/) seeks to add additional functionality to Bitcoin, but it goes about that process differently than Stacks.
+
+RSK is a merge-mined chain, meaning that it is mined concurrently with Bitcoin. Stacks has its own miners and mining process, and its own economic value and security that is a function of that token value, more on this below.
+
+There are multiple perspectives to look at this from. Because RSK is merge-mined, Bitcoin miners are also the ones mining RSK blocks, and RSK does not have its own token.
+
+RSK can only exist with opt-in from Bitcoin miners and mining rewards are highly dependent on transaction volume.
+
+This also opens up a wider discussion on the costs and benefits of having a separate token, which we'll get into below a bit when we discuss rollups.
+
+RSK is also EVM-compatible, where Stacks uses Clarity and the Clarity VM.
+
+#### Liquid
+
+[Liquid](https://liquid.net/) is a federated network focused on unlocking more advanced financial capabilities with Bitcoin. Being federated, Liquid is not an open network, and thus not decentralized.
+
+The Liquid consensus mechanism is managed by 15 functionaries, who handle the transaction processing and validating. Liquid also does not support general-purpose applications, but is solely focused on financial applications.
+
+For another perspective, Hiro wrote an [excellent post](https://www.hiro.so/blog/building-on-bitcoin-project-comparison) comparing Stacks with other Bitcoin projects.
+
+#### Bitcoin Rollups
+
+Rollups are an exciting development for scaling decentralized applications. There are many different types of rollups; they're broadly divided into ZK rollups and Optimistic rollups, although other classifications are also there (see [this overview](https://era.zksync.io/docs/dev/fundamentals/rollups.html#what-are-rollups)).
+
+Rollups are generally considered layer-2 (L2) technology that runs on top of a layer-1 blockchain like Bitcoin or Ethereum. A critical aspect of rollups is the trustless nature where logic running on the L1 chain can determine whether something that happened on the rollup was valid. This is not true for all types of rollups, and there is some fuzziness around exact definitions. [Sovereign rollups](https://blog.celestia.org/sovereign-rollup-chains/), for example, only use the underlying L1 for data availability (DA) and not for consensus.
+
+Most of the rollups work on Ethereum uses Ethereum L1 both as a data availability layer, and for consensus, i.e., the validity of rollup transactions is determined by logic running on Ethereum L1. Newer systems, [like Celestia](https://celestia.org/), are taking a more modular approach and are separating DA from consensus. One interesting aspect of separating DA is that more established and durable chains like Bitcoin can be used for DA as well. Below is an interesting comparison of sidechains and two types of rollups possible on Bitcoin (John Light posted this [on Twitter](https://twitter.com/lightcoin/status/1630301411962388481?s=20)):
+
+
+
+This image broadly means developers can build sovereign rollups on Bitcoin today, but you'll need a "trusted" setup for moving BTC in and out of the rollup. In fact, people are already doing this -- see the recent [Rollkit announcement](https://rollkit.dev/blog/sovereign-rollups-on-bitcoin/). To build validity rollups, meaning Bitcoin L1 enforces BTC withdrawals from the rollup, you'll need modifications to Bitcoin L1. See [this overview](https://bitcoinrollups.org/) for more details.
+
+One important nuance here is the cost required to effectively run a rollup on Bitcoin as discussed in the Galaxy research report linked in the first section.
+
+Now we have a solid grasp of how Stacks works and how it fits in among other layers. Let's begin to dig into some of the technical implementation details and see how Stacks actually works.
+
+***
+
+Additional Resources
+
+* \[[Hiro Blog](https://www.hiro.so/blog/building-on-bitcoin-project-comparison)] Building on Bitcoin: a Comparison of Bitcoin Projects
+* \[[Hiro Books](https://www.hiro.so/books/a-beginners-guide-to-bitcoin-layers)] A Beginner's Guide to Bitcoin Layers
diff --git a/docs/learn/stacks-101/what-is-stacks.md b/docs/learn/stacks-101/what-is-stacks.md
new file mode 100644
index 0000000000..37a45a7cbd
--- /dev/null
+++ b/docs/learn/stacks-101/what-is-stacks.md
@@ -0,0 +1,74 @@
+# What Is Stacks?
+
+
+
+We can get an idea of the goal and ethos behind Stacks by looking at [how Satoshi envisioned generalizing Bitcoin](https://satoshi.nakamotoinstitute.org/posts/bitcointalk/threads/244/#222) back in 2010:
+
+> "...to be a completely separate network and separate block chain, yet share CPU power with Bitcoin...all networks in the world would share combined CPU power, increasing the total strength."
+
+This is a major theme in the design decisions for Stacks. A bit of a contradiction in the Bitcoin world, the Stacks network is a Bitcoin L2, but it does have its own token.
+
+This is an intentional and critical design decision primarily for the purpose of maintaining decentralization, rather than needing to rely on a federation.
+
+If that's confusing or you are skeptical, that's understandable — we'll be diving deeper into these ideas as we go through the docs.
+
+### Stacks and the Purpose of Blockchain Technology
+
+When evaluating new blockchain technologies, it's important to keep the original intent and purpose of them intact. If we go back to Bitcoin, it was originally designed to be:
+
+* Decentralized
+* Immutable
+* Secure
+
+You've likely heard of the blockchain trilemma — the problem of trying to balance decentralization, scalability, and security of a blockchain network.
+
+Stacks takes the approach of solving this trilemma by separating out chains into layers.
+
+So at the bottom, you have the foundational layer: Bitcoin.
+
+Bitcoin is the most decentralized, most secure, and most immutable blockchain network. However, that comes with a few tradeoffs.
+
+* Bitcoin is very slow compared to other networks. Bitcoin only has a new block written once every \~10 minutes, making its throughput negligible compared to networks designed for speed like Solana.
+* Bitcoin is also "boring". Ethereum came along after Bitcoin and sought to do the same thing for software that Bitcoin did for money. Ethereum's goal is to be a decentralized supercomputer of sorts, serving as a global compute environment for smart contracts (code that is written to a blockchain).
+* Bitcoin is not scalable. Because every new block must propagate to every node on the network, Bitcoin can only run as fast as the slowest node in the network.
+
+Now we are seeing the rise of modular blockchain networks like Cosmos that are designed to make it easy for people to spin up their own blockchain networks.
+
+While most new blockchain protocols popping up these days see these properties as negatives and seek to eliminate them, the Stacks community sees things differently.
+
+### The Stacks Way
+
+Stacks takes a layered approach: the foundational settlement layer is Bitcoin, and scalability and functionality are added on top of that using layers.
+
+There are many different types of L2s and different ways they can be built. They all come with [different tradeoffs](stacks-among-other-layers.md) and have their own way of accomplishing the goals of scalability or functionality.
+
+By taking this layered approach, we are able to have all of the same functionality as chains like Ethereum, but built on Bitcoin.
+
+So Stacks is a Bitcoin layer 2 with some unique properties, like having its own token, that acts as an incentive mechanism to maintain a historical ledger of all of its transactions and operate with its own security budget (in addition to Bitcoin's security budget — more on this in the next section).
+
+This is one of the things that separates Stacks from other Bitcoin layers like Lightning.
+
+* Lightning doesn't add any additional functionality to Bitcoin; it simply helps to scale functionality Bitcoin already has and helps it operate faster. Lightning is also ephemeral — it has no permanent state — and so is unsuitable for things like smart contracts that need to keep track of data and maintain state.
+* Contrast this to Stacks, which adds additional functionality to Bitcoin but still ultimately settles to Bitcoin (we'll cover this in the next section as well).
+
+The benefit is that we can maintain a separation of concerns and keep Bitcoin simple and sturdy, chugging along producing blocks, while adding additional layers for functionality and speed. If those other layers were compromised, the foundational layer would remain unaffected.
+
+This is important when building systems intended to be a global decentralized money (Bitcoin) and a decentralized economy built on top of that money (Stacks).
+
+The STX token is a separate token used to incentivize honest block production. It does not represent pegged Bitcoin (there is a separate Bitcoin peg called [sBTC](../sbtc/) for that purpose). While this may ruffle some feathers among parts of the Bitcoin community, it has several advantages.
+
+By implementing a token into the Stacks chain, we provide additional economic incentive for miners to produce Stacks blocks honestly.
+
+This token provides additional incentive as a way to grow the chain. Rather than relying on altruism to produce blocks and grow the chain, we can incentivize builders, token-holders, and investors all at the same time by having a token.
+
+The ICO scams of 2017 put a bad taste in many people's mouths, which has justifiably made a lot of people skeptical of every new blockchain project that pops up with a new token.
+
+But the problem with many of those projects was they had no actual value, weren't anchored to anything else of value, and provided no real utility.
+
+With a project like Stacks, we have real utility in the sense of serving as a way to utilize Bitcoin and make it a productive asset in a decentralized way. This is a key point: currently the only common ways to make Bitcoin productive are to give it to a custodial service or transfer it off the Bitcoin chain via something like wBTC on Ethereum.
+
+Stacks allows us to do this while ultimately still settling to the Bitcoin chain.
+
+In addition, Stacks allows us to build decentralized and censorship-resistant software utilizing Bitcoin as the foundational settlement layer. Eventually, the goal is to build a network of financial systems and decentralized software products that all utilize Bitcoin as their money.
+
+With that context, let's dive into exactly how Stacks is connected to Bitcoin.
diff --git a/docs/learn/transactions/README.md b/docs/learn/transactions/README.md
new file mode 100644
index 0000000000..8e77cb2089
--- /dev/null
+++ b/docs/learn/transactions/README.md
@@ -0,0 +1,3 @@
+# Transactions
+
+Transactions are a key component of the Stacks chain and are the primary way users will interact with it. In this section, we'll cover how transactions work and give an introduction to post conditions, an additional security feature of Stacks that allows client-side developers to enforce certain conditions to protect users from interacting with malicious contracts.
diff --git a/docs/learn/transactions/how-transactions-work.md b/docs/learn/transactions/how-transactions-work.md
new file mode 100644
index 0000000000..04831f7e4d
--- /dev/null
+++ b/docs/learn/transactions/how-transactions-work.md
@@ -0,0 +1,74 @@
+# How Transactions Work
+
+source: Hiro blog
+
+### Introduction
+
+Transactions are the fundamental unit of execution in the Stacks blockchain. Each transaction is originated from a Stacks account, and is retained in the Stacks blockchain history for eternity. This guide helps you understand Stacks transactions.
+
+### Lifecycle
+
+Transactions go through phases before being finally confirmed, and available for all, on the Stacks 2.0 network.
+
+
+
+{% stepper %}
+{% step %}
+#### Generate
+
+Transactions are assembled according to the encoding specification.
+{% endstep %}
+
+{% step %}
+#### Validate and sign
+
+Transactions are validated to confirm they are well-formed. Required signatures are filled in.
+{% endstep %}
+
+{% step %}
+#### Broadcast
+
+Transactions are sent to a node.
+{% endstep %}
+
+{% step %}
+#### Register
+
+A miner receives transactions, verifies, and adds them to the ["mempool,"](https://academy.binance.com/en/glossary/mempool) a holding area for all the pending transactions.
+{% endstep %}
+
+{% step %}
+#### Process
+
+Miners review the mempool and select transactions for the next block to be mined. Depending on the transaction type, different actions can happen during this step. For example, post-conditions could be verified for a token transfer, smart-contract defined tokens could be minted, or an attempt to call an existing smart contract method could be made.
+{% endstep %}
+
+{% step %}
+#### Confirm
+
+Miners successfully propose blocks with a set of transactions. The transactions inside are successfully propagated to the network when the stackers approve them.
+{% endstep %}
+{% endstepper %}
+
+{% hint style="info" %}
+A transaction can have one of three states once it is registered: `pending`, `success`, or `failed`.
+{% endhint %}
+
+### Types
+
+Stacks supports a set of different transaction types:
+
+| **Type** | **Value** | **Description** |
+| ------------------------- | ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| Tenure change | `TenureChange` | A tenure change is an event in the existing Stacks blockchain when one miner assumes responsibility for creating new stacks blocks from another miner. A change in tenure occurs when a Stacks block is discovered from a cryptographic sortition. Carried out by stackers. |
+| Tenure change block found | `TenureChange-BlockFound` | A `TenureChange-BlockFound` transaction is induced by a winning sortition. This causes the new miner to start producing blocks, and stops the current miner from producing more blocks. |
+| Tenure change extend | `TenureChange-Extend` | A `TenureChange-Extend`, which is induced by Stackers, resets the current tenure's ongoing execution budget, thereby allowing the miner to continue producing blocks. |
+| Token transfer | `token_transfer` | Asset transfer from a sender to a recipient |
+| Contract deploy | `smart_contract` | Contract instantiation |
+| Contract call | `contract_call` | Contract call for a public, non read-only function |
+
+A sample of each transaction type can be found in the [Stacks Blockchain API response definition for transactions](https://docs.hiro.so/stacks/api/transactions/get-transaction).
+
+{% hint style="info" %}
+Read-only contract call calls do **not** require transactions. Read more about it in the network guide.
+{% endhint %}
diff --git a/docs/learn/transactions/post-conditions.md b/docs/learn/transactions/post-conditions.md
new file mode 100644
index 0000000000..91edcaca66
--- /dev/null
+++ b/docs/learn/transactions/post-conditions.md
@@ -0,0 +1,37 @@
+# Post Conditions
+
+source: Hiro blog
+
+Post conditions are one of the most interesting and unique aspects of Stacks.
+
+From the beginning, safety and security has been at the heart of the Stacks ethos and formed the foundation of architecture decisions when building it.
+
+Like Clarity, Stacks' smart contract programming language, post conditions were specifically built and designed to solve the problem of user safety when interacting with blockchain applications.
+
+So what are they and how do they work?
+
+### How Post Conditions Work
+
+Post conditions are conditions that are set on the client side to ensure that a smart contract does not perform any unexpected behavior.
+
+Let's look at an example to make this more concrete.
+
+Let's say a user is on an NFT marketplace and is expecting to purchase an NFT for 100 STX. Using post conditions, the developer who is building the frontend of the application can add in post conditions to ensure that this is in fact what happens when the user initiates the transaction.
+
+If it does not, the transaction will abort and the user won't be out anything except the transaction fee.
+
+It's important to note that post conditions do not live in smart contracts. They are designed to be an extra layer of security on top of smart contracts.
+
+The problem they help address is a user interacting with a malicious smart contract that attempts to do something the user does not expect.
+
+But rather than simply being a UI feature of a wallet, these post conditions are built into the Stacks blockchain itself and are enforced at the protocol level.
+
+When you use a Stacks wallet like the Hiro web wallet and initiate a transaction, the wallet will display the post conditions set by the developer and tell the user exactly what is going to happen. If the action taken by the smart contract matches, the transaction goes through fine, otherwise it aborts.
+
+Here's what that looks like:
+
+
+
+In this example, if the smart contract does not transfer one fabulous-frog NFT and and take 50 STX from the user, the transaction will abort.
+
+You can learn more about how post conditions work in [SIP-005](https://github.com/stacksgov/sips/blob/main/sips/sip-005/sip-005-blocks-and-transactions.md#transaction-post-conditions) and how to utilize them in your applications in Hiro's excellent [post conditions tutorial](https://docs.hiro.so/stacks/stacks.js/guides/post-conditions).
diff --git a/docs/operate/.gitbook.yaml b/docs/operate/.gitbook.yaml
new file mode 100644
index 0000000000..9c25db3cbb
--- /dev/null
+++ b/docs/operate/.gitbook.yaml
@@ -0,0 +1,31 @@
+root: ./
+
+redirects:
+
+ # nodes-and-miners to run-a-node redirects
+ guides-and-tutorials/nodes-and-miners: README.md
+ guides-and-tutorials/nodes-and-miners/run-a-node-with-docker: run-a-node/run-a-node-with-docker.md
+ guides-and-tutorials/nodes-and-miners/run-a-node-with-digital-ocean: run-a-node/run-a-node-with-digital-ocean.md
+
+ # guides-and-tutorials/run-a-miner to operate/run-a-miner redirects
+ guides-and-tutorials/run-a-miner/mine-mainnet-stacks-tokens: run-a-miner/mine-mainnet-stacks-tokens.md
+ guides-and-tutorials/run-a-miner/mine-testnet-stacks-tokens: run-a-miner/mine-testnet-stacks-tokens.md
+ guides-and-tutorials/run-a-miner/miner-costs-and-fees: run-a-miner/miner-costs-and-fees.md
+ guides-and-tutorials/run-a-miner/miner-prerequisites: run-a-miner/miner-prerequisites.md
+ guides-and-tutorials/run-a-miner/verify-miner: run-a-miner/verify-miner.md
+
+ # guides-and-tutorials/running-a-signer to operate/run-a-signer redirects
+ guides-and-tutorials/running-a-signer/best-practices-to-run-a-signer: run-a-signer/best-practices-to-run-a-signer.md
+ guides-and-tutorials/running-a-signer/how-to-monitor-signer: run-a-signer/how-to-monitor-signer.md
+ guides-and-tutorials/running-a-signer/how-to-read-signer-logs: run-a-signer/how-to-read-signer-logs.md
+ guides-and-tutorials/running-a-signer/opsec-best-practices: run-a-signer/opsec-best-practices.md
+ guides-and-tutorials/running-a-signer/signer-quickstart: run-a-signer/signer-quickstart.md
+
+ guides-and-tutorials/best-practices-to-snapshot-the-chainstate: snapshot-the-chainstate.md
+
+ # guides-and-tutorials/stack-stx to operate/stacking-stx redirects
+ guides-and-tutorials/stack-stx/increase-stacking: stacking-stx/increase-stacked-position.md
+ guides-and-tutorials/stack-stx/operate-a-pool: stacking-stx/operate-a-stacking-pool.md
+ guides-and-tutorials/stack-stx/stack-with-a-pool: stacking-stx/stack-with-a-pool.md
+ guides-and-tutorials/stack-stx/stacking-flow: stacking-stx/solo-stack.md
+ guides-and-tutorials/stack-stx/stop-stacking: stacking-stx/stop-stacking.md
diff --git a/docs/operate/.gitbook/assets/Frame 316126262 (1).jpg b/docs/operate/.gitbook/assets/Frame 316126262 (1).jpg
new file mode 100644
index 0000000000..b80d52e8b7
Binary files /dev/null and b/docs/operate/.gitbook/assets/Frame 316126262 (1).jpg differ
diff --git a/docs/operate/.gitbook/assets/Frame 316126262.jpg b/docs/operate/.gitbook/assets/Frame 316126262.jpg
new file mode 100644
index 0000000000..b80d52e8b7
Binary files /dev/null and b/docs/operate/.gitbook/assets/Frame 316126262.jpg differ
diff --git a/docs/operate/README.md b/docs/operate/README.md
new file mode 100644
index 0000000000..c1d201af24
--- /dev/null
+++ b/docs/operate/README.md
@@ -0,0 +1,20 @@
+# Run a Node
+
+
+
+This section walks through the technical setup steps required to run Stacks network nodes and miners. There are multiple options available for running a node, including Docker, Digital Ocean, and Render.
+
+Running your own Stacks node is a great way to increase the decentralization of the ecosystem and avoid relying on third-party centralized providers.
+
+## Minimum viable requirements
+
+While you can run a node using these specs, it's recommended to assign more than the minimum for better performance.
+
+{% hint style="warning" %}
+* ⚠️ docker-compose version `2.2.2` or greater is **required** — https://docs.docker.com/compose/install/
+* **8 GB memory** if running only a Stacks node
+* **16 GB memory** if running Stacks + Bitcoin node
+* **2 vCPU**
+* **1 TB disk** for Stacks node
+* **1 TB disk** for Bitcoin node
+{% endhint %}
diff --git a/docs/operate/SUMMARY.md b/docs/operate/SUMMARY.md
new file mode 100644
index 0000000000..16332ea770
--- /dev/null
+++ b/docs/operate/SUMMARY.md
@@ -0,0 +1,30 @@
+# Table of contents
+
+* [Run a Node](README.md)
+ * [Run a Node with Docker](readme/run-a-node-with-docker.md)
+ * [Run a Node with Digital Ocean](readme/run-a-node-with-digital-ocean.md)
+ * [Run a Node with a Hosted Provider](readme/run-a-node-with-a-hosted-provider.md)
+ * [Run a Node with Quicknode](readme/run-a-node-with-quicknode.md)
+ * [Run a Bitcoin Node](readme/run-a-bitcoin-node.md)
+ * [Run a Pruned Bitcoin Node](readme/run-a-pruned-bitcoin-node.md)
+* [Run a Miner](run-a-miner/README.md)
+ * [Miner Prerequisites](run-a-miner/miner-prerequisites.md)
+ * [Miner Costs and Fees](run-a-miner/miner-costs-and-fees.md)
+ * [Mine Testnet Stacks Tokens](run-a-miner/mine-testnet-stacks-tokens.md)
+ * [Mine Mainnet Stacks Tokens](run-a-miner/mine-mainnet-stacks-tokens.md)
+ * [Verify Miner](run-a-miner/verify-miner.md)
+* [Run a Signer](run-a-signer/README.md)
+ * [Signer Quickstart](run-a-signer/signer-quickstart.md)
+ * [How to Read Signer Logs](run-a-signer/how-to-read-signer-logs.md)
+ * [How to Monitor Signer](run-a-signer/how-to-monitor-signer.md)
+ * [Best Practices to Run a Signer](run-a-signer/best-practices-to-run-a-signer.md)
+ * [OpSec Best Practices](run-a-signer/opsec-best-practices.md)
+* [Run a sBTC Signer](run-a-sbtc-signer/README.md)
+ * [Best Practices for Running a sBTC Signer](run-a-sbtc-signer/best-practices-for-running-an-sbtc-signer.md)
+* [Snapshot the Chainstate](snapshot-the-chainstate.md)
+* [Stacking STX](stacking-stx/README.md)
+ * [Solo Stack](stacking-stx/solo-stack.md)
+ * [Operate a Stacking Pool](stacking-stx/operate-a-stacking-pool.md)
+ * [Stack with a Pool](stacking-stx/stack-with-a-pool.md)
+ * [Increase Stacked Position](stacking-stx/increase-stacked-position.md)
+ * [Stop Stacking](stacking-stx/stop-stacking.md)
diff --git a/docs/operate/readme/run-a-bitcoin-node.md b/docs/operate/readme/run-a-bitcoin-node.md
new file mode 100644
index 0000000000..b935cf30e2
--- /dev/null
+++ b/docs/operate/readme/run-a-bitcoin-node.md
@@ -0,0 +1,236 @@
+# Run a Bitcoin Node
+
+{% stepper %}
+{% step %}
+### Requirements
+
+This guide is written for a Unix based system. It's reasonable to expect some modifications will be required for other operating systems.
+
+When started, the Bitcoin node will take several days to reach chain tip.
+
+* Bitcoin Core >= v25.0
+ * https://github.com/bitcoin/bitcoin
+ * https://bitcoincore.org/en/download/
+* Host with a minimum of:
+ * 2 vCPU (a single dedicated cpu for the bitcoind process)
+ * 4GB Memory (during sync, more available memory will improve sync time)
+ * 1TB free disk space
+* User account: `bitcoin:bitcoin`
+* Chainstate directory located at: `/bitcoin/mainnet`
+ * `bitcoin` user must have read/write access.
+* Config directory located at: `/etc/bitcoin`
+ * `bitcoin` user must have at least read access
+{% endstep %}
+
+{% step %}
+### Add bitcoin user and set file ownership
+
+Run the following commands:
+
+{% code title="Create directories and add user" %}
+```shell
+$ sudo mkdir -p /bitcoin/mainnet
+$ sudo mkdir /etc/bitcoin
+$ sudo useradd bitcoin -d /bitcoin
+$ sudo chown -R bitcoin:bitcoin /bitcoin /etc/bitcoin/
+```
+{% endcode %}
+{% endstep %}
+
+{% step %}
+### Bitcoin config
+
+Below is a sample config used to sync a bitcoin node - feel free to adjust as needed.
+
+{% hint style="info" %}
+If using the [systemd unit below](run-a-bitcoin-node.md#systemd-unit-file), save this file as `/etc/bitcoin/bitcoin.conf`
+{% endhint %}
+
+* `btuser:btcpass` is hardcoded as an rpcauth user/password ([generated using this script](https://github.com/bitcoin/bitcoin/tree/master/share/rpcauth)).
+* Only localhost access is allowed (`127.0.0.1`) on the standard mainnet ports.
+* `dbcache` is set to the maximum of 16GB.
+* Wallet (and wallet rpc calls) are disabled.
+
+{% code title="Sample /etc/bitcoin/bitcoin.conf" %}
+```
+## [rpc]
+
+# Accept command line and JSON-RPC commands.
+server=1
+
+# Allow JSON-RPC connections from specified source.
+rpcallowip=127.0.0.1/0
+
+# Bind to given address to listen for JSON-RPC connections.
+rpcbind=127.0.0.1:8332
+
+# Username and HMAC-SHA-256 hashed password for JSON-RPC connections.
+
+# Use the script at https://github.com/bitcoin/bitcoin/tree/master/share/rpcauth to generate
+
+# Note: may be specified multiple times for different users.
+rpcauth=btcuser:18857b4df4b1f0f5e6b1d7884617ab39$de6e02e1da8ee138ee702e13e0637e24679d844756216b066c3aeac4bcac5e10 # btuser:btcpass
+
+# Optional: rpcwhitelist can restrict listed RPC calls to specific rpcauth users.
+
+# Uncomment the below the restrict the `limited` user to a small subset of `get` commands
+
+# rpcauth=limited:350c91a60895b567c4662c27e63e9a41$25188b0f51f2f974dcdc75c1e0d41174e8f7ae19fb96927abf68ac5bc1e8897b # limited:limited
+
+# rpcwhitelist=limited:getblockchaininfo,getblock,getblockcount,getblockhash,getblockheader,getnetworkinfo
+
+# rpcwhitelistdefault=0
+
+## [core]
+
+# Specify data directory
+datadir=/bitcoin/mainnet
+
+# Do not keep transactions in the mempool longer than hours (default: 336)
+mempoolexpiry=24
+
+# Bind to given address and always listen on it (default: 0.0.0.0)
+bind=127.0.0.1:8333
+
+# Maximum database cache size MiB (4 to 16384, default: 450). In addition, unused mempool memory is shared for this cache
+dbcache=16384
+
+# Maintain a full transaction index, used by the getrawtransaction rpc call
+txindex=1
+
+## [wallet]
+
+# Do not load the wallet and disable wallet RPC calls
+disablewallet=1
+```
+{% endcode %}
+{% endstep %}
+
+{% step %}
+### Systemd unit file
+
+Reference: https://github.com/bitcoin/bitcoin/blob/master/contrib/init/bitcoind.service
+
+Save the following as your systemd unit (for example `/etc/systemd/system/bitcoin.service`):
+
+{% code title="bitcoind.service" %}
+```
+[Unit]
+Description=Bitcoin daemon
+Documentation=https://github.com/bitcoin/bitcoin/blob/master/doc/init.md
+
+# https://www.freedesktop.org/wiki/Software/systemd/NetworkTarget/
+After=network-online.target
+Wants=network-online.target
+
+[Service]
+ExecStart=/usr/bin/bitcoind -pid=/run/bitcoind/bitcoind.pid \
+ -conf=/etc/bitcoin/bitcoin.conf \
+ -startupnotify='systemd-notify --ready' \
+ -shutdownnotify='systemd-notify --stopping'
+
+# Make sure the config directory is readable by the service user
+PermissionsStartOnly=true
+ExecStartPre=/bin/chgrp bitcoin /etc/bitcoin
+
+# Process management
+####################
+
+Type=notify
+NotifyAccess=all
+PIDFile=/run/bitcoind/bitcoind.pid
+
+Restart=on-failure
+TimeoutStartSec=infinity
+TimeoutStopSec=600
+
+# Directory creation and permissions
+####################################
+
+# Run as bitcoin:bitcoin
+User=bitcoin
+Group=bitcoin
+
+# /run/bitcoind
+RuntimeDirectory=bitcoind
+RuntimeDirectoryMode=0710
+
+# /etc/bitcoin
+ConfigurationDirectory=bitcoin
+ConfigurationDirectoryMode=0710
+
+# /var/lib/bitcoind
+StateDirectory=bitcoind
+StateDirectoryMode=0710
+
+# Hardening measures
+####################
+
+# Provide a private /tmp and /var/tmp.
+PrivateTmp=true
+
+# Mount /usr, /boot/ and /etc read-only for the process.
+ProtectSystem=full
+
+# Deny access to /home, /root and /run/user
+ProtectHome=true
+
+# Disallow the process and all of its children to gain
+
+# new privileges through execve().
+NoNewPrivileges=true
+
+# Use a new /dev namespace only populated with API pseudo devices
+
+# such as /dev/null, /dev/zero and /dev/random.
+PrivateDevices=true
+
+# Deny the creation of writable and executable memory mappings.
+MemoryDenyWriteExecute=true
+
+# Restrict ABIs to help ensure MemoryDenyWriteExecute is enforced
+SystemCallArchitectures=native
+
+[Install]
+WantedBy=multi-user.target
+```
+{% endcode %}
+{% endstep %}
+
+{% step %}
+### Enable and start the Bitcoin service
+
+Run:
+
+{% code title="Enable and start service" %}
+```shell
+$ sudo systemctl daemon-reload
+$ sudo systemctl enable bitcoin.service
+$ sudo systemctl start bitcoin.service
+```
+{% endcode %}
+{% endstep %}
+
+{% step %}
+### Track sync progress
+
+{% hint style="info" %}
+Once started, you may track the sync progress:
+{% endhint %}
+
+{% code title="Tail debug log and query RPC" %}
+```
+$ sudo tail -f /bitcoin/mainnet/debug.log
+2024-12-05T19:35:31Z UpdateTip: new best=00000000000000000058990a84cc8f8eab25dbbd572f123f9190cea7256d7349 height=509258 version=0x20000000 log2_work=88.128280 tx=299522737 date='2018-02-15T03:42:14Z' progress=0.295203 cache=43.5MiB(172740txo)
+...
+$ bitcoin-cli \
+ -rpcconnect=127.0.0.1 \
+ -rpcport=8332 \
+ -rpcuser=btcuser \
+ -rpcpassword=btcpass \
+ getblockcount
+509016
+```
+{% endcode %}
+{% endstep %}
+{% endstepper %}
diff --git a/docs/operate/readme/run-a-node-with-a-hosted-provider.md b/docs/operate/readme/run-a-node-with-a-hosted-provider.md
new file mode 100644
index 0000000000..5a10fe2d30
--- /dev/null
+++ b/docs/operate/readme/run-a-node-with-a-hosted-provider.md
@@ -0,0 +1,19 @@
+# Run a Node with a Hosted Provider
+
+We're always looking for new hosting providers that enable anyone to run the Stacks Blockchain. Below, you'll find some examples of the current providers that are known to support running a node.
+
+### Quicknode
+
+Please refer to the Quicknode Section for instructions on launching an instance with Quicknode.
+
+### Stacks on Render
+
+The [render-stacks](https://github.com/stacksfoundation/render-stacks) GitHub repo has instructions so anyone can deploy a Stacks node to the hosted [Render](https://render.com/) service in one click.
+
+{% hint style="warning" %}
+While it is possible to use the free plan with some modifications, it is recommended to run this on a paid plan.
+{% endhint %}
+
+### Stacks on Fly
+
+The [fly-stacks](https://github.com/stacksfoundation/fly-stacks) GitHub repo has instructions so anyone can deploy a Stacks node to the hosted [Fly](https://fly.io/) service.
diff --git a/docs/operate/readme/run-a-node-with-digital-ocean.md b/docs/operate/readme/run-a-node-with-digital-ocean.md
new file mode 100644
index 0000000000..5f125b0caa
--- /dev/null
+++ b/docs/operate/readme/run-a-node-with-digital-ocean.md
@@ -0,0 +1,104 @@
+# Run a Node with Digital Ocean
+
+### Introduction
+
+This is a step by step guide to deploy the [Stacks Blockchain](https://github.com/stacks-network/stacks-blockchain) on [DigitalOcean](https://digitalocean.com/).
+
+Build code is hosted on this [Github repository](https://github.com/stacksfoundation/stacks-machine-images) using the [methods from here](https://github.com/stacks-network/stacks-blockchain-docker).
+
+### Steps
+
+{% stepper %}
+{% step %}
+### Create the Droplet from the Marketplace
+
+Go to the [Stacks Blockchain page](https://marketplace.digitalocean.com/apps/stacks-blockchain) in DigitalOcean's marketplace. Click on `Create Stacks Blockchain Droplet`.
+{% endstep %}
+
+{% step %}
+### Choose plan and region
+
+Choose a plan (it will only allow you to select a droplet that meets the minimum requirements) and your preferred datacenter region.
+{% endstep %}
+
+{% step %}
+### Authentication
+
+Enter a root password or [enable SSH keys](https://docs.digitalocean.com/products/droplets/how-to/add-ssh-keys/) if you prefer.
+{% endstep %}
+
+{% step %}
+### Create the Droplet
+
+You can leave the rest of the options as they are and click on `Create Droplet`.
+{% endstep %}
+
+{% step %}
+### Wait for creation
+
+You will need to wait a few seconds for the droplet to get created. Once created click on it to see more information.
+{% endstep %}
+
+{% step %}
+### Access the Droplet
+
+Congratulations! You are now running the Stacks Blockchain. You can click on `Console` for a terminal window to open or login using SSH to the public IP you've been assigned to with user `root`.
+{% endstep %}
+{% endstepper %}
+
+### Getting started after deploying Stacks Blockchain
+
+Once the droplet is launched, the initial startup can take several minutes while BNS data is imported (this is a one time operation) and the Bitcoin headers are synced.
+
+To keep track of the progress, you can SSH to the host and view logs:
+
+```bash
+ssh root@your_droplet_public_ipv4
+/opt/stacks-blockchain-docker/manage.sh -n mainnet -a logs
+```
+
+After the stacks blockchain finishes the initial header sync and starts to sync with its peers, the application ports will open (`20443` and `3999`) and HTTP port `80` will now start proxying requests.
+
+Use `http://your_droplet_public_ipv4` to access the data directly, with output being similar to:
+
+```json
+{
+ "server_version": "stacks-blockchain-api v6.2.3 (master:77ab3ae2)",
+ "status": "ready",
+ "chain_tip": {
+ "block_height": 91820,
+ "block_hash": "0x06b276e85f238151414616618ae0adaf5eeda4eac6cad5bbefceeb37948ab275",
+ "index_block_hash": "0x4d7c075d7ab0f90b1dbc175f5c42b7344265d00cfef202dd9681d95388eeed8c",
+ "microblock_hash": "0xcf4f9037cc10696b2812b617ca105885be625c6acf8ad67e71bb4c09fa6ebb21",
+ "microblock_sequence": 4
+ }
+}
+```
+
+{% hint style="info" %}
+For the full list of API endpoints for the Stacks Blockchain, consult the [Hiro API Docs](https://docs.hiro.so/api)
+{% endhint %}
+
+All services are managed by a [systemd unit file](https://github.com/stacksfoundation/stacks-machine-images/blob/master/files/etc/systemd/system/stacks.service) that is set to start on boot.
+
+Manual control is also possible via the [manage.sh script](https://github.com/stacks-network/stacks-blockchain-docker/blob/master/manage.sh) at `/opt/stacks-blockchain-docker/manage.sh` on the host.
+
+Full details on how to use the manage.sh script is [available here](https://github.com/stacks-network/stacks-blockchain-docker/blob/master/docs/usage.md).
+
+### Launching a Droplet using the DigitalOcean API
+
+In addition to creating a Droplet from the Stacks Blockchain 1-Click App via the control panel, you can also use the [DigitalOcean API](https://digitalocean.com/docs/api).
+
+As an example, to create a 4GB Stacks Blockchain Droplet in the SFO2 region, you can use the following curl command. You’ll need to either save your [API access token](https://docs.digitalocean.com/reference/api/create-personal-access-token/) to an environment variable or substitute it into the command below.
+
+{% hint style="info" %}
+The `name`, `region` and `size` values below are hardcoded, so adjust as desired.
+{% endhint %}
+
+```bash
+$ export TOKEN=
+$ curl -X POST -H 'Content-Type: application/json' \
+ -H 'Authorization: Bearer '$TOKEN'' -d \
+ '{"name":"stacks-blockchain","region":"sfo2","size":"s-2vcpu-4gb","image":"stacksfoundation-stacksblockchain"}' \
+ "https://api.digitalocean.com/v2/droplets"
+```
diff --git a/docs/operate/readme/run-a-node-with-docker.md b/docs/operate/readme/run-a-node-with-docker.md
new file mode 100644
index 0000000000..defe4be9b4
--- /dev/null
+++ b/docs/operate/readme/run-a-node-with-docker.md
@@ -0,0 +1,119 @@
+# Run a Node with Docker
+
+### Stacks Blockchain with Docker
+
+Run your own Stacks Blockchain node using [docker-compose](https://docs.docker.com/compose/) with just a few commands using [stacks-blockchain-docker](https://github.com/stacks-network/stacks-blockchain-docker)
+
+### Requirements
+
+The minimum viable requirements are listed below.
+
+While you _can_ run a node using these specs, it's _recommended_ to assign more than the minimum for better performance.
+
+* ⚠️ [docker-compose](https://docs.docker.com/compose/install/) version `2.2.2` or greater is **required**
+* **8GB memory if running only a Stacks node**
+* **16 GB memory if running Stacks + Bitcoin node**
+* **1 Vcpu** ( _minimum of 2 Vcpu is recommended_ )
+* **500GB disk for Stacks node**
+* **1TB disk space for Bitcoin node**
+
+{% hint style="warning" %}
+MacOS with an ARM (M-series chip) processor is NOT recommended
+
+The way Docker for Mac on an Arm CPU is designed makes the I/O incredibly slow, and blockchains are _**very**_ heavy on I/O. This only seems to affect MacOS with the M-series chip, other Arm based systems like Raspberry Pi work as expected.
+{% endhint %}
+
+### Quickstart
+
+The `` placeholder used below can be replaced with one of:
+
+* mainnet
+* testnet
+* mocknet
+
+{% stepper %}
+{% step %}
+### Clone the repository
+
+Clone the stacks-blockchain-docker repository locally and change into the directory:
+
+{% code title="Clone repository" %}
+```bash
+git clone https://github.com/stacks-network/stacks-blockchain-docker && cd stacks-blockchain-docker
+```
+{% endcode %}
+{% endstep %}
+
+{% step %}
+### Start the services
+
+Start the docker-compose services for the chosen network:
+
+{% code title="Start services" %}
+```bash
+./manage.sh -n -a start
+```
+{% endcode %}
+
+{% hint style="info" %}
+With an optional HTTP proxy on port 80:
+
+{% code title="Start with proxy" %}
+```bash
+./manage.sh -n -a start -f proxy
+```
+{% endcode %}
+{% endhint %}
+{% endstep %}
+{% endstepper %}
+
+### Accessing the services
+
+{% hint style="info" %}
+For networks other than `mocknet`, downloading the initial headers can take several minutes. Until the headers are downloaded, the `/v2/info` endpoints won't return any data.
+
+Follow the logs to track the sync progress:
+
+{% code title="Follow logs" %}
+```bash
+./manage.sh -n -a logs
+```
+{% endcode %}
+{% endhint %}
+
+stacks-blockchain:
+
+* Ports `20443-20444` are exposed on `localhost`
+
+{% code title="Check stacks-blockchain /v2/info" %}
+```bash
+curl -sL localhost:20443/v2/info | jq -r
+```
+{% endcode %}
+
+stacks-blockchain-api:
+
+* Port `3999` is exposed on `localhost`
+
+{% code title="Check stacks-blockchain-api" %}
+```bash
+curl -sL localhost:3999 | jq -r
+```
+{% endcode %}
+
+proxy:
+
+* Port `80` is exposed on `localhost`
+
+{% code title="Check proxy" %}
+```bash
+curl -sL localhost/v2/info | jq -r
+curl -sL localhost | jq -r
+```
+{% endcode %}
+
+### Upgrades
+
+{% hint style="warning" %}
+For schema-breaking upgrades to running instances of this repo, you'll need to [run an event-replay](https://github.com/stacks-network/stacks-blockchain-docker/blob/master/docs/upgrade.md).
+{% endhint %}
diff --git a/docs/operate/readme/run-a-node-with-quicknode.md b/docs/operate/readme/run-a-node-with-quicknode.md
new file mode 100644
index 0000000000..aa06a7868b
--- /dev/null
+++ b/docs/operate/readme/run-a-node-with-quicknode.md
@@ -0,0 +1,63 @@
+# Run a Node with Quicknode
+
+[QuickNode](https://www.quicknode.com/) is a service for rapidly getting set up with a Stacks node. As an easy and fast alternative to running your own node, you can utilize QuickNode to serve as an API.
+
+{% stepper %}
+{% step %}
+### Create a QuickNode account
+
+Sign up on QuickNode: https://www.quicknode.com/signup
+{% endstep %}
+
+{% step %}
+### Create an endpoint
+
+Once signed in, click "Create an endpoint". Select:
+
+* Stacks
+* your desired network (e.g., mainnet or testnet)
+* your desired QuickNode plan level
+
+After that you'll have an API endpoint URL you can use to connect to Stacks.
+{% endstep %}
+
+{% step %}
+### Install the Stacks network package
+
+Install the `@stacks/network` package in your frontend project.
+{% endstep %}
+
+{% step %}
+### Import the network class
+
+In your frontend code, import the network class:
+
+{% code title="example.js" %}
+```javascript
+import { StacksTestnet } from "@stacks/network";
+```
+{% endcode %}
+{% endstep %}
+
+{% step %}
+### Configure the network with your QuickNode endpoint
+
+Create the network instance using your QuickNode endpoint URL:
+
+{% code title="example.js" %}
+```javascript
+const network = new StacksTestnet({ url: "" });
+```
+{% endcode %}
+
+Replace \ with the full endpoint URL provided by QuickNode.
+{% endstep %}
+
+{% step %}
+### Use with @stacks/transactions
+
+You can now call transactions and other Stacks RPC methods as you normally would using the `@stacks/transactions` library, passing the `network` instance where required.
+
+For an example integration and walkthrough, refer to the Hello Stacks tutorial.
+{% endstep %}
+{% endstepper %}
diff --git a/docs/operate/readme/run-a-pruned-bitcoin-node.md b/docs/operate/readme/run-a-pruned-bitcoin-node.md
new file mode 100644
index 0000000000..e5b5c22356
--- /dev/null
+++ b/docs/operate/readme/run-a-pruned-bitcoin-node.md
@@ -0,0 +1,255 @@
+# Run a Pruned Bitcoin Node
+
+This guide is written for a Unix based system. It's reasonable to expect some modifications will be required for other operating systems.
+
+When started, the pruned Bitcoin node will take roughly \~24 hours to reach chain tip.
+
+{% hint style="warning" %}
+While bitcoin is syncing, it's recommended to keep a stacks-blockchain node at chain tip, or [use a stacks chainstate archive](https://docs.hiro.so/stacks/archive/guides/stacks-blockchain).
+{% endhint %}
+
+Requirements:
+
+* Bitcoin Core >= v25.0
+ * https://github.com/bitcoin/bitcoin
+ * https://bitcoincore.org/en/download/
+* Host with a minimum of:
+ * 2 vCPU (a single dedicated cpu for the bitcoind process)
+ * 4GB Memory (during sync, more available memory will improve sync time)
+ * 50GB free disk space (actual usage is closer to 20GB)
+* User account: `bitcoin:bitcoin`
+* Chainstate directory located at: `/bitcoin/mainnet`
+ * `bitcoin` user must have read/write access.
+* Config directory located at: `/etc/bitcoin`
+ * `bitcoin` user must have at least read access
+
+Caveats
+
+[BIP-0159](https://github.com/bitcoin/bips/blob/master/bip-0159.mediawiki)
+
+In short, this BIP specifies that pruned nodes will advertise the service bit `NODE_NETWORK_LIMITED`, which restricts syncing blocks older than 288 blocks (\~2 days).
+
+What this means is that in practice, a stacks-blockchain node:
+
+* Cannot sync from genesis using a pruned node.
+* Must not be offline or otherwise down for longer than \~2 days (or 288 Bitcoin blocks).
+
+{% stepper %}
+{% step %}
+### Add bitcoin user and set file ownership
+
+```shell
+$ sudo mkdir -p /bitcoin/mainnet
+$ sudo mkdir /etc/bitcoin
+$ sudo useradd bitcoin -d /bitcoin
+$ sudo chown -R bitcoin:bitcoin /bitcoin /etc/bitcoin/
+```
+{% endstep %}
+
+{% step %}
+### Bitcoin Config
+
+Below is a sample config used to sync a pruned bitcoin node - feel free to adjust as needed.
+
+{% hint style="info" %}
+If using the [systemd unit below](run-a-pruned-bitcoin-node.md#systemd-unit-file), save this file as `/etc/bitcoin/bitcoin.conf`
+{% endhint %}
+
+Notes:
+
+* `btuser:btcpass` is hardcoded as an rpcauth user/password ([generated using this script](https://github.com/bitcoin/bitcoin/tree/master/share/rpcauth)).
+* Only localhost access is allowed (`127.0.0.1`) on the standard mainnet ports.
+* Pruning is set to be small, storing only the last 1GB of blocks (for p2p traffic, this is more than enough).
+* `dbcache` is set to the maximum of 16GB.
+* Wallet (and wallet rpc calls) are disabled.
+
+```
+## [rpc]
+
+# Accept command line and JSON-RPC commands.
+server=1
+
+# Allow JSON-RPC connections from specified source.
+rpcallowip=127.0.0.1/0
+
+# Bind to given address to listen for JSON-RPC connections.
+rpcbind=127.0.0.1:8332
+
+# Username and HMAC-SHA-256 hashed password for JSON-RPC connections.
+
+# Use the script at https://github.com/bitcoin/bitcoin/tree/master/share/rpcauth to generate
+
+# Note: may be specified multiple times for different users.
+rpcauth=btcuser:18857b4df4b1f0f5e6b1d7884617ab39$de6e02e1da8ee138ee702e13e0637e24679d844756216b066c3aeac4bcac5e10 # btuser:btcpass
+
+# Optional: rpcwhitelist can restrict listed RPC calls to specific rpcauth users.
+
+# Uncomment the below the restrict the `limited` user to a small subset of `get` commands
+
+# rpcauth=limited:350c91a60895b567c4662c27e63e9a41$25188b0f51f2f974dcdc75c1e0d41174e8f7ae19fb96927abf68ac5bc1e8897b # limited:limited
+
+# rpcwhitelist=limited:getblockchaininfo,getblock,getblockcount,getblockhash,getblockheader,getnetworkinfo
+
+# rpcwhitelistdefault=0
+
+## [core]
+
+# Specify data directory
+datadir=/bitcoin/mainnet
+
+# Do not keep transactions in the mempool longer than hours (default: 336)
+mempoolexpiry=24
+
+# Bind to given address and always listen on it (default: 0.0.0.0)
+bind=127.0.0.1:8333
+
+# Maximum database cache size MiB (4 to 16384, default: 450). In addition, unused mempool memory is shared for this cache
+dbcache=16384
+
+# Maintain a full transaction index, used by the getrawtransaction rpc call (**Running a pruned node requires that this option is disabled**)
+txindex=0
+
+# Reduce storage requirements by enabling pruning (deleting) of old
+
+# blocks. This allows the pruneblockchain RPC to be called to
+
+# delete specific blocks and enables automatic pruning of old
+
+# blocks if a target size in MiB is provided. This mode is
+
+# incompatible with -txindex. Warning: Reverting this setting
+
+# requires re-downloading the entire blockchain. (default: 0 =
+
+# disable pruning blocks, 1 = allow manual pruning via RPC, >=550 =
+
+# automatically prune block files to stay under the specified
+
+# target size in MiB)
+prune=1024 # 1GB of chainstate is enough for p2p block data (if using the RPC,this can be adjusted higher to store more blocks)
+
+## [wallet]
+
+# Do not load the wallet and disable wallet RPC calls
+disablewallet=1
+```
+{% endstep %}
+
+{% step %}
+### Systemd unit file
+
+ref: https://github.com/bitcoin/bitcoin/blob/master/contrib/init/bitcoind.service
+
+```
+[Unit]
+Description=Bitcoin daemon
+Documentation=https://github.com/bitcoin/bitcoin/blob/master/doc/init.md
+
+# https://www.freedesktop.org/wiki/Software/systemd/NetworkTarget/
+After=network-online.target
+Wants=network-online.target
+
+[Service]
+ExecStart=/usr/bin/bitcoind -pid=/run/bitcoind/bitcoind.pid \
+ -conf=/etc/bitcoin/bitcoin.conf \
+ -startupnotify='systemd-notify --ready' \
+ -shutdownnotify='systemd-notify --stopping'
+
+# Make sure the config directory is readable by the service user
+PermissionsStartOnly=true
+ExecStartPre=/bin/chgrp bitcoin /etc/bitcoin
+
+# Process management
+####################
+
+Type=notify
+NotifyAccess=all
+PIDFile=/run/bitcoind/bitcoind.pid
+
+Restart=on-failure
+TimeoutStartSec=infinity
+TimeoutStopSec=600
+
+# Directory creation and permissions
+####################################
+
+# Run as bitcoin:bitcoin
+User=bitcoin
+Group=bitcoin
+
+# /run/bitcoind
+RuntimeDirectory=bitcoind
+RuntimeDirectoryMode=0710
+
+# /etc/bitcoin
+ConfigurationDirectory=bitcoin
+ConfigurationDirectoryMode=0710
+
+# /var/lib/bitcoind
+StateDirectory=bitcoind
+StateDirectoryMode=0710
+
+# Hardening measures
+####################
+
+# Provide a private /tmp and /var/tmp.
+PrivateTmp=true
+
+# Mount /usr, /boot/ and /etc read-only for the process.
+ProtectSystem=full
+
+# Deny access to /home, /root and /run/user
+ProtectHome=true
+
+# Disallow the process and all of its children to gain
+
+# new privileges through execve().
+NoNewPrivileges=true
+
+# Use a new /dev namespace only populated with API pseudo devices
+
+# such as /dev/null, /dev/zero and /dev/random.
+PrivateDevices=true
+
+# Deny the creation of writable and executable memory mappings.
+MemoryDenyWriteExecute=true
+
+# Restrict ABIs to help ensure MemoryDenyWriteExecute is enforced
+SystemCallArchitectures=native
+
+[Install]
+WantedBy=multi-user.target
+```
+{% endstep %}
+
+{% step %}
+### Enable and start the Bitcoin service
+
+```shell
+$ sudo systemctl daemon-reload
+$ sudo systemctl enable bitcoin.service
+$ sudo systemctl start bitcoin.service
+```
+{% endstep %}
+
+{% step %}
+### Track sync progress
+
+{% hint style="info" %}
+Once started, you may track the sync progress:
+
+```
+$ sudo tail -f /bitcoin/mainnet/debug.log
+2024-12-05T19:35:31Z UpdateTip: new best=00000000000000000058990a84cc8f8eab25dbbd572f123f9190cea7256d7349 height=509258 version=0x20000000 log2_work=88.128280 tx=299522737 date='2018-02-15T03:42:14Z' progress=0.295203 cache=43.5MiB(172740txo)
+...
+$ bitcoin-cli \
+ -rpcconnect=127.0.0.1 \
+ -rpcport=8332 \
+ -rpcuser=btcuser \
+ -rpcpassword=btcpass \
+ getblockcount
+509016
+```
+{% endhint %}
+{% endstep %}
+{% endstepper %}
diff --git a/docs/operate/run-a-miner/README.md b/docs/operate/run-a-miner/README.md
new file mode 100644
index 0000000000..f0da72f8a3
--- /dev/null
+++ b/docs/operate/run-a-miner/README.md
@@ -0,0 +1,5 @@
+# Run a Miner
+
+If you are interested in running a Stacks miner, there are a few things you'll need to understand. Running a miner is similar to running a node, but you'll need to set up some additional configuration.
+
+These guides will help you get up and running with both a testnet and mainnet Stacks miner.
diff --git a/docs/operate/run-a-miner/mine-mainnet-stacks-tokens.md b/docs/operate/run-a-miner/mine-mainnet-stacks-tokens.md
new file mode 100644
index 0000000000..8f1df5a046
--- /dev/null
+++ b/docs/operate/run-a-miner/mine-mainnet-stacks-tokens.md
@@ -0,0 +1,302 @@
+# Mine Mainnet Stacks Tokens
+
+### Introduction
+
+For more on the technical details of mining, please review the mining guide.
+
+The following is an abridged version of the [walkthrough here](https://github.com/stacksfoundation/miner-docs), written for a Linux system. If you're on Windows or MacOS, there will be some slight modifications needed (PR's welcome!).
+
+If you're interested in mining on the Stacks mainnet, you can find instructions on how to do that here:
+
+### Running a Bitcoin Mainnet Full Node
+
+To participate as a miner on mainnet, you must have access to a mainnet bitcoin node with a wallet (and the wallet's private key). One way to accomplish this is to run bitcoin locally.
+
+* [Ensure your computer meets the minimum hardware requirements before continuing.](https://bitcoin.org/en/bitcoin-core/features/requirements#system-requirements)
+
+First, download a [bitcoin binary](https://bitcoin.org/en/download), or [build from source](https://github.com/stacksfoundation/miner-docs/blob/main/bitcoin.md#source-install) (_there may be some extra requirements to building,_ [_defined here_](https://github.com/stacksfoundation/miner-docs/blob/main/prerequisites.md#install-required-packages)).
+
+If you want to learn more about the technical details of mining, please review the mining guide:
+
+{% hint style="info" %}
+**Tip:** It is recommended to use a persistent location for the chainstate, in the steps below we're using `/bitcoin`.
+{% endhint %}
+
+#### Update the Bitcoin Configuration File
+
+Next, update the bitcoin configuration:
+
+* **Optional, but recommended:** Use a persistent directory to store the Bitcoin chainstate, i.e. `datadir=/bitcoin`.
+* **Optional, but recommended:** Update the `rpcallowip` value to only allow `127.0.0.1`, or the stacks miner IPv4.
+* Modify the `rpcuser` and `rpcpassword` values from the defaults below.
+* Store the following configuration somewhere on your filesystem (ex: `$HOME/bitcoin.conf`).
+
+```toml
+server=1
+disablewallet=0
+datadir=/bitcoin
+rpcuser=btcuser
+rpcpassword=btcpass
+rpcallowip=0.0.0.0/0
+bind=0.0.0.0:8333
+rpcbind=0.0.0.0:8332
+dbcache=512
+banscore=1
+rpcthreads=256
+rpcworkqueue=256
+rpctimeout=100
+txindex=1
+```
+
+#### Start Bitcoin
+
+Finally, start `bitcoind` as follows (adjust the `conf` path to where it was created in the previous step, i.e. `$HOME/bitcoin.conf`):
+
+```bash
+bitcoind -conf=$HOME/bitcoin.conf
+```
+
+{% hint style="info" %}
+**Note:** It will take a few hours for the node to synchronize with Bitcoin Mainnet.
+{% endhint %}
+
+While it's syncing, you can track the progress with `bitcoin-cli` or the logfile (will be located where the chainstate is stored, i.e. `/bitcoin/debug.log`):
+
+```bash
+$ bitcoin-cli \
+ -rpcconnect=127.0.0.1 \
+ -rpcport=8332 \
+ -rpcuser=btcuser \
+ -rpcpassword=btcpass \
+getblockchaininfo | jq .blocks
+836745
+```
+
+### Running a Stacks Blockchain miner
+
+First, download the latest tagged [stacks blockchain binary](https://github.com/stacks-network/stacks-blockchain/releases/latest), or [build from source](https://github.com/stacksfoundation/miner-docs/blob/main/stacks-blockchain.md#build-and-install-stacks-blockchain-from-source) (_there may be some extra requirements to building,_ [_defined here_](https://github.com/stacksfoundation/miner-docs/blob/main/prerequisites.md#install-required-packages)).
+
+{% hint style="info" %}
+**Tip:** It is recommended to use a persistent location for the chainstate, in the steps below we're using `/stacks-blockchain`.
+{% endhint %}
+
+#### Generate a keychain
+
+First, a keychain needs to be generated. With this keychain, we'll purchase some BTC from a cryptocurrency exchange, and then use that BTC to start mining.
+
+To create a keychain, the simplest way is to use the [stacks-cli](https://docs.hiro.so/references/stacks-cli) with the `make_keychain` command.
+
+```bash
+npx @stacks/cli make_keychain 2>/dev/null | jq -r
+```
+
+After this runs, you should see some JSON printed to the screen that looks like this:
+
+```json
+{
+ "mnemonic": "spare decade dog ghost luxury churn flat lizard inch nephew nut drop huge divert mother soccer father zebra resist later twin vocal slender detail",
+ "keyInfo": {
+ "privateKey": "ooxeemeitar4ahw0ca8anu4thae7aephahshae1pahtae5oocahthahho4ahn7eici",
+ "address": "SPTXOG3AIHOHNAEH5AU6IEX9OOTOH8SEIWEI5IJ9",
+ "btcAddress": "Ook6goo1Jee5ZuPualeiqu9RiN8wooshoo",
+ "wif": "rohCie2ein2chaed9kaiyoo6zo1aeQu1yae4phooShov2oosh4ox",
+ "index": 0
+ }
+}
+```
+
+{% hint style="danger" %}
+**Do not lose this information** - we'll need to use the `privateKey`, `btcAddress` and `wif` fields in later steps.
+{% endhint %}
+
+The above `wif` (`Kyk49jsPGen5C1ThhyJJH4CndLk8yLESuQJVGsbbTV3FFF9CRTJG`) will then need to be imported into the bitcoin mainnet network.
+
+Next, a bitcoin wallet is created:
+
+```bash
+bitcoin-cli \
+ -rpcconnect=127.0.0.1 \
+ -rpcport=8332 \
+ -rpcuser=btcuser \
+ -rpcpassword=btcpass \
+ createwallet \
+ wallet_name="miner" \
+ disable_private_keys=false \
+ blank=false \
+ passphrase="" \
+ avoid_reuse=false \
+ descriptors=false \
+ load_on_startup=true
+```
+
+Now, import your wif (bitcoin private key) inside the newly created wallet.
+
+{% hint style="info" %}
+**Note:** Be sure to replace `` with the wif value in the `Generate a keychain` step.
+{% endhint %}
+
+```bash
+bitcoin-cli \
+ -rpcport=8332 \
+ -rpcuser=btcuser \
+ -rpcpassword=btcpassword \
+ importprivkey
+```
+
+{% hint style="info" %}
+**Note:** The import may take a while, because a wallet rescan is triggered. After the import has completed successfully, you can check that the address is imported with `getaddressinfo`.
+{% endhint %}
+
+```bash
+bitcoin-cli \
+ -rpcconnect=127.0.0.1 \
+ -rpcport=8332 \
+ -rpcuser=btcuser \
+ -rpcpassword=btcpass \
+ getaddressinfo
+```
+
+Once imported, we need to get some BTC to that address. You should be able to transfer BTC to this address using a cryptocurrency exchange such as [Coinbase](https://www.coinbase.com/), [Binance](https://www.binance.com/), or [Kraken](https://www.kraken.com/).
+
+#### Update the Stacks Blockchain Configuration File
+
+Now, we need to configure our node to use this Bitcoin keychain. Copy the [sample mainnet miner config](https://raw.githubusercontent.com/stacks-network/stacks-blockchain/master/testnet/stacks-node/conf/mainnet-miner-conf.toml) to your local machine in a _memorable_ location like `$HOME/mainnet-miner-conf.toml`.
+
+Next, update the stacks configuration:
+
+* **Optional, but recommended:** Use a persistent directory to store the Stacks chainstate, i.e. `working_dir = "/stacks-blockchain"`
+* From the `make_keychain` step, modify the `seed` and `mining_key` values with `privatekey`
+* Store the following configuration somewhere on your filesystem (ex: `$HOME/mainnet-miner-conf.toml`)
+
+```toml
+[node]
+working_dir = "/stacks-blockchain"
+rpc_bind = "0.0.0.0:20443"
+p2p_bind = "0.0.0.0:20444"
+seed = ""
+miner = true
+bootstrap_node = "02196f005965cebe6ddc3901b7b1cc1aa7a88f305bb8c5893456b8f9a605923893@seed.mainnet.hiro.so:20444,02539449ad94e6e6392d8c1deb2b4e61f80ae2a18964349bc14336d8b903c46a8c@cet.stacksnodes.org:20444,02ececc8ce79b8adf813f13a0255f8ae58d4357309ba0cedd523d9f1a306fcfb79@sgt.stacksnodes.org:20444,0303144ba518fe7a0fb56a8a7d488f950307a4330f146e1e1458fc63fb33defe96@est.stacksnodes.org:20444"
+mine_microblocks = false
+
+[burnchain]
+wallet_name = "miner"
+chain = "bitcoin"
+mode = "mainnet"
+peer_host = "127.0.0.1"
+username = ""
+password = ""
+rpc_port = 8332
+peer_port = 8333
+satoshis_per_byte = 100
+burn_fee_cap = 450000
+
+[miner]
+mining_key = ""
+activated_vrf_key_path = "/stacks-blockchain/saved_vrf_key.json"
+
+[connection_options]
+private_neighbors = false
+```
+
+#### Start the Stacks Blockchain
+
+To run your miner, run this in the command line:
+
+```bash
+stacks-node start --config $HOME/mainnet-miner-conf.toml
+```
+
+Your node should start. It will take some time to sync, and then your miner will be running.
+
+#### Enable Debug Logging
+
+In case you are running into issues or would like to see verbose logging, you can run your node with debug logging enabled. In the command line, run:
+
+```bash
+STACKS_LOG_DEBUG=1 stacks-node start --config $HOME/mainnet-miner-conf.toml
+```
+
+### Optional: Running a Stacks Blockchain miner with Docker
+
+Alternatively, you can run a Stacks mainnet miner with Docker.
+
+{% hint style="warning" %}
+Ensure you have [Docker](https://docs.docker.com/get-docker/) installed.
+{% endhint %}
+
+#### Generate a Keychain and Get Some Tokens
+
+Generate a keychain:
+
+```bash
+docker run -i node:20-alpine npx @stacks/cli make_keychain 2>/dev/null | jq -r
+```
+
+We need to get some BTC to that address. You should be able to transfer BTC to this address using a cryptocurrency exchange such as [Coinbase](https://www.coinbase.com/), [Binance](https://www.binance.com/), or [Kraken](https://www.kraken.com/).
+
+#### Update Stacks Blockchain Docker Configuration File
+
+Use the steps outlined above to create the configuration file.
+
+#### Start the Stacks Blockchain miner with Docker
+
+{% hint style="info" %}
+**Info:** The ENV VARS `RUST_BACKTRACE` and `STACKS_LOG_DEBUG` are optional. If removed, debug logs will be disabled.
+{% endhint %}
+
+```bash
+docker run -d \
+ --name stacks_miner \
+ --rm \
+ --network host \
+ -e RUST_BACKTRACE="full" \
+ -e STACKS_LOG_DEBUG="1" \
+ -v "$HOME/mainnet-miner-conf.toml:/src/stacks-node/mainnet-miner-conf.toml" \
+ -v "/stacks-blockchain:/stacks-blockchain" \
+ -p 20443:20443 \
+ -p 20444:20444 \
+ blockstack/stacks-blockchain:latest \
+/bin/stacks-node start --config /src/stacks-node/mainnet-miner-conf.toml
+```
+
+You can review the node logs with this command:
+
+```bash
+docker logs -f stacks_miner
+```
+
+### Optional: Running in Kubernetes with Helm
+
+In addition, you're also able to run a Stacks miner in a Kubernetes cluster using the [stacks-blockchain Helm chart](https://github.com/stacks-network/stacks-blockchain/tree/master/deployment/helm/stacks-blockchain).
+
+Ensure you have the following prerequisites installed:
+
+* [Docker](https://docs.docker.com/get-docker/)
+* [minikube](https://minikube.sigs.k8s.io/docs/start/) (Only needed if standing up a local Kubernetes cluster)
+* [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/)
+* [helm](https://helm.sh/docs/intro/install/)
+
+#### Generate keychain and get some tokens
+
+Use the steps outlined above
+
+#### Install the chart and run the miner
+
+To install the chart with the release name `my-release` and run the node as a miner:
+
+```bash
+minikube start # Only run this if standing up a local Kubernetes cluster
+helm repo add blockstack https://charts.blockstack.xyz
+helm install my-release blockstack/stacks-blockchain \
+ --set config.node.miner=true \
+ --set config.node.seed="your-privateKey-from-generate-keychain-step" \
+ --set config.burnchain.mode="mainnet"
+```
+
+You can review the node logs with this command:
+
+```bash
+kubectl logs -l app.kubernetes.io/name=stacks-blockchain
+```
+
+For more information on the Helm chart and configuration options, please refer to the [chart's homepage](https://github.com/stacks-network/stacks-blockchain/tree/master/deployment/helm/stacks-blockchain).
diff --git a/docs/operate/run-a-miner/mine-testnet-stacks-tokens.md b/docs/operate/run-a-miner/mine-testnet-stacks-tokens.md
new file mode 100644
index 0000000000..5053833301
--- /dev/null
+++ b/docs/operate/run-a-miner/mine-testnet-stacks-tokens.md
@@ -0,0 +1,316 @@
+# Mine Testnet Stacks Tokens
+
+### Introduction
+
+For more on the technical details of mining, please review the mining guide.
+
+The following is an abridged version of the [walkthrough here](https://github.com/stacksfoundation/miner-docs/tree/testnet), written for a Linux system. If you're on Windows or MacOS, there will be some slight modifications needed (PR's welcome!).
+
+If you're interested in mining on the Stacks testnet, you can find instructions on how to do that here:
+
+### Running a Bitcoin Testnet Full Node
+
+To participate as a miner on testnet, you must have access to a testnet bitcoin node with a wallet (and the wallet's private key). One way to accomplish this is to run bitcoin locally.
+
+* [Ensure your computer meets the minimum hardware requirements before continuing.](https://bitcoin.org/en/bitcoin-core/features/requirements#system-requirements)
+
+First, download a [bitcoin binary](https://bitcoin.org/en/download), or [build from source](https://github.com/stacksfoundation/miner-docs/blob/testnet/bitcoin.md#source-install) (_there may be some extra requirements to building,_ [_defined here_](https://github.com/stacksfoundation/miner-docs/blob/testnet/prerequisites.md#install-required-packages)).
+
+{% hint style="info" %}
+Tip: It is recommended to use a persistent location for the chainstate, in the steps below we're using `/bitcoin`.
+{% endhint %}
+
+#### Update the Bitcoin Configuration File
+
+Next, update the bitcoin configuration:
+
+* Optional, but recommended: Use a persistent directory to store the Bitcoin chainstate, i.e. `datadir=/bitcoin`.
+* Optional, but recommended: Update the `rpcallowip` value to only allow `127.0.0.1`, or the stacks miner IPv4.
+* Modify the `rpcuser` and `rpcpassword` values from the defaults below.
+* Store the following configuration somewhere on your filesystem (ex: `$HOME/bitcoin.conf`).
+
+```toml
+server=1
+testnet=1
+disablewallet=0
+datadir=/bitcoin
+rpcuser=btcuser
+rpcpassword=btcpass
+rpcallowip=0.0.0.0/0
+dbcache=512
+banscore=1
+rpcthreads=256
+rpcworkqueue=256
+rpctimeout=100
+txindex=1
+
+[test]
+bind=0.0.0.0:18333
+rpcbind=0.0.0.0:18332
+rpcport=18332
+```
+
+#### Start Bitcoin
+
+Finally, start `bitcoind` as follows (adjust the `conf` path to where it was created in the previous step, i.e. `$HOME/bitcoin.conf`):
+
+```bash
+bitcoind -conf=$HOME/bitcoin.conf
+```
+
+{% hint style="info" %}
+Note: It will take a few hours for the node to synchronize with Bitcoin Testnet.
+{% endhint %}
+
+While it's syncing, you can track the progress with `bitcoin-cli` or the logfile (will be located where the chainstate is stored, i.e. `/bitcoin/testnet3/debug.log`):
+
+```bash
+$ bitcoin-cli \
+ -rpcconnect=127.0.0.1 \
+ -rpcport=18332 \
+ -rpcuser=btcuser \
+ -rpcpassword=btcpass \
+getblockchaininfo | jq .blocks
+2583513
+```
+
+***
+
+### Running a Stacks Blockchain miner
+
+First, download the latest tagged [stacks blockchain binary](https://github.com/stacks-network/stacks-blockchain/releases/latest), or [build from source](https://github.com/stacksfoundation/miner-docs/blob/testnet/stacks-blockchain.md#build-and-install-stacks-blockchain-from-source) (_there may be some extra requirements to building,_ [_defined here_](https://github.com/stacksfoundation/miner-docs/blob/testnet/prerequisites.md#install-required-packages)).
+
+{% hint style="info" %}
+Tip: It is recommended to use a persistent location for the chainstate, in the steps below we're using `/stacks-blockchain`.
+{% endhint %}
+
+#### Generate a keychain
+
+First, a keychain needs to be generated. With this keychain, we'll get some testnet BTC from a faucet, and then use that BTC to start mining.
+
+To create a keychain, the simplest way is to use the [stacks-cli](https://docs.hiro.so/references/stacks-cli) with the `make_keychain` command.
+
+```bash
+npx @stacks/cli make_keychain -t 2>/dev/null | jq -r
+```
+
+After this runs, you should see some JSON printed to the screen that looks like this:
+
+```json
+{
+ "mnemonic": "spare decade dog ghost luxury churn flat lizard inch nephew nut drop huge divert mother soccer father zebra resist later twin vocal slender detail",
+ "keyInfo": {
+ "privateKey": "ooxeemeitar4ahw0ca8anu4thae7aephahshae1pahtae5oocahthahho4ahn7eici",
+ "address": "STTXOG3AIHOHNAEH5AU6IEX9OOTOH8SEIWEI5IJ9",
+ "btcAddress": "Ook6goo1Jee5ZuPualeiqu9RiN8wooshoo",
+ "wif": "rohCie2ein2chaed9kaiyoo6zo1aeQu1yae4phooShov2oosh4ox",
+ "index": 0
+ }
+}
+```
+
+{% hint style="danger" %}
+Do not lose this information - we'll need to use the `privateKey`, `btcAddress` and `wif` fields in later steps.
+{% endhint %}
+
+The above `wif` (`cPdTdMgww2njhnekUZmHmFNKsWAjVdCR4cfvD2Y4UQhFzMmwoW33`) will then need to be imported into the bitcoin testnet network.
+
+Next, a bitcoin wallet is created:
+
+```bash
+bitcoin-cli \
+ -rpcconnect=127.0.0.1 \
+ -rpcport=18332 \
+ -rpcuser=btcuser \
+ -rpcpassword=btcpass \
+ createwallet "miner" \
+ false \
+ false \
+ "" \
+ false \
+ false \
+ true
+```
+
+Now, import your wif (bitcoin private key) inside the newly created wallet.
+
+{% hint style="info" %}
+Note: Be sure to replace `` with the wif value in the `Generate a keychain` step.
+{% endhint %}
+
+```bash
+bitcoin-cli \
+ -rpcport=18332 \
+ -rpcuser=btcuser \
+ -rpcpassword=btcpassword \
+ importprivkey
+```
+
+{% hint style="info" %}
+Note: The import may take a while, because a wallet rescan is triggered. After the import has completed successfully, you can check that the address is imported with `getaddressinfo`.
+{% endhint %}
+
+```bash
+bitcoin-cli \
+ -rpcconnect=127.0.0.1 \
+ -rpcport=18332 \
+ -rpcuser=btcuser \
+ -rpcpassword=btcpass \
+ getaddressinfo
+```
+
+Once imported, we need to get some testnet BTC to that address. Grab the `btcAddress` field, and paste it into [this Bitcoin testnet faucet](https://tbtc.bitaps.com/). You'll be sent `0.01` testnet BTC to that address.
+
+#### Update the Stacks Blockchain Configuration File
+
+Now, we need to configure our node to use this Bitcoin keychain. Copy the [sample testnet miner config](https://raw.githubusercontent.com/stacks-network/stacks-blockchain/master/testnet/stacks-node/conf/testnet-miner-conf.toml) to your local machine in a memorable location like `$HOME/testnet-miner-conf.toml`.
+
+Next, update the stacks configuration:
+
+* Optional, but recommended: Use a persistent directory to store the Stacks chainstate, i.e. `working_dir = "/stacks-blockchain"`
+* From the `make_keychain` step, modify the `seed` value with `privatekey`
+* Store the following configuration somewhere on your filesystem (ex: `$HOME/testnet-miner-conf.toml`)
+
+```toml
+[node]
+working_dir = "/stacks-blockchain"
+rpc_bind = "0.0.0.0:20443"
+p2p_bind = "0.0.0.0:20444"
+seed = ""
+miner = true
+bootstrap_node = "029266faff4c8e0ca4f934f34996a96af481df94a89b0c9bd515f3536a95682ddc@seed.testnet.hiro.so:30444"
+mine_microblocks = false
+wait_time_for_microblocks = 10000
+
+[burnchain]
+wallet_name = "miner"
+chain = "bitcoin"
+mode = "xenon"
+peer_host = "127.0.0.1"
+username = ""
+password = ""
+rpc_port = 18332
+peer_port = 18333
+
+[[ustx_balance]]
+address = "ST2QKZ4FKHAH1NQKYKYAYZPY440FEPK7GZ1R5HBP2"
+amount = 10000000000000000
+
+[[ustx_balance]]
+address = "ST319CF5WV77KYR1H3GT0GZ7B8Q4AQPY42ETP1VPF"
+amount = 10000000000000000
+
+[[ustx_balance]]
+address = "ST221Z6TDTC5E0BYR2V624Q2ST6R0Q71T78WTAX6H"
+amount = 10000000000000000
+
+[[ustx_balance]]
+address = "ST2TFVBMRPS5SSNP98DQKQ5JNB2B6NZM91C4K3P7B"
+amount = 10000000000000000
+```
+
+#### Start the Stacks Blockchain
+
+To run your miner, run this in the command line:
+
+```bash
+stacks-node start --config $HOME/testnet-miner-conf.toml
+```
+
+Your node should start. It will take some time to sync, and then your miner will be running.
+
+#### Enable Debug Logging
+
+In case you are running into issues or would like to see verbose logging, you can run your node with debug logging enabled. In the command line, run:
+
+```bash
+STACKS_LOG_DEBUG=1 stacks-node start --config $HOME/testnet-miner-conf.toml
+```
+
+***
+
+### Optional: Running a Stacks Blockchain miner with Docker
+
+Alternatively, you can run a Stacks testnet miner with Docker.
+
+{% hint style="warning" %}
+Ensure you have [Docker](https://docs.docker.com/get-docker/) installed.
+{% endhint %}
+
+#### Generate a Keychain and Get Some Tokens
+
+Generate a keychain:
+
+```bash
+docker run -i node:20-alpine npx @stacks/cli make_keychain 2>/dev/null | jq -r
+```
+
+Now, we need to get some tBTC. Grab the `btcAddress` field, and paste it into [this Bitcoin testnet faucet](https://tbtc.bitaps.com/). You'll be sent `0.01` tBTC to that address.
+
+#### Update Stacks Blockchain Docker Configuration File
+
+Use the steps outlined above to create the configuration file.
+
+#### Start the Stacks Blockchain miner with Docker
+
+{% hint style="info" %}
+Info: The ENV VARS `RUST_BACKTRACE` and `STACKS_LOG_DEBUG` are optional. If removed, debug logs will be disabled.
+{% endhint %}
+
+```bash
+docker run -d \
+ --name stacks_miner \
+ --rm \
+ --network host \
+ -e RUST_BACKTRACE="full" \
+ -e STACKS_LOG_DEBUG="1" \
+ -v "$HOME/testnet-miner-conf.toml:/src/stacks-node/testnet-miner-conf.toml" \
+ -v "/stacks-blockchain:/stacks-blockchain" \
+ -p 20443:20443 \
+ -p 20444:20444 \
+ blockstack/stacks-blockchain:latest \
+/bin/stacks-node start --config /src/stacks-node/testnet-miner-conf.toml
+```
+
+You can review the node logs with this command:
+
+```bash
+docker logs -f stacks_miner
+```
+
+***
+
+### Optional: Running in Kubernetes with Helm
+
+In addition, you're also able to run a Stacks miner in a Kubernetes cluster using the [stacks-blockchain Helm chart](https://github.com/stacks-network/stacks-blockchain/tree/master/deployment/helm/stacks-blockchain).
+
+Ensure you have the following prerequisites installed:
+
+* [Docker](https://docs.docker.com/get-docker/)
+* [minikube](https://minikube.sigs.k8s.io/docs/start/) (Only needed if standing up a local Kubernetes cluster)
+* [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/)
+* [helm](https://helm.sh/docs/intro/install/)
+
+#### Generate keychain and get some tokens
+
+Use the steps outlined above
+
+#### Install the chart and run the miner
+
+To install the chart with the release name `my-release` and run the node as a miner:
+
+```bash
+minikube start # Only run this if standing up a local Kubernetes cluster
+helm repo add blockstack https://charts.blockstack.xyz
+helm install my-release blockstack/stacks-blockchain \
+ --set config.node.miner=true \
+ --set config.node.seed="privateKey-from-generate-keychain-step" \
+```
+
+You can review the node logs with this command:
+
+```bash
+kubectl logs -l app.kubernetes.io/name=stacks-blockchain
+```
+
+For more information on the Helm chart and configuration options, please refer to the [chart's homepage](https://github.com/stacks-network/stacks-blockchain/tree/master/deployment/helm/stacks-blockchain).
diff --git a/docs/operate/run-a-miner/miner-costs-and-fees.md b/docs/operate/run-a-miner/miner-costs-and-fees.md
new file mode 100644
index 0000000000..291a94e499
--- /dev/null
+++ b/docs/operate/run-a-miner/miner-costs-and-fees.md
@@ -0,0 +1,36 @@
+# Miner Costs and Fees
+
+### Configuring Cost and Fee Estimation
+
+{% code title="config.toml" %}
+```toml
+[fee_estimation]
+cost_estimator = naive_pessimistic
+fee_estimator = fuzzed_weighted_median_fee_rate
+fee_rate_fuzzer_fraction = 0.1
+fee_rate_window_size = 5
+cost_metric = proportion_dot_product
+log_error = true
+enabled = true
+```
+{% endcode %}
+
+Fee and cost estimators observe transactions on the network and use the observed costs of those transactions to build estimates for viable fee rates and expected execution costs. Estimators and metrics can be selected using the configuration fields above (the defaults shown are currently the only options). `log_error` controls whether the INFO logger will display information about cost estimator accuracy as new costs are observed. Setting `enabled = false` turns off the cost estimators.
+
+{% hint style="info" %}
+Cost estimators are not consensus-critical components — they are intended for miners to rank mempool transactions or for clients to pick appropriate fee rates before broadcasting.
+{% endhint %}
+
+The `fuzzed_weighted_median_fee_rate` estimator:
+
+* uses a median estimate from a window of the fees paid in the last `fee_rate_window_size` blocks, and
+* then applies a uniform random "fuzz" up to `fee_rate_fuzzer_fraction` of the base estimate.
+
+
+
+Mining calculator (external)
+
+There is a mining calculator that can help with this process: https://friedger.github.io/mining-calculator/\
+Source code: https://github.com/friedger/mining-calculator
+
+
diff --git a/docs/operate/run-a-miner/miner-prerequisites.md b/docs/operate/run-a-miner/miner-prerequisites.md
new file mode 100644
index 0000000000..a75cefa59c
--- /dev/null
+++ b/docs/operate/run-a-miner/miner-prerequisites.md
@@ -0,0 +1,109 @@
+# Miner Prerequisites
+
+## Prerequisites
+
+### VM setup
+
+The VM will not need a lot of resources to run a miner - the most resources will be consumed during the blockchain syncs (for both Bitcoin and Stacks). For this example, we'll assume a [**Debian**](https://www.debian.org/) host with `x86_64` architecture (_commands may also work on any Debian-derived distribution_).
+
+A single CPU system with at least 4GB of memory and 1TB of disk space should be considered the minimum required specs to run the miner.
+
+#### VM Specs
+
+* Minimum CPU: `1 vCPU`
+* Minimum Memory: `4GB`
+* Minimum Storage: `1TB Disk` to allow for chainstate growth
+ * as of **July 2022**:
+ * Bitcoin chainstate is roughly `420GB`
+ * Stacks chainstate is roughly `45GB`
+
+#### Disk Configuration
+
+Two options here — either are fine but it's recommended to mount the chainstate from a separate disk that only contains the chainstate (see the first option).
+
+{% stepper %}
+{% step %}
+### Separate disks for chainstate(s) and OS
+
+* mount a dedicated disk for bitcoin at `/bitcoin` of 1TB
+* mount a dedicated disk for stacks-blockchain at `/stacks-blockchain` of at least 100GB
+* root volume `/` of at least 25GB
+{% endstep %}
+
+{% step %}
+### Combined Disk for all data
+
+* root volume `/` of at least 1TB
+{% endstep %}
+{% endstepper %}
+
+Create the required directories:
+
+{% code title="Create directories" %}
+```bash
+$ sudo mkdir -p /bitcoin
+$ sudo mkdir -p /stacks-blockchain
+$ sudo mkdir -p /etc/bitcoin
+$ sudo mkdir -p /etc/stacks-blockchain
+```
+{% endcode %}
+
+If using mounted disks: mount the disks to each filesystem created above — edit `/etc/fstab` to automount these disks at boot.
+
+Example `/etc/fstab` entries:
+
+```
+/dev/xvdb1 /bitcoin xfs rw,relatime,attr2,inode64,noquota
+/dev/xvdc1 /stacks-blockchain xfs rw,relatime,attr2,inode64,noquota
+```
+
+Mount the disks:
+
+```bash
+sudo mount -a
+```
+
+### Scripted install
+
+You can use the scripts/prerequisites.sh to install everything:
+
+```bash
+curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/stacksfoundation/miner-docs/main/scripts/prerequisites.sh | bash
+```
+
+### Install required packages
+
+The following packages are required and used by the rest of these docs:
+
+{% code title="Install packages" %}
+```bash
+$ curl -sL https://deb.nodesource.com/setup_16.x | sudo -E bash -
+$ sudo apt-get update -y && sudo apt-get install -y \
+ build-essential \
+ jq \
+ netcat \
+ nodejs \
+ git \
+ autoconf \
+ libboost-system-dev \
+ libboost-filesystem-dev \
+ libboost-thread-dev \
+ libboost-chrono-dev \
+ libevent-dev \
+ libzmq5 \
+ libtool \
+ m4 \
+ automake \
+ pkg-config \
+ libtool \
+ libboost-system-dev \
+ libboost-filesystem-dev \
+ libboost-chrono-dev \
+ libboost-program-options-dev \
+ libboost-test-dev \
+ libboost-thread-dev \
+ libboost-iostreams-dev
+$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh && source $HOME/.cargo/env
+$ sudo npm install -g @stacks/cli rimraf shx
+```
+{% endcode %}
diff --git a/docs/operate/run-a-miner/verify-miner.md b/docs/operate/run-a-miner/verify-miner.md
new file mode 100644
index 0000000000..47907ccf11
--- /dev/null
+++ b/docs/operate/run-a-miner/verify-miner.md
@@ -0,0 +1,21 @@
+# Verify Miner
+
+## Verify Configuration
+
+You can verify that your node is operating as a miner by checking its log output to verify that it was able to find its Bitcoin UTXOs:
+
+{% code title="logs" %}
+```bash
+$ head -n 1000 /path/to/your/node/logs | grep -i utxo
+INFO [1630127492.031042] [testnet/stacks-node/src/run_loop/neon.rs:146] [main] Miner node: checking UTXOs at address:
+INFO [1630127492.062652] [testnet/stacks-node/src/run_loop/neon.rs:164] [main] UTXOs found - will run as a Miner node
+```
+{% endcode %}
+
+## Verify Operations
+
+The first transaction of the miner is a registration transaction on Bitcoin. It just contains an `OP_RETURN` utxo.
+
+Thereafter, the miner creates for each block one transaction on Bitcoin with one data output, and two commit outputs to the stackers. The amount is half the value of the configured `burn_fee_cap` property.
+
+If the miner won a sortition, the corresponding Stacks address will create a tenure change transaction and a coinbase transaction. The block rewards will be awarded 100 blocks later if mining was successful.
diff --git a/docs/operate/run-a-node/run-a-bitcoin-node.md b/docs/operate/run-a-node/run-a-bitcoin-node.md
new file mode 100644
index 0000000000..b935cf30e2
--- /dev/null
+++ b/docs/operate/run-a-node/run-a-bitcoin-node.md
@@ -0,0 +1,236 @@
+# Run a Bitcoin Node
+
+{% stepper %}
+{% step %}
+### Requirements
+
+This guide is written for a Unix based system. It's reasonable to expect some modifications will be required for other operating systems.
+
+When started, the Bitcoin node will take several days to reach chain tip.
+
+* Bitcoin Core >= v25.0
+ * https://github.com/bitcoin/bitcoin
+ * https://bitcoincore.org/en/download/
+* Host with a minimum of:
+ * 2 vCPU (a single dedicated cpu for the bitcoind process)
+ * 4GB Memory (during sync, more available memory will improve sync time)
+ * 1TB free disk space
+* User account: `bitcoin:bitcoin`
+* Chainstate directory located at: `/bitcoin/mainnet`
+ * `bitcoin` user must have read/write access.
+* Config directory located at: `/etc/bitcoin`
+ * `bitcoin` user must have at least read access
+{% endstep %}
+
+{% step %}
+### Add bitcoin user and set file ownership
+
+Run the following commands:
+
+{% code title="Create directories and add user" %}
+```shell
+$ sudo mkdir -p /bitcoin/mainnet
+$ sudo mkdir /etc/bitcoin
+$ sudo useradd bitcoin -d /bitcoin
+$ sudo chown -R bitcoin:bitcoin /bitcoin /etc/bitcoin/
+```
+{% endcode %}
+{% endstep %}
+
+{% step %}
+### Bitcoin config
+
+Below is a sample config used to sync a bitcoin node - feel free to adjust as needed.
+
+{% hint style="info" %}
+If using the [systemd unit below](run-a-bitcoin-node.md#systemd-unit-file), save this file as `/etc/bitcoin/bitcoin.conf`
+{% endhint %}
+
+* `btuser:btcpass` is hardcoded as an rpcauth user/password ([generated using this script](https://github.com/bitcoin/bitcoin/tree/master/share/rpcauth)).
+* Only localhost access is allowed (`127.0.0.1`) on the standard mainnet ports.
+* `dbcache` is set to the maximum of 16GB.
+* Wallet (and wallet rpc calls) are disabled.
+
+{% code title="Sample /etc/bitcoin/bitcoin.conf" %}
+```
+## [rpc]
+
+# Accept command line and JSON-RPC commands.
+server=1
+
+# Allow JSON-RPC connections from specified source.
+rpcallowip=127.0.0.1/0
+
+# Bind to given address to listen for JSON-RPC connections.
+rpcbind=127.0.0.1:8332
+
+# Username and HMAC-SHA-256 hashed password for JSON-RPC connections.
+
+# Use the script at https://github.com/bitcoin/bitcoin/tree/master/share/rpcauth to generate
+
+# Note: may be specified multiple times for different users.
+rpcauth=btcuser:18857b4df4b1f0f5e6b1d7884617ab39$de6e02e1da8ee138ee702e13e0637e24679d844756216b066c3aeac4bcac5e10 # btuser:btcpass
+
+# Optional: rpcwhitelist can restrict listed RPC calls to specific rpcauth users.
+
+# Uncomment the below the restrict the `limited` user to a small subset of `get` commands
+
+# rpcauth=limited:350c91a60895b567c4662c27e63e9a41$25188b0f51f2f974dcdc75c1e0d41174e8f7ae19fb96927abf68ac5bc1e8897b # limited:limited
+
+# rpcwhitelist=limited:getblockchaininfo,getblock,getblockcount,getblockhash,getblockheader,getnetworkinfo
+
+# rpcwhitelistdefault=0
+
+## [core]
+
+# Specify data directory
+datadir=/bitcoin/mainnet
+
+# Do not keep transactions in the mempool longer than hours (default: 336)
+mempoolexpiry=24
+
+# Bind to given address and always listen on it (default: 0.0.0.0)
+bind=127.0.0.1:8333
+
+# Maximum database cache size MiB (4 to 16384, default: 450). In addition, unused mempool memory is shared for this cache
+dbcache=16384
+
+# Maintain a full transaction index, used by the getrawtransaction rpc call
+txindex=1
+
+## [wallet]
+
+# Do not load the wallet and disable wallet RPC calls
+disablewallet=1
+```
+{% endcode %}
+{% endstep %}
+
+{% step %}
+### Systemd unit file
+
+Reference: https://github.com/bitcoin/bitcoin/blob/master/contrib/init/bitcoind.service
+
+Save the following as your systemd unit (for example `/etc/systemd/system/bitcoin.service`):
+
+{% code title="bitcoind.service" %}
+```
+[Unit]
+Description=Bitcoin daemon
+Documentation=https://github.com/bitcoin/bitcoin/blob/master/doc/init.md
+
+# https://www.freedesktop.org/wiki/Software/systemd/NetworkTarget/
+After=network-online.target
+Wants=network-online.target
+
+[Service]
+ExecStart=/usr/bin/bitcoind -pid=/run/bitcoind/bitcoind.pid \
+ -conf=/etc/bitcoin/bitcoin.conf \
+ -startupnotify='systemd-notify --ready' \
+ -shutdownnotify='systemd-notify --stopping'
+
+# Make sure the config directory is readable by the service user
+PermissionsStartOnly=true
+ExecStartPre=/bin/chgrp bitcoin /etc/bitcoin
+
+# Process management
+####################
+
+Type=notify
+NotifyAccess=all
+PIDFile=/run/bitcoind/bitcoind.pid
+
+Restart=on-failure
+TimeoutStartSec=infinity
+TimeoutStopSec=600
+
+# Directory creation and permissions
+####################################
+
+# Run as bitcoin:bitcoin
+User=bitcoin
+Group=bitcoin
+
+# /run/bitcoind
+RuntimeDirectory=bitcoind
+RuntimeDirectoryMode=0710
+
+# /etc/bitcoin
+ConfigurationDirectory=bitcoin
+ConfigurationDirectoryMode=0710
+
+# /var/lib/bitcoind
+StateDirectory=bitcoind
+StateDirectoryMode=0710
+
+# Hardening measures
+####################
+
+# Provide a private /tmp and /var/tmp.
+PrivateTmp=true
+
+# Mount /usr, /boot/ and /etc read-only for the process.
+ProtectSystem=full
+
+# Deny access to /home, /root and /run/user
+ProtectHome=true
+
+# Disallow the process and all of its children to gain
+
+# new privileges through execve().
+NoNewPrivileges=true
+
+# Use a new /dev namespace only populated with API pseudo devices
+
+# such as /dev/null, /dev/zero and /dev/random.
+PrivateDevices=true
+
+# Deny the creation of writable and executable memory mappings.
+MemoryDenyWriteExecute=true
+
+# Restrict ABIs to help ensure MemoryDenyWriteExecute is enforced
+SystemCallArchitectures=native
+
+[Install]
+WantedBy=multi-user.target
+```
+{% endcode %}
+{% endstep %}
+
+{% step %}
+### Enable and start the Bitcoin service
+
+Run:
+
+{% code title="Enable and start service" %}
+```shell
+$ sudo systemctl daemon-reload
+$ sudo systemctl enable bitcoin.service
+$ sudo systemctl start bitcoin.service
+```
+{% endcode %}
+{% endstep %}
+
+{% step %}
+### Track sync progress
+
+{% hint style="info" %}
+Once started, you may track the sync progress:
+{% endhint %}
+
+{% code title="Tail debug log and query RPC" %}
+```
+$ sudo tail -f /bitcoin/mainnet/debug.log
+2024-12-05T19:35:31Z UpdateTip: new best=00000000000000000058990a84cc8f8eab25dbbd572f123f9190cea7256d7349 height=509258 version=0x20000000 log2_work=88.128280 tx=299522737 date='2018-02-15T03:42:14Z' progress=0.295203 cache=43.5MiB(172740txo)
+...
+$ bitcoin-cli \
+ -rpcconnect=127.0.0.1 \
+ -rpcport=8332 \
+ -rpcuser=btcuser \
+ -rpcpassword=btcpass \
+ getblockcount
+509016
+```
+{% endcode %}
+{% endstep %}
+{% endstepper %}
diff --git a/docs/operate/run-a-node/run-a-node-with-a-hosted-provider.md b/docs/operate/run-a-node/run-a-node-with-a-hosted-provider.md
new file mode 100644
index 0000000000..5a10fe2d30
--- /dev/null
+++ b/docs/operate/run-a-node/run-a-node-with-a-hosted-provider.md
@@ -0,0 +1,19 @@
+# Run a Node with a Hosted Provider
+
+We're always looking for new hosting providers that enable anyone to run the Stacks Blockchain. Below, you'll find some examples of the current providers that are known to support running a node.
+
+### Quicknode
+
+Please refer to the Quicknode Section for instructions on launching an instance with Quicknode.
+
+### Stacks on Render
+
+The [render-stacks](https://github.com/stacksfoundation/render-stacks) GitHub repo has instructions so anyone can deploy a Stacks node to the hosted [Render](https://render.com/) service in one click.
+
+{% hint style="warning" %}
+While it is possible to use the free plan with some modifications, it is recommended to run this on a paid plan.
+{% endhint %}
+
+### Stacks on Fly
+
+The [fly-stacks](https://github.com/stacksfoundation/fly-stacks) GitHub repo has instructions so anyone can deploy a Stacks node to the hosted [Fly](https://fly.io/) service.
diff --git a/docs/operate/run-a-node/run-a-node-with-digital-ocean.md b/docs/operate/run-a-node/run-a-node-with-digital-ocean.md
new file mode 100644
index 0000000000..5f125b0caa
--- /dev/null
+++ b/docs/operate/run-a-node/run-a-node-with-digital-ocean.md
@@ -0,0 +1,104 @@
+# Run a Node with Digital Ocean
+
+### Introduction
+
+This is a step by step guide to deploy the [Stacks Blockchain](https://github.com/stacks-network/stacks-blockchain) on [DigitalOcean](https://digitalocean.com/).
+
+Build code is hosted on this [Github repository](https://github.com/stacksfoundation/stacks-machine-images) using the [methods from here](https://github.com/stacks-network/stacks-blockchain-docker).
+
+### Steps
+
+{% stepper %}
+{% step %}
+### Create the Droplet from the Marketplace
+
+Go to the [Stacks Blockchain page](https://marketplace.digitalocean.com/apps/stacks-blockchain) in DigitalOcean's marketplace. Click on `Create Stacks Blockchain Droplet`.
+{% endstep %}
+
+{% step %}
+### Choose plan and region
+
+Choose a plan (it will only allow you to select a droplet that meets the minimum requirements) and your preferred datacenter region.
+{% endstep %}
+
+{% step %}
+### Authentication
+
+Enter a root password or [enable SSH keys](https://docs.digitalocean.com/products/droplets/how-to/add-ssh-keys/) if you prefer.
+{% endstep %}
+
+{% step %}
+### Create the Droplet
+
+You can leave the rest of the options as they are and click on `Create Droplet`.
+{% endstep %}
+
+{% step %}
+### Wait for creation
+
+You will need to wait a few seconds for the droplet to get created. Once created click on it to see more information.
+{% endstep %}
+
+{% step %}
+### Access the Droplet
+
+Congratulations! You are now running the Stacks Blockchain. You can click on `Console` for a terminal window to open or login using SSH to the public IP you've been assigned to with user `root`.
+{% endstep %}
+{% endstepper %}
+
+### Getting started after deploying Stacks Blockchain
+
+Once the droplet is launched, the initial startup can take several minutes while BNS data is imported (this is a one time operation) and the Bitcoin headers are synced.
+
+To keep track of the progress, you can SSH to the host and view logs:
+
+```bash
+ssh root@your_droplet_public_ipv4
+/opt/stacks-blockchain-docker/manage.sh -n mainnet -a logs
+```
+
+After the stacks blockchain finishes the initial header sync and starts to sync with its peers, the application ports will open (`20443` and `3999`) and HTTP port `80` will now start proxying requests.
+
+Use `http://your_droplet_public_ipv4` to access the data directly, with output being similar to:
+
+```json
+{
+ "server_version": "stacks-blockchain-api v6.2.3 (master:77ab3ae2)",
+ "status": "ready",
+ "chain_tip": {
+ "block_height": 91820,
+ "block_hash": "0x06b276e85f238151414616618ae0adaf5eeda4eac6cad5bbefceeb37948ab275",
+ "index_block_hash": "0x4d7c075d7ab0f90b1dbc175f5c42b7344265d00cfef202dd9681d95388eeed8c",
+ "microblock_hash": "0xcf4f9037cc10696b2812b617ca105885be625c6acf8ad67e71bb4c09fa6ebb21",
+ "microblock_sequence": 4
+ }
+}
+```
+
+{% hint style="info" %}
+For the full list of API endpoints for the Stacks Blockchain, consult the [Hiro API Docs](https://docs.hiro.so/api)
+{% endhint %}
+
+All services are managed by a [systemd unit file](https://github.com/stacksfoundation/stacks-machine-images/blob/master/files/etc/systemd/system/stacks.service) that is set to start on boot.
+
+Manual control is also possible via the [manage.sh script](https://github.com/stacks-network/stacks-blockchain-docker/blob/master/manage.sh) at `/opt/stacks-blockchain-docker/manage.sh` on the host.
+
+Full details on how to use the manage.sh script is [available here](https://github.com/stacks-network/stacks-blockchain-docker/blob/master/docs/usage.md).
+
+### Launching a Droplet using the DigitalOcean API
+
+In addition to creating a Droplet from the Stacks Blockchain 1-Click App via the control panel, you can also use the [DigitalOcean API](https://digitalocean.com/docs/api).
+
+As an example, to create a 4GB Stacks Blockchain Droplet in the SFO2 region, you can use the following curl command. You’ll need to either save your [API access token](https://docs.digitalocean.com/reference/api/create-personal-access-token/) to an environment variable or substitute it into the command below.
+
+{% hint style="info" %}
+The `name`, `region` and `size` values below are hardcoded, so adjust as desired.
+{% endhint %}
+
+```bash
+$ export TOKEN=
+$ curl -X POST -H 'Content-Type: application/json' \
+ -H 'Authorization: Bearer '$TOKEN'' -d \
+ '{"name":"stacks-blockchain","region":"sfo2","size":"s-2vcpu-4gb","image":"stacksfoundation-stacksblockchain"}' \
+ "https://api.digitalocean.com/v2/droplets"
+```
diff --git a/docs/operate/run-a-node/run-a-node-with-docker.md b/docs/operate/run-a-node/run-a-node-with-docker.md
new file mode 100644
index 0000000000..defe4be9b4
--- /dev/null
+++ b/docs/operate/run-a-node/run-a-node-with-docker.md
@@ -0,0 +1,119 @@
+# Run a Node with Docker
+
+### Stacks Blockchain with Docker
+
+Run your own Stacks Blockchain node using [docker-compose](https://docs.docker.com/compose/) with just a few commands using [stacks-blockchain-docker](https://github.com/stacks-network/stacks-blockchain-docker)
+
+### Requirements
+
+The minimum viable requirements are listed below.
+
+While you _can_ run a node using these specs, it's _recommended_ to assign more than the minimum for better performance.
+
+* ⚠️ [docker-compose](https://docs.docker.com/compose/install/) version `2.2.2` or greater is **required**
+* **8GB memory if running only a Stacks node**
+* **16 GB memory if running Stacks + Bitcoin node**
+* **1 Vcpu** ( _minimum of 2 Vcpu is recommended_ )
+* **500GB disk for Stacks node**
+* **1TB disk space for Bitcoin node**
+
+{% hint style="warning" %}
+MacOS with an ARM (M-series chip) processor is NOT recommended
+
+The way Docker for Mac on an Arm CPU is designed makes the I/O incredibly slow, and blockchains are _**very**_ heavy on I/O. This only seems to affect MacOS with the M-series chip, other Arm based systems like Raspberry Pi work as expected.
+{% endhint %}
+
+### Quickstart
+
+The `` placeholder used below can be replaced with one of:
+
+* mainnet
+* testnet
+* mocknet
+
+{% stepper %}
+{% step %}
+### Clone the repository
+
+Clone the stacks-blockchain-docker repository locally and change into the directory:
+
+{% code title="Clone repository" %}
+```bash
+git clone https://github.com/stacks-network/stacks-blockchain-docker && cd stacks-blockchain-docker
+```
+{% endcode %}
+{% endstep %}
+
+{% step %}
+### Start the services
+
+Start the docker-compose services for the chosen network:
+
+{% code title="Start services" %}
+```bash
+./manage.sh -n -a start
+```
+{% endcode %}
+
+{% hint style="info" %}
+With an optional HTTP proxy on port 80:
+
+{% code title="Start with proxy" %}
+```bash
+./manage.sh -n -a start -f proxy
+```
+{% endcode %}
+{% endhint %}
+{% endstep %}
+{% endstepper %}
+
+### Accessing the services
+
+{% hint style="info" %}
+For networks other than `mocknet`, downloading the initial headers can take several minutes. Until the headers are downloaded, the `/v2/info` endpoints won't return any data.
+
+Follow the logs to track the sync progress:
+
+{% code title="Follow logs" %}
+```bash
+./manage.sh -n -a logs
+```
+{% endcode %}
+{% endhint %}
+
+stacks-blockchain:
+
+* Ports `20443-20444` are exposed on `localhost`
+
+{% code title="Check stacks-blockchain /v2/info" %}
+```bash
+curl -sL localhost:20443/v2/info | jq -r
+```
+{% endcode %}
+
+stacks-blockchain-api:
+
+* Port `3999` is exposed on `localhost`
+
+{% code title="Check stacks-blockchain-api" %}
+```bash
+curl -sL localhost:3999 | jq -r
+```
+{% endcode %}
+
+proxy:
+
+* Port `80` is exposed on `localhost`
+
+{% code title="Check proxy" %}
+```bash
+curl -sL localhost/v2/info | jq -r
+curl -sL localhost | jq -r
+```
+{% endcode %}
+
+### Upgrades
+
+{% hint style="warning" %}
+For schema-breaking upgrades to running instances of this repo, you'll need to [run an event-replay](https://github.com/stacks-network/stacks-blockchain-docker/blob/master/docs/upgrade.md).
+{% endhint %}
diff --git a/docs/operate/run-a-node/run-a-node-with-quicknode.md b/docs/operate/run-a-node/run-a-node-with-quicknode.md
new file mode 100644
index 0000000000..aa06a7868b
--- /dev/null
+++ b/docs/operate/run-a-node/run-a-node-with-quicknode.md
@@ -0,0 +1,63 @@
+# Run a Node with Quicknode
+
+[QuickNode](https://www.quicknode.com/) is a service for rapidly getting set up with a Stacks node. As an easy and fast alternative to running your own node, you can utilize QuickNode to serve as an API.
+
+{% stepper %}
+{% step %}
+### Create a QuickNode account
+
+Sign up on QuickNode: https://www.quicknode.com/signup
+{% endstep %}
+
+{% step %}
+### Create an endpoint
+
+Once signed in, click "Create an endpoint". Select:
+
+* Stacks
+* your desired network (e.g., mainnet or testnet)
+* your desired QuickNode plan level
+
+After that you'll have an API endpoint URL you can use to connect to Stacks.
+{% endstep %}
+
+{% step %}
+### Install the Stacks network package
+
+Install the `@stacks/network` package in your frontend project.
+{% endstep %}
+
+{% step %}
+### Import the network class
+
+In your frontend code, import the network class:
+
+{% code title="example.js" %}
+```javascript
+import { StacksTestnet } from "@stacks/network";
+```
+{% endcode %}
+{% endstep %}
+
+{% step %}
+### Configure the network with your QuickNode endpoint
+
+Create the network instance using your QuickNode endpoint URL:
+
+{% code title="example.js" %}
+```javascript
+const network = new StacksTestnet({ url: "" });
+```
+{% endcode %}
+
+Replace \ with the full endpoint URL provided by QuickNode.
+{% endstep %}
+
+{% step %}
+### Use with @stacks/transactions
+
+You can now call transactions and other Stacks RPC methods as you normally would using the `@stacks/transactions` library, passing the `network` instance where required.
+
+For an example integration and walkthrough, refer to the Hello Stacks tutorial.
+{% endstep %}
+{% endstepper %}
diff --git a/docs/operate/run-a-node/run-a-pruned-bitcoin-node.md b/docs/operate/run-a-node/run-a-pruned-bitcoin-node.md
new file mode 100644
index 0000000000..e5b5c22356
--- /dev/null
+++ b/docs/operate/run-a-node/run-a-pruned-bitcoin-node.md
@@ -0,0 +1,255 @@
+# Run a Pruned Bitcoin Node
+
+This guide is written for a Unix based system. It's reasonable to expect some modifications will be required for other operating systems.
+
+When started, the pruned Bitcoin node will take roughly \~24 hours to reach chain tip.
+
+{% hint style="warning" %}
+While bitcoin is syncing, it's recommended to keep a stacks-blockchain node at chain tip, or [use a stacks chainstate archive](https://docs.hiro.so/stacks/archive/guides/stacks-blockchain).
+{% endhint %}
+
+Requirements:
+
+* Bitcoin Core >= v25.0
+ * https://github.com/bitcoin/bitcoin
+ * https://bitcoincore.org/en/download/
+* Host with a minimum of:
+ * 2 vCPU (a single dedicated cpu for the bitcoind process)
+ * 4GB Memory (during sync, more available memory will improve sync time)
+ * 50GB free disk space (actual usage is closer to 20GB)
+* User account: `bitcoin:bitcoin`
+* Chainstate directory located at: `/bitcoin/mainnet`
+ * `bitcoin` user must have read/write access.
+* Config directory located at: `/etc/bitcoin`
+ * `bitcoin` user must have at least read access
+
+Caveats
+
+[BIP-0159](https://github.com/bitcoin/bips/blob/master/bip-0159.mediawiki)
+
+In short, this BIP specifies that pruned nodes will advertise the service bit `NODE_NETWORK_LIMITED`, which restricts syncing blocks older than 288 blocks (\~2 days).
+
+What this means is that in practice, a stacks-blockchain node:
+
+* Cannot sync from genesis using a pruned node.
+* Must not be offline or otherwise down for longer than \~2 days (or 288 Bitcoin blocks).
+
+{% stepper %}
+{% step %}
+### Add bitcoin user and set file ownership
+
+```shell
+$ sudo mkdir -p /bitcoin/mainnet
+$ sudo mkdir /etc/bitcoin
+$ sudo useradd bitcoin -d /bitcoin
+$ sudo chown -R bitcoin:bitcoin /bitcoin /etc/bitcoin/
+```
+{% endstep %}
+
+{% step %}
+### Bitcoin Config
+
+Below is a sample config used to sync a pruned bitcoin node - feel free to adjust as needed.
+
+{% hint style="info" %}
+If using the [systemd unit below](run-a-pruned-bitcoin-node.md#systemd-unit-file), save this file as `/etc/bitcoin/bitcoin.conf`
+{% endhint %}
+
+Notes:
+
+* `btuser:btcpass` is hardcoded as an rpcauth user/password ([generated using this script](https://github.com/bitcoin/bitcoin/tree/master/share/rpcauth)).
+* Only localhost access is allowed (`127.0.0.1`) on the standard mainnet ports.
+* Pruning is set to be small, storing only the last 1GB of blocks (for p2p traffic, this is more than enough).
+* `dbcache` is set to the maximum of 16GB.
+* Wallet (and wallet rpc calls) are disabled.
+
+```
+## [rpc]
+
+# Accept command line and JSON-RPC commands.
+server=1
+
+# Allow JSON-RPC connections from specified source.
+rpcallowip=127.0.0.1/0
+
+# Bind to given address to listen for JSON-RPC connections.
+rpcbind=127.0.0.1:8332
+
+# Username and HMAC-SHA-256 hashed password for JSON-RPC connections.
+
+# Use the script at https://github.com/bitcoin/bitcoin/tree/master/share/rpcauth to generate
+
+# Note: may be specified multiple times for different users.
+rpcauth=btcuser:18857b4df4b1f0f5e6b1d7884617ab39$de6e02e1da8ee138ee702e13e0637e24679d844756216b066c3aeac4bcac5e10 # btuser:btcpass
+
+# Optional: rpcwhitelist can restrict listed RPC calls to specific rpcauth users.
+
+# Uncomment the below the restrict the `limited` user to a small subset of `get` commands
+
+# rpcauth=limited:350c91a60895b567c4662c27e63e9a41$25188b0f51f2f974dcdc75c1e0d41174e8f7ae19fb96927abf68ac5bc1e8897b # limited:limited
+
+# rpcwhitelist=limited:getblockchaininfo,getblock,getblockcount,getblockhash,getblockheader,getnetworkinfo
+
+# rpcwhitelistdefault=0
+
+## [core]
+
+# Specify data directory
+datadir=/bitcoin/mainnet
+
+# Do not keep transactions in the mempool longer than hours (default: 336)
+mempoolexpiry=24
+
+# Bind to given address and always listen on it (default: 0.0.0.0)
+bind=127.0.0.1:8333
+
+# Maximum database cache size MiB (4 to 16384, default: 450). In addition, unused mempool memory is shared for this cache
+dbcache=16384
+
+# Maintain a full transaction index, used by the getrawtransaction rpc call (**Running a pruned node requires that this option is disabled**)
+txindex=0
+
+# Reduce storage requirements by enabling pruning (deleting) of old
+
+# blocks. This allows the pruneblockchain RPC to be called to
+
+# delete specific blocks and enables automatic pruning of old
+
+# blocks if a target size in MiB is provided. This mode is
+
+# incompatible with -txindex. Warning: Reverting this setting
+
+# requires re-downloading the entire blockchain. (default: 0 =
+
+# disable pruning blocks, 1 = allow manual pruning via RPC, >=550 =
+
+# automatically prune block files to stay under the specified
+
+# target size in MiB)
+prune=1024 # 1GB of chainstate is enough for p2p block data (if using the RPC,this can be adjusted higher to store more blocks)
+
+## [wallet]
+
+# Do not load the wallet and disable wallet RPC calls
+disablewallet=1
+```
+{% endstep %}
+
+{% step %}
+### Systemd unit file
+
+ref: https://github.com/bitcoin/bitcoin/blob/master/contrib/init/bitcoind.service
+
+```
+[Unit]
+Description=Bitcoin daemon
+Documentation=https://github.com/bitcoin/bitcoin/blob/master/doc/init.md
+
+# https://www.freedesktop.org/wiki/Software/systemd/NetworkTarget/
+After=network-online.target
+Wants=network-online.target
+
+[Service]
+ExecStart=/usr/bin/bitcoind -pid=/run/bitcoind/bitcoind.pid \
+ -conf=/etc/bitcoin/bitcoin.conf \
+ -startupnotify='systemd-notify --ready' \
+ -shutdownnotify='systemd-notify --stopping'
+
+# Make sure the config directory is readable by the service user
+PermissionsStartOnly=true
+ExecStartPre=/bin/chgrp bitcoin /etc/bitcoin
+
+# Process management
+####################
+
+Type=notify
+NotifyAccess=all
+PIDFile=/run/bitcoind/bitcoind.pid
+
+Restart=on-failure
+TimeoutStartSec=infinity
+TimeoutStopSec=600
+
+# Directory creation and permissions
+####################################
+
+# Run as bitcoin:bitcoin
+User=bitcoin
+Group=bitcoin
+
+# /run/bitcoind
+RuntimeDirectory=bitcoind
+RuntimeDirectoryMode=0710
+
+# /etc/bitcoin
+ConfigurationDirectory=bitcoin
+ConfigurationDirectoryMode=0710
+
+# /var/lib/bitcoind
+StateDirectory=bitcoind
+StateDirectoryMode=0710
+
+# Hardening measures
+####################
+
+# Provide a private /tmp and /var/tmp.
+PrivateTmp=true
+
+# Mount /usr, /boot/ and /etc read-only for the process.
+ProtectSystem=full
+
+# Deny access to /home, /root and /run/user
+ProtectHome=true
+
+# Disallow the process and all of its children to gain
+
+# new privileges through execve().
+NoNewPrivileges=true
+
+# Use a new /dev namespace only populated with API pseudo devices
+
+# such as /dev/null, /dev/zero and /dev/random.
+PrivateDevices=true
+
+# Deny the creation of writable and executable memory mappings.
+MemoryDenyWriteExecute=true
+
+# Restrict ABIs to help ensure MemoryDenyWriteExecute is enforced
+SystemCallArchitectures=native
+
+[Install]
+WantedBy=multi-user.target
+```
+{% endstep %}
+
+{% step %}
+### Enable and start the Bitcoin service
+
+```shell
+$ sudo systemctl daemon-reload
+$ sudo systemctl enable bitcoin.service
+$ sudo systemctl start bitcoin.service
+```
+{% endstep %}
+
+{% step %}
+### Track sync progress
+
+{% hint style="info" %}
+Once started, you may track the sync progress:
+
+```
+$ sudo tail -f /bitcoin/mainnet/debug.log
+2024-12-05T19:35:31Z UpdateTip: new best=00000000000000000058990a84cc8f8eab25dbbd572f123f9190cea7256d7349 height=509258 version=0x20000000 log2_work=88.128280 tx=299522737 date='2018-02-15T03:42:14Z' progress=0.295203 cache=43.5MiB(172740txo)
+...
+$ bitcoin-cli \
+ -rpcconnect=127.0.0.1 \
+ -rpcport=8332 \
+ -rpcuser=btcuser \
+ -rpcpassword=btcpass \
+ getblockcount
+509016
+```
+{% endhint %}
+{% endstep %}
+{% endstepper %}
diff --git a/docs/operate/run-a-sbtc-signer/README.md b/docs/operate/run-a-sbtc-signer/README.md
new file mode 100644
index 0000000000..baea1839c8
--- /dev/null
+++ b/docs/operate/run-a-sbtc-signer/README.md
@@ -0,0 +1,193 @@
+# How to Run sBTC Signer
+
+{% hint style="info" %}
+This documentation provides guidelines, best-practices and recommendations for running an sBTC Signer. Review it and adapt it to your infrastructure policy before deploying it.
+{% endhint %}
+
+{% hint style="warning" %}
+Each sBTC signer will control a set of signing shares used to sign transactions on both Bitcoin and Stacks.
+
+Such shares will be encrypted by using the `private_key` specified in the Signer's config and stored in the PostgreSQL database attached to each signer.
+
+It is of the utmost importance to follow the recommendations below.
+{% endhint %}
+
+{% stepper %}
+{% step %}
+### Prevent unauthorized access to signer infrastructure
+
+Prevent unauthorized access to the sBTC Signer infrastructure (the signer itself, its private key, and the associated PostgreSQL database).
+{% endstep %}
+
+{% step %}
+### Keep an offline, secure backup of the Signer private key
+
+Keep an offline, secure backup of the sBTC Signer private key.
+{% endstep %}
+
+{% step %}
+### Regularly backup PostgreSQL database
+
+Regularly backup the PostgreSQL database and store it in a secure location.
+{% endstep %}
+{% endstepper %}
+
+See [here](best-practices-for-running-an-sbtc-signer.md) for additional best practices to run an sBTC signer.
+
+## Minimum System Requirements
+
+Below are the **minimum required specs** to be able to run a sBTC signer.
+
+* 2 CPU
+* 4GB memory
+* 50GB storage
+
+Note that these are in _addition_ to the hardware requirements for running a Stacks node and Bitcoin node outlined in the [How to Run a Signer doc](https://app.gitbook.com/s/4cpTb2lbw0LAOuMHrvhA/run-a-signer).
+
+## Connection diagram
+
+
+
+## Configure your Bitcoin node
+
+### Minimum version
+
+You will need `bitcoind` version 25 or higher.
+
+### Settings
+
+Your Bitcoin node must include these settings for sBTC signer operation:
+
+* `txindex=1`: Transaction indexing must be enabled
+* `server=1`: RPC server must be enabled
+
+### RPC-Based Block Detection
+
+Starting with sBTC v1.1.0, the signer uses RPC polling instead of ZeroMQ for block detection.
+
+The signer connects to Bitcoin Core via RPC and polls for new bitcoin blocks. This process works as follows:
+
+{% stepper %}
+{% step %}
+### Bitcoin Core validates a new block
+
+Bitcoin Core validates a new block.
+{% endstep %}
+
+{% step %}
+### Signer detects the block via RPC polling
+
+Signer detects the block via RPC polling.
+{% endstep %}
+
+{% step %}
+### Signer processes relevant sBTC transactions
+
+Signer processes relevant sBTC transactions.
+{% endstep %}
+{% endstepper %}
+
+### Example
+
+```bash
+bitcoind \
+ -server \
+ -datadir=${BITCOIN_DATA} \
+ -rpcbind=0.0.0.0 \
+ -rpcuser=${BITCOIN_RPC_USERNAME} \
+ -rpcpassword=${BITCOIN_RPC_PASSWORD} \
+ -rpcport=${BITCOIN_RPC_PORT} \
+ -rpcallowip=0.0.0.0/0 \
+ -rpcallowip=::/0 \
+ -txindex
+```
+
+## Configure your Stacks node
+
+### Minimum version
+
+Please ensure your Stacks version is up-to-date (using the latest release).
+
+### Event observer
+
+You will need to add a _new_ event observer that relays information from the sBTC smart contracts to the sBTC signer:
+
+```toml
+[[events_observer]]
+endpoint = "sbtc-signer:8801"
+events_keys = [
+ "SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-registry::print",
+]
+```
+
+### Reference configuration
+
+See [here](https://github.com/stacks-network/sbtc/blob/main/docker/mainnet/nodes/stacks/Config.toml.in).
+
+## Configure your sBTC Signer
+
+The signer configuration file (`signer-config.toml`) defines the signer's operation parameters. The configuration sections include:
+
+### Blocklist Client Settings
+
+```toml
+[blocklist_client]
+endpoint = "http://blocklist-client:3032"
+```
+
+### Bitcoin Connection Settings
+
+Defines how the signer connects to Bitcoin Core:
+
+```toml
+[bitcoin]
+rpc_endpoints = ["http://user:pass@your-bitcoin-node:8332"]
+
+# Note: block_hash_stream_endpoints are no longer used as of v1.1.0
+
+# The signer now uses RPC polling for block detection
+```
+
+### Core Signer Parameters
+
+Defines the signer's identity and network participation:
+
+```toml
+[signer]
+private_key = "your-private-key" # 32 or 33-byte hex format
+network = "mainnet"
+deployer = "SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4"
+```
+
+### P2P Network Configuration
+
+Controls how the signer communicates with other network participants:
+
+```toml
+[signer.p2p]
+listen_on = ["tcp://0.0.0.0:4122"]
+```
+
+The signer operates on port 4122 by default and supports both TCP and QUIC protocols for peer communication. The signer will attempt QUIC connections first for improved performance, automatically falling back to TCP if QUIC is unavailable or blocked on the network.
+
+### Reference configuration
+
+See [here](https://github.com/stacks-network/sbtc/blob/main/docker/mainnet/sbtc-signer/signer-config.toml.in).
+
+## Set up your containers
+
+See [here](https://github.com/stacks-network/sbtc/blob/main/docker/mainnet/docker-compose.yml) for a Docker Compose including all the required components.
+
+{% hint style="warning" %}
+When deploying with Docker, always use [immutable image tags](https://docs.docker.com/reference/cli/docker/image/pull/#pull-an-image-by-digest-immutable-identifier) - the image digests are provided below. Verify the attestation of these images using this [guide](https://docs.github.com/en/actions/security-for-github-actions/using-artifact-attestations/using-artifact-attestations-to-establish-provenance-for-builds#verifying-artifact-attestations-with-the-github-cli).
+
+We publish our images on [GitHub Container Registry](https://github.com/stacks-sbtc/sbtc/pkgs/container/sbtc).
+{% endhint %}
+
+## Monitoring
+
+Monitoring Details TBD
+
+## Troubleshooting
+
+Troubleshooting Guide TBD
diff --git a/docs/operate/run-a-sbtc-signer/best-practices-for-running-an-sbtc-signer.md b/docs/operate/run-a-sbtc-signer/best-practices-for-running-an-sbtc-signer.md
new file mode 100644
index 0000000000..d614a3b677
--- /dev/null
+++ b/docs/operate/run-a-sbtc-signer/best-practices-for-running-an-sbtc-signer.md
@@ -0,0 +1,121 @@
+# Best Practices for running an sBTC Signer
+
+The following best practices suggest how to create a resilient setup for running your sBTC Signer.
+
+## Protect your private key and have a cold-storage backup
+
+* Prevent unauthorised access to the sBTC Signer private key.
+* Keep an offline, secure backup of your sBTC Signer private key (e.g., hardware security modules or encrypted storage devices).
+
+## Backup your sBTC Signer PostgreSQL DB
+
+* Perform daily backups of the sBTC Signer PostgreSQL DB.
+* Periodically verify the integrity of backups (see steps below).
+
+### Verifying integrity of PostgreSQL DB backups
+
+{% stepper %}
+{% step %}
+### Import the backup
+
+Import the backup into a fresh PostgreSQL instance. The database alone is sufficient — you do not need to spin up a Stacks or Bitcoin node or the sBTC signer.
+{% endstep %}
+
+{% step %}
+### Run the verification query
+
+Execute the following query:
+
+{% code title="PostgreSQL" %}
+```
+```
+{% endcode %}
+
+```sql
+SELECT aggregate_key FROM sbtc_signer.dkg_shares
+WHERE dkg_shares_status = 'verified'
+ORDER BY created_at DESC;
+```
+
+This returns rows like:
+
+```sql
+ aggregate_key
+----------------------------------------------------------------------
+ \x03d8c4344861fc7590fd812c24884a3bfd9374d8ba865a787ff53c9060020aa967
+ \x03f898f8a6ddb86dd4608dd168355ec6135fe2839222240c01942e8e7e50dd4c89
+(2 rows)
+```
+
+The most recent `aggregate_key` is the first row.
+{% endstep %}
+
+{% step %}
+### Compare with the on-chain aggregate key
+
+Fetch the current aggregate pubkey from the sbtc-registry contract and compare it to the most recent `aggregate_key` from the DB query:
+
+```bash
+curl -s 'https://api.hiro.so/v2/contracts/call-read/SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4/sbtc-registry/get-current-aggregate-pubkey' \
+ -H 'content-type: application/json' --data-raw '{"sender":"SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4","arguments":[]}' | jq .result
+```
+
+Example output:
+
+```
+"0x020000002103d8c4344861fc7590fd812c24884a3bfd9374d8ba865a787ff53c9060020aa967"
+```
+
+Discard the prefix `0x02000000210` (Clarity encoding). The remaining hex `3d8c4344861fc7590fd812c24884a3bfd9374d8ba865a787ff53c9060020aa967` should match the first row of the PostgreSQL query (excluding `\x0` which indicates hex encoding).
+{% endstep %}
+{% endstepper %}
+
+## Setup proper access control
+
+* Require hardware 2FA keys for access control (e.g., YubiKey) to connect through SSH, to authenticate to AWS, and for every other relevant action.
+* Follow the principle of least privilege: if you don’t need access, you don’t get access; if you get access, it expires after the action is taken.
+
+{% hint style="info" %}
+Optional, but strongly recommended: Implement a "4-eyes" process (require that any activity by an individual must be reviewed or approved by a second individual) to access critical resources (e.g., deploying a new version of the sBTC signer).
+{% endhint %}
+
+## Maintain a strict firewall configuration
+
+* Allow connections to your sBTC signer `listen_on` address (used for P2P communication).
+* Do not expose any non-essential service to the internet: use a DEFAULT DENY policy with explicit ALLOWs for necessary network traffic (such as sBTC signer P2P and SSH).
+
+## Maintain a robust secrets management program
+
+* Ensure all relevant secrets are safely managed and rotated (where possible), e.g., if someone leaves the team.
+
+## Monitor and observe your sBTC Signer
+
+* Retain at least 90 days of logs for the sBTC Signer, the Stacks node, and the Bitcoin node.
+* The sBTC signer can optionally expose Prometheus metrics (see `prometheus_exporter_endpoint` configuration option).
+
+{% hint style="info" %}
+You can use Prometheus metrics to monitor signer health. For example, see how Alloy can be configured to collect metrics on Grafana Cloud: ../running-a-signer/how-to-monitor-signer.md
+{% endhint %}
+
+## Provision dedicated downstream components
+
+* Run a dedicated Bitcoin node and Stacks node for your sBTC Signer.
+ * Ensure the nodes are provisioned with the minimum hardware requirements described here: https://docs.stacks.co/guides-and-tutorials/running-a-signer#minimum-system-requirements
+ * Nodes should be exclusively dedicated to serve the sBTC Signer. Avoid re-using them to serve other clients as that may negatively affect performance (no mock-signing, no Stacks API nodes).
+
+## Monitor new software releases
+
+* Stay up-to-date with new releases, patches, and security advisories for all used operating systems, software and packages.
+ * https://www.cve.org/ is a useful resource for popular software packages.
+ * Subscribe to security notifications from your vendors.
+ * Join relevant messaging channels as applicable (Discord, Slack, etc.).
+* Exercise vulnerability management for all packages.
+* Apply updates promptly, especially those addressing security vulnerabilities.
+* Use inventory and patch management software, if available.
+
+## Ensure redundancy in operations
+
+* Ensure that multiple, trusted system administrators can manage and maintain your sBTC Signer instance.
+* Where feasible, system administrators should span different time zones.
+* Document your operations procedures and ensure that relevant personnel have access to them.
+
diff --git a/docs/operate/run-a-signer/README.md b/docs/operate/run-a-signer/README.md
new file mode 100644
index 0000000000..ed8aad2fd6
--- /dev/null
+++ b/docs/operate/run-a-signer/README.md
@@ -0,0 +1,361 @@
+# Run a Signer
+
+### How to Use This Guide
+
+If you are not familiar with the concept of signing and stacking, and how they work together, be sure to check out the [Stackers and Signing concept guide](https://app.gitbook.com/s/H74xqoobupBWwBsVMJhK/block-production/signing).
+
+This guide is a step-by-step walkthrough for setting up and running a signer. If you need to troubleshoot your signer setup, see the Signer Troubleshooting section. If you need to Stack your STX, or have questions about how that process works, check out the Stack STX guide.
+
+### Background and High-Level Process
+
+To run a signer you'll run a signer and a Stacks node side-by-side. Specifically, run a follower node. The signer monitors events from the Stacks node and uses the generated account (see Preflight Setup) to sign incoming Stacks blocks sent from the Stacks node.
+
+This doc provides instructions to set up both using either Docker or the release binaries available in the [stacks core releases](https://github.com/stacks-network/stacks-core/releases) repository, and how to configure them so the signer and Stacks node communicate correctly.
+
+### Knowledge Prerequisites
+
+* Docker and basic knowledge of pulling and running images
+* Basic knowledge of [Stacks accounts](https://app.gitbook.com/s/H74xqoobupBWwBsVMJhK/network-fundamentals/accounts)
+* Basic knowledge of [stacking](https://app.gitbook.com/s/H74xqoobupBWwBsVMJhK/block-production/stacking) and the stacking flow
+
+{% stepper %}
+{% step %}
+### Signer Checklist — Pre-Launch Setup
+
+Quick reference of major setup steps prior to launching a signer.
+
+* Ensure your system meets the [minimum system requirements](./#minimum-system-requirements).
+* Acquire Docker and basic knowledge of Stacks accounts, stacking, and the Nakamoto stacking flow (links above).
+{% endstep %}
+
+{% step %}
+### Signer Checklist — Preflight Setup
+
+* Generate a new private key using stacks-cli (see Preflight Setup).
+* Save the generated account information securely.
+{% endstep %}
+
+{% step %}
+### Signer Checklist — Configuration Setup
+
+* Create a `signer-config.toml` file with necessary configurations:
+ * node\_host
+ * endpoint
+ * network
+ * db\_path
+ * auth\_password
+ * stacks\_private\_key
+* Store `signer-config.toml` securely and note down the values used.
+{% endstep %}
+
+{% step %}
+### Signer Checklist — Running the Signer
+
+* Decide whether to run the signer using Docker (recommended) or as a binary.
+* If using Docker:
+ * Set up the necessary ports and volumes.
+ * Run the Docker container with the appropriate settings.
+* If running as a binary:
+ * Build `stacks-core` from source or download the pre-built binary.
+ * Run the signer using: `stacks-signer run --config `.
+{% endstep %}
+
+{% step %}
+### Signer Checklist — Verify Signer Operation
+
+* Check that the signer is listening on its configured endpoint.
+* Confirm that there are no errors and that the system is ready for connections.
+{% endstep %}
+
+{% step %}
+### Signer Checklist — Setting Up the Stacks Node
+
+* Create a `node-config.toml`, include:
+ * connection\_options.sauth\_token
+ * events\_observer.endpoint (matching signer config)
+* Decide whether to run the Stacks node using Docker or as a binary and follow the respective run steps.
+{% endstep %}
+
+{% step %}
+### Signer Checklist — Verify Stacks Node Operation
+
+* Check Stacks node logs for successful connection to the signer.
+* Confirm the node is syncing Bitcoin headers properly.
+{% endstep %}
+
+{% step %}
+### Signer Checklist — Setup Stacks Accounts
+
+* Set up a pool operator wallet in a Stacks wallet (e.g., Leather or Xverse).
+* Fund the pool operator wallet with sufficient STX for transaction fees.
+* Share the pool operator wallet’s STX address with delegating parties.
+* Fund your signer's STX wallet with enough STX to cover transaction fees (recommend at least 100–200 STX).
+{% endstep %}
+{% endstepper %}
+
+### Minimum System Requirements
+
+These are the minimum required specs to run a node and signer. More resources are recommended for optimal performance.
+
+#### Signer, Stacks node and Bitcoin node
+
+* 4 vCPU
+* 8 GB memory if running only a Stacks node and signer
+* 16 GB memory if running Stacks + Bitcoin node + signer
+* 1.5+ TB storage (1 TB for Bitcoin node, 500 GB for Stacks node, and 50 GB for signer)
+
+***
+
+## Preflight Setup
+
+Before you get your signer set up, you'll need to [generate a new private key](https://docs.stacks.co/stacks-101/accounts#creation). The `stacks-cli` provides a mechanism for quickly generating a new account keychain via a simple CLI interface. The linked guide shows how to create one of those accounts on testnet.
+
+Save the generated account information securely; you'll need it later.
+
+{% hint style="info" %}
+What should the networking setup look like?
+
+Signers are intended to work with a local node. The node<->signer connection is not run over SSL, which means you can be exposed to a man-in-the-middle attack if your signer and node are hosted on separate machines. Ensure your signer isn't allowing requests from the public internet. We recommend having the signer and node running locally on the same machine or using internal networking between them.
+{% endhint %}
+
+***
+
+## Create a Configuration File
+
+Create a file named `signer-config.toml`. Populate it with the example signer config file contents from the [Sample Configuration Files](https://app.gitbook.com/s/GVj1Z9vMuEOMe7oH7Wnq/signer-configuration) page. Each field is described on that page.
+
+***
+
+## Running the Signer
+
+Two options: Docker (recommended) or binary. Binaries are available on the [Stacks Core releases page](https://github.com/stacks-network/stacks-core/releases).
+
+### Running the Signer with Docker
+
+You can run the signer as a Docker container using the `blockstack/stacks-signer:3.1.0.0.5.0` image.
+
+Requirements when running the container:
+
+* The port configured as the `endpoint` (example: 30000) must be exposed to your Stacks node (endpoint should not be public).
+* A volume with at least a few GB available that contains the folder specified by your `db_path` (example: `/var`).
+* Mount your `signer-config.toml` file as a volume.
+
+Example docker run command:
+
+```bash
+IMG="blockstack/stacks-signer"
+VER="3.1.0.0.5.0"
+STX_SIGNER_PATH="./"
+STX_SIGNER_DATA="$STX_SIGNER_PATH/data"
+STX_SIGNER_CONFIG="$STX_SIGNER_PATH/signer-config.toml"
+
+docker run -d \
+ -v $STX_SIGNER_CONFIG:/config.toml \
+ -v $STX_SIGNER_DATA:/var/stacks \
+ -p 30000:30000 \
+ -e RUST_BACKTRACE=full \
+ -e BLOCKSTACK_DEBUG=0 \
+ --name stacks-signer \
+ $IMG:$VER \
+ stacks-signer run \
+ --config /config.toml
+```
+
+Hint about platform mismatch:
+
+{% hint style="info" %}
+If you get an error about the manifest not found or the image platform not matching the host platform, you probably are running on an architecture other than x64. Add `--platform=linux/amd64` to the command (for example, on M1 Mac).
+{% endhint %}
+
+Or, using a custom Dockerfile:
+
+```docker
+FROM blockstack/stacks-signer:3.1.0.0.5.0
+COPY signer-config.toml /config.toml
+EXPOSE 30000
+CMD ["stacks-signer", "run", "--config", "/config.toml"]
+```
+
+### Running the Signer as a Binary
+
+Download the pre-built binaries from the [Stacks Core releases page on Github](https://github.com/stacks-network/stacks-core/releases), unzip the archive for your architecture — inside is a `stacks-signer` binary.
+
+Run the signer:
+
+```bash
+stacks-signer run --config ../signer-config.toml
+```
+
+(Replace `../signer-config.toml` with the actual path to your config.)
+
+***
+
+## Verify the Signer is Running
+
+List running containers:
+
+```bash
+docker ps
+```
+
+Check the container logs:
+
+```bash
+docker logs
+```
+
+You should see:
+
+Signer spawned successfully. Waiting for messages to process...
+
+You may also see a warning like:
+
+```
+WARN [1712003997.160121] [stacks-signer/src/runloop.rs:247] [signer_runloop] Signer is not registered for reward cycle 556. Waiting for confirmed registration...
+```
+
+This means your signer is running and awaiting registration; proceed to set up the Stacks node and begin stacking.
+
+{% hint style="warning" %}
+Even after you Stack, you may still see messages saying the signer is not registered for the current or next reward cycle. This is normal until the prepare phase for your chosen reward cycle; assuming you meet the stacking minimum, the signer will be registered during that phase.
+{% endhint %}
+
+***
+
+## Set Up Your Bitcoin Node
+
+Optional but recommended to improve signer health and performance.
+
+Guides:
+
+* Run a full Bitcoin node: https://docs.stacks.co/guides-and-tutorials/nodes-and-miners/run-a-bitcoin-node
+* Run a pruned Bitcoin node: https://docs.stacks.co/guides-and-tutorials/nodes-and-miners/run-a-pruned-bitcoin-node
+
+***
+
+## Set Up Your Stacks Node
+
+Start the Stacks node after the signer is running — the node will not run unless it can send events to the signer.
+
+### Stacks Node Configuration
+
+Create `node-config.toml`. See the [Sample Configuration Files](https://app.gitbook.com/s/GVj1Z9vMuEOMe7oH7Wnq/signer-configuration) page for the full contents.
+
+Important fields to change:
+
+* `working_dir`: directory where the node persists data
+* `auth_token`: authentication token used by signer (must match signer `auth_password`)
+* `events_observer.endpoint`: host and port where your signer listens (example: `127.0.0.1:30000` or `stacks-signer.local:30000`)
+
+### Start with an archive
+
+Starting from an archive snapshot is much faster than syncing from genesis. Archives are at https://archive.hiro.so.
+
+Example to download and extract the latest mainnet snapshot:
+
+```bash
+curl -# https://archive.hiro.so/mainnet/stacks-blockchain/mainnet-stacks-blockchain-latest.tar.gz -o stacks-snapshot.tar.gz
+tar -zxvf stacks-snapshot.tar.gz
+```
+
+This creates a `mainnet` folder where downloaded. Set `working_dir` to the parent directory containing `mainnet`.
+
+See best practices for snapshots: ../best-practices-to-snapshot-the-chainstate.md
+
+### Run a Stacks Node with Docker
+
+Use the `blockstack/stacks-core` image (example tag: `3.1.0.0.13`).
+
+When running the container:
+
+* Expose the port configured for `p2p_bind` to the internet.
+* Make the port configured for `rpc_bind` accessible by your signer.
+* `working_dir` needs 500 GB–1 TB storage.
+* Include your `node-config.toml`.
+
+Example docker run:
+
+```bash
+IMG="blockstack/stacks-core"
+VER="3.1.0.0.13"
+STX_NODE_CONFIG="./node-config.toml"
+
+docker run -d \
+ -v $STX_NODE_CONFIG:/config.toml \
+ -v /var/stacks \
+ -p 20443:20443 \
+ -p 20444:20444 \
+ -e RUST_BACKTRACE=full \
+ --name stacks-node \
+ $IMG:$VER \
+ stacks-node start \
+ --config /config.toml
+```
+
+Or with a custom Dockerfile:
+
+```docker
+FROM blockstack/stacks-core:3.1.0.0.13
+COPY node-config.toml /config.toml
+EXPOSE 20444
+EXPOSE 20443
+CMD ["stacks-node", "start", "--config", "/config.toml"]
+```
+
+If you get connection refused errors, you may need to point `events_observer.endpoint` to the Docker signer container. If using default Docker bridge mode, `localhost` inside the container is not the host — point the endpoint to the Docker host or the signer container hostname accordingly.
+
+### Run a Stacks Node with a Binary
+
+Download the pre-built `stacks-node` binary from the [Stacks Core releases](https://github.com/stacks-network/stacks-core/releases).
+
+Start the node:
+
+```bash
+./stacks-node start --config node-config.toml
+```
+
+### Verify Stacks Node is Running
+
+Typical startup logs:
+
+```bash
+Mar 6 19:35:08.212848 INFO stacks-node 0.1.0
+Mar 6 19:35:08.213084 INFO Loading config at path ./Stacks-config.toml
+Mar 6 19:35:08.216674 INFO Registering event observer at: localhost:30000
+Mar 6 19:35:08.221603 INFO Migrating sortition DB to the latest schema version
+Mar 6 19:35:08.224082 INFO Migrating chainstate DB to the latest schema version
+Mar 6 19:35:08.227404 INFO Start syncing Bitcoin headers, feel free to grab a cup of coffee, this can take a while
+```
+
+Ensure you see the `Registering event observer at XXX` log with your signer endpoint. Once Bitcoin headers are synced, you can GET `/v2/info` on the node RPC endpoint (default port 20443).
+
+You may see many logs while syncing; refer to How to Read the Signer Logs if concerned.
+
+***
+
+## Setup Your Stacks Accounts
+
+{% hint style="info" %}
+For more on stacking and signing relationship, see the [Stack STX](broken-reference) guide.
+{% endhint %}
+
+As a signer you’ll manage two Stacks accounts:
+
+1. A “pool operator” wallet, which commits delegated STX to your signer
+2. Your signer’s wallet
+
+{% hint style="warning" %}
+For testing, make sure you are using testnet (not mainnet). Testnet STX can be [requested from a faucet](https://explorer.hiro.so/sandbox/faucet?chain=testnet).
+{% endhint %}
+
+### Setup Your Pool Operator Wallet
+
+Set up a pool operator wallet using any Stacks wallet, such as [Leather](https://leather.io/) or [Xverse](https://www.xverse.app/). You may generate a new account or use an existing one. Leather supports Ledger hardware wallets if you prefer.
+
+Fund the wallet with enough STX to cover transaction fees (testnet: faucet at https://explorer.hiro.so/sandbox/faucet?chain=testnet).
+
+Share this wallet’s STX address with parties that will delegate STX to you. For improved UX, you might use the helper contract allowing a BTC address for stackers ([pox4-pools](https://explorer.hiro.so/txid/SP001SFSMC2ZY76PD4M68P3WGX154XCH7NE3TYMX.pox4-pools?chain=mainnet)) and add your pool to [earn.leather.io](https://earn.leather.io/).
+
+***
+
+If you need more detailed troubleshooting or further setup examples (config snippets, sample signer-config.toml or node-config.toml), let me know which files or examples you'd like converted or added.
diff --git a/docs/operate/run-a-signer/best-practices-to-run-a-signer.md b/docs/operate/run-a-signer/best-practices-to-run-a-signer.md
new file mode 100644
index 0000000000..96b30092c8
--- /dev/null
+++ b/docs/operate/run-a-signer/best-practices-to-run-a-signer.md
@@ -0,0 +1,101 @@
+# Best Practices to Run a Signer
+
+{% hint style="info" %}
+**Intended audience**: solo Stackers or Stacking pool operators.
+{% endhint %}
+
+The following best practices suggest how to create a resilient setup for running your Signer.
+
+{% hint style="info" %}
+tl;dr: avoid single point of failures, introduce redundancy, monitor things.
+{% endhint %}
+
+### Monitor your Signer and collect logs
+
+* See [here](how-to-monitor-signer.md) on how to set up monitoring.
+* Retain at least 1 week of logs for both the Signer and the Stacks node.
+
+### Downstream components
+
+* Run a dedicated Bitcoin node and Stacks node per Signer.
+ * Ensure the nodes are provisioned with the minimum hardware requirements described [here](https://docs.stacks.co/guides-and-tutorials/running-a-signer#minimum-system-requirements).
+ * Nodes should be exclusively dedicated to serve the Signer. Avoid re-using them to serve other clients as that may negatively affect performance (no mock-signing, no Stacks API nodes).
+* If running dedicated nodes is not possible, then ensure that the Bitcoin / Stacks nodes do not become single points of failure for multiple signers depending on them.
+ * Introduce redundancy, load balancing, rely on a robust Bitcoin RPC provider, etc.
+
+### Split voting power across multiple Signers
+
+* Distribute your voting power across multiple, distinct Signer public keys to mitigate the risk of loss or downtime from a single compromised key.
+* Each Signer should also limit voting power to a maximum amount and invite Stackers to use a different Signer when the limit is reached.
+
+### Monitor new software releases
+
+* Stay up-to-date with new releases, patches, and security advisories (e.g., GitHub, mailing lists, Discord).
+* Apply updates as quickly as possible, especially those addressing a security vulnerability.
+
+### Upgrade procedures
+
+{% stepper %}
+{% step %}
+### Test one instance first
+
+Upgrade one Signer instance at a time. Test the update on a single instance and verify functionality before proceeding to others.
+{% endstep %}
+
+{% step %}
+### Roll out gradually
+
+If the test is successful, proceed to upgrade the remaining instances one-by-one.
+{% endstep %}
+
+{% step %}
+### Minimize downtime
+
+While a Signer is offline for upgrades, it won't sign any blocks. Ensure that the downtime is as short as possible.
+{% endstep %}
+{% endstepper %}
+
+### Diversified hosting
+
+* Use different provider / configuration where feasible (e.g., a self-hosted instance and one in the cloud, or in two different data center regions, etc.).
+* Ensure each host has redundant power supply and network connectivity.
+
+### Fall-back deployments
+
+* Deploy additional Stacks nodes and Bitcoin nodes to be used as fall-back.
+ * Use the same configuration as your active instances.
+ * For the Stacks node, comment out the `event_observer` section.
+* Prepare a backup Signer (same configuration) to be quickly activated, but do not run it.
+ * At all times, there should be exactly one Signer instance running for each Signer private key.
+* These fall-back instances should be hosted on separate physical hosts (see diversified hosting) from the instances usually active in operations (serving each Signer).
+
+To switch to the fall-back configuration quickly if an active instance fails, follow these steps:
+
+{% stepper %}
+{% step %}
+### Run the backup Signer
+
+Start the prepared backup Signer instance.
+{% endstep %}
+
+{% step %}
+### Enable event observer
+
+Enable the `event_observer` section of the Stacks node configuration.
+{% endstep %}
+
+{% step %}
+### Restart the node
+
+Restart the Stacks node so it runs with the enabled `event_observer`.
+{% endstep %}
+{% endstepper %}
+
+### Redundancy in operations
+
+* Ensure that multiple, trusted users can manage and maintain signer instances.
+* Where feasible, users should span different timezones.
+
+### Backup signer keys in cold-storage
+
+* Keep an offline, secure backup of all Signer private keys (e.g., hardware security modules or encrypted storage devices).
diff --git a/docs/operate/run-a-signer/how-to-monitor-signer.md b/docs/operate/run-a-signer/how-to-monitor-signer.md
new file mode 100644
index 0000000000..baad96143a
--- /dev/null
+++ b/docs/operate/run-a-signer/how-to-monitor-signer.md
@@ -0,0 +1,229 @@
+# How to Monitor Signer
+
+We will use [Grafana Cloud](https://grafana.com/) to observe and monitor both the Signer and its corresponding Stacks node.
+
+## Requirements
+
+Grafana's application observability docs have a [great quick-start](https://grafana.com/docs/grafana-cloud/monitor-applications/application-observability/). We will use:
+
+* Grafana Cloud to collect metrics and visualize them.
+* Grafana Alloy, on the Signer host, to push the metrics.
+
+### Creating a Grafana Cloud account
+
+Before we begin, create a [Grafana Cloud](https://grafana.com/docs/grafana-cloud/monitor-applications/application-observability/grafana-cloud/) account (they offer a free tier that you can use).
+
+Once done, access your dashboard and follow these steps:
+
+{% stepper %}
+{% step %}
+### Add a new connection
+
+Click on "Connections", then "Add new connection".
+{% endstep %}
+
+{% step %}
+### Select Hosted Prometheus metrics
+
+Select "Hosted Prometheus metrics".
+{% endstep %}
+
+{% step %}
+### Choose via Grafana Alloy
+
+Select "Via Grafana Alloy", then on step 2 choose "Run Grafana Alloy" to generate an API token.
+{% endstep %}
+{% endstepper %}
+
+Note the token `GCLOUD_RW_API_KEY` and the parameters `GCLOUD_HOSTED_METRICS_URL` and `GCLOUD_HOSTED_METRICS_ID`; we will use them later.
+
+### Configuring the Signer and the Stacks node
+
+Ensure both your Signer configuration and your node configuration include the following lines:
+
+```toml
+# signer-config.toml
+
+# ...
+
+# Adjust to 0.0.0.0:30001 if running in Docker.
+metrics_endpoint = "127.0.0.1:30001"
+```
+
+```toml
+# node-config.toml
+[node]
+
+# ...
+
+# Adjust to 0.0.0.0:9153 if running in Docker.
+prometheus_bind = "127.0.0.1:9153"
+```
+
+The pre-compiled binaries already include the monitoring feature. However, if you are compiling the application binaries yourself, remember to enable the Cargo feature `monitoring_prom` while building them, for example:
+
+```bash
+cargo build --features monitoring_prom,slog_json --release
+```
+
+Once both binaries are running with the updated configuration, you can peek at the metrics being exposed:
+
+```bash
+curl 127.0.0.1:30001/metrics
+
+# HELP stacks_signer_current_reward_cycle The current reward cycle
+
+# TYPE stacks_signer_current_reward_cycle gauge
+stacks_signer_current_reward_cycle 95
+
+# HELP stacks_signer_node_rpc_call_latencies_histogram Time (seconds) measuring round-trip RPC call latency to the Stacks node
+
+# TYPE stacks_signer_node_rpc_call_latencies_histogram histogram
+...
+stacks_signer_node_rpc_call_latencies_histogram_bucket{path="/v2/info",le="0.005"} 0
+stacks_signer_node_rpc_call_latencies_histogram_bucket{path="/v2/info",le="0.01"} 0
+stacks_signer_node_rpc_call_latencies_histogram_bucket{path="/v2/info",le="0.025"} 0
+stacks_signer_node_rpc_call_latencies_histogram_bucket{path="/v2/info",le="0.05"} 985
+stacks_signer_node_rpc_call_latencies_histogram_bucket{path="/v2/info",le="0.1"} 1194
+...
+```
+
+Also, you'll have a `/info` endpoint on the same port:
+
+```bash
+curl 127.0.0.1:30001/info
+```
+
+### Install Alloy
+
+Follow these instructions to install [Grafana Alloy](https://grafana.com/docs/alloy/latest/set-up/install/linux/).
+
+On Debian-based distributions:
+
+```bash
+sudo apt install gpg
+sudo mkdir -p /etc/apt/keyrings/
+wget -q -O - https://apt.grafana.com/gpg.key | gpg --dearmor | sudo tee /etc/apt/keyrings/grafana.gpg > /dev/null
+echo "deb [signed-by=/etc/apt/keyrings/grafana.gpg] https://apt.grafana.com stable main" | sudo tee /etc/apt/sources.list.d/grafana.list
+sudo apt-get update
+sudo apt-get install alloy
+```
+
+### Configure Alloy
+
+Edit the file `/etc/alloy/config.alloy` as follows, replacing the placeholders related to the `prometheus` endpoint with the parameters obtained when creating a Grafana Cloud account:
+
+* `GCLOUD_HOSTED_METRICS_URL`
+* `GCLOUD_HOSTED_METRICS_ID`
+* `GCLOUD_RW_API_KEY`
+
+```conf
+// For a full configuration reference, see https://grafana.com/docs/alloy
+// For a default configuration, integrating all environmental variables from Grafana Cloud
+// see https://storage.googleapis.com/cloud-onboarding/alloy/config/config.alloy
+
+logging {
+ level = "warn"
+}
+
+prometheus.exporter.unix "default" {
+ include_exporter_metrics = true
+ disable_collectors = ["mdadm"]
+}
+
+prometheus.scrape "default" {
+ targets = array.concat(
+ prometheus.exporter.unix.default.targets,
+ [
+ {
+ // Self-collect metrics
+ job = "alloy",
+ __address__ = "127.0.0.1:12345",
+ },
+ {
+ // stacks-signer
+ job = "stacks-signer",
+ __address__ = "127.0.0.1:30001",
+ },
+ {
+ // stacks-node
+ job = "stacks-node",
+ __address__ = "127.0.0.1:9153",
+ },
+ ],
+ )
+
+ forward_to = [prometheus.remote_write.metrics_service.receiver]
+}
+
+prometheus.remote_write "metrics_service" {
+ external_labels = {"instance" = constants.hostname}
+ endpoint {
+ # TODO: Edit the URL below with your Grafana production URL.
+ # should end with /api/prom/push
+ url = ""
+
+ # TODO: Edit with your Grafana Cloud ID and Token
+ basic_auth {
+ username = ""
+ password = ""
+ }
+ }
+}
+```
+
+Enable and start Alloy:
+
+```bash
+sudo systemctl daemon-reload
+sudo systemctl enable alloy.service
+sudo systemctl start alloy.service
+```
+
+Metrics from your Signer and node will now start being pushed to Grafana Cloud.
+
+## Visualizing the metrics
+
+You can now start building a dashboard to visualize the metrics.
+
+1. Log in to Grafana Cloud and create a new Dashboard.
+2. Pick the Prometheus instance you created before as the data source.
+3. Create a new panel and pick `stacks_signer_current_reward_cycle` from the metrics.
+
+You should now be able to see Stacks' current reward cycle, as measured by the Signer, in the dashboard.
+
+Grafana comes with powerful data visualization tools. You can read about how to query and transform data [here](https://grafana.com/docs/grafana-cloud/visualizations/panels-visualizations/query-transform-data/), and find examples on how to build [Prometheus queries](https://prometheus.io/docs/prometheus/latest/querying/basics/).
+
+[This template](https://grafana.com/grafana/dashboards/22137-stacks-signer-template/) will kick-start your dashboard.
+
+
+
+## Bonus: monitoring the host
+
+Since we are here, we can also monitor the host itself. Debian-based distributions make it very easy for us by using [`node_exporter`](https://github.com/prometheus/node_exporter/tree/master).
+
+```bash
+sudo apt install prometheus-node-exporter
+sudo systemctl enable prometheus-node-exporter
+sudo systemctl start prometheus-node-exporter
+```
+
+This will expose metrics on port `9100` of `localhost`.
+
+We can now configure `alloy` to push them to Grafana. Edit your `/etc/alloy/config.alloy` file and add the following scrape target to the `prometheus.scrape "default"` targets list:
+
+```conf
+{
+ job = "node_exporter",
+ __address__ = "127.0.0.1:9100",
+}
+```
+
+Now reload `alloy` and check its status:
+
+```bash
+sudo systemctl reload alloy
+sudo systemctl status alloy
+```
+
+`node_exporter` provides a lot of metrics. Explore them through the Grafana Explorer or use one of the many prepared dashboards (e.g., [this one](https://grafana.com/grafana/dashboards/1860-node-exporter-full/)) to see comprehensive information. Once you have a dashboard ready, you can also use it to configure alerts (e.g., on disk space, etc.).
diff --git a/docs/operate/run-a-signer/how-to-read-signer-logs.md b/docs/operate/run-a-signer/how-to-read-signer-logs.md
new file mode 100644
index 0000000000..2f74b2fd13
--- /dev/null
+++ b/docs/operate/run-a-signer/how-to-read-signer-logs.md
@@ -0,0 +1,63 @@
+# How to Read Signer Logs
+
+There are a lot of different messages you can get in the logs when running a signer. Getting a good grasp on what some of these logs mean can help you troubleshoot effectively and determine if your signer is running successfully or not.
+
+There are three types of log messages you should be aware of:
+
+* Successful
+* Informational
+* Errors
+
+Successful log messages indicate that you are on track and everything is working as expected. However, there are various success stages depending on several factors including your stacking status and the timing of the current reward cycle.
+
+There are also several informational/warning logs that you don't necessarily need to take action on, but they provide useful context about the network or the signer.
+
+Finally, error logs indicate something has gone wrong and you need to take action.
+
+Below are some common log messages you might see, what they mean, and what action (if any) you should take.
+
+{% hint style="info" %}
+Successful / informational / error categories — general guidance:
+
+* Successful: nothing to do unless the message indicates a different stage of operation that requires action (e.g., registration needed).
+* Informational: often safe to ignore, but useful for context.
+* Errors: require investigation and remediation.
+{% endhint %}
+
+## Successful
+
+### Signer uninitialized or not registered
+
+If you get a message saying your signer is uninitialized, it means your signer is not registered for the current or upcoming reward cycle (or the burnchain block height is not yet at the second block in the prepare phase) so the signer cannot determine registration status yet. This does not mean the signer process itself has failed — it is running successfully, but the signer cannot act until registration/delegation occurs.
+
+Example log:
+
+`Signer spawned successfully. Waiting for messages to process... INFO [1711088054.872542] [stacks-signer/src/runloop.rs:278] [signer_runloop] Running one pass for signer ID# 0. Current state: Uninitialized`
+
+You may also see a warning like:
+
+```
+WARN [1712003997.160121] [stacks-signer/src/runloop.rs:247] [signer_runloop] Signer is not registered for reward cycle 556. Waiting for confirmed registration...
+```
+
+Action:
+
+* If you want the signer to participate, either delegate to it or stack on your own for an upcoming reward cycle.
+* For more details on stacking and registration, see the How to Stack doc: ../stack-stx/stacking-flow.md
+
+## Informational
+
+### Peer not connecting
+
+If you see a message about a peer not connecting, for example:
+
+```
+INFO [1711988555.021567] [stackslib/src/net/neighbors/walk.rs:1015] [p2p-(0.0.0.0:20444,0.0.0.0:20443)] local.80000000://(bind=0.0.0.0:20444)(pub=Some(10.0.19.16:20444)): Failed to connect to facade0b+80000000://172.16.60.18:20444: PeerNotConnected
+```
+
+This means your node attempted to connect to another node on the network but was unable to. This can happen for many reasons (network connectivity, remote node offline, NAT/firewall, etc.).
+
+Action:
+
+* Usually not a cause for concern and does not impact whether your signer is running correctly.
+* If you see many such messages or persistent connectivity issues, investigate network connectivity, firewall/NAT rules, or peer configuration.
diff --git a/docs/operate/run-a-signer/opsec-best-practices.md b/docs/operate/run-a-signer/opsec-best-practices.md
new file mode 100644
index 0000000000..bd1b1361a2
--- /dev/null
+++ b/docs/operate/run-a-signer/opsec-best-practices.md
@@ -0,0 +1,113 @@
+# OpSec Best Practices
+
+#### Threat Modeling
+
+A threat actor that is able to compromise > 70% of Signers (by stake weight) would be able to successfully propose Stacks blocks that would otherwise be considered invalid.
+
+Some potential vectors for signer key compromise are as follows:
+
+* stacks-signer node is compromised and key is exfiltrated from the filesystem
+* Signer key is compromised during generation or deployment
+* Signer key is accidentally checked into SCM (eg Github or Gitlab)
+* Social engineering attack against Signer community: eg a malicious link is posted to social media that harvests key material
+* An undisclosed backdoor is discovered in the Signer binary.
+* Supply chain attack against stacks-signer source code: threat actor compromises upstream dependencies of stacks-signer
+
+#### Countermeasures
+
+What can Signers do to mitigate the threat vectors identified above? Let's identify countermeasures in response to each of the threats identified above, starting with the first vector: stacks-signer node compromise and key exfiltration.
+
+{% stepper %}
+{% step %}
+### Run the stacks-signer on a separate system from the stacks-node
+
+This reduces discoverability of the signer. Systems running the stacks-node participate in the peer-to-peer network and are more easily enumerated. If an attacker can't find your stacks-signer, they can't attack it directly.
+
+Best practice: ensure stacks-node and stacks-signer communicate only over trusted networks, ideally using localhost (127.0.0.1) or a secure private subnet.
+
+Note: Running the stacks-signer on a separate system is an option, but not strictly necessary. Running both on the same virtual machine within a private network, with traffic firewalled to allow only incoming P2P connections (port 20444), provides a secure and easier setup while minimizing exposure.
+{% endstep %}
+
+{% step %}
+### Run the stacks-signer as a separate user from the stacks-node
+
+When resource constraints prevent separate workloads, run the stacks-signer under a distinct unprivileged user account from the stacks-node. Ensure exclusive ownership and restrictive permissions for each user's configuration files.
+
+Example: the user running the signer binary (e.g., signer) should own the signer’s config file and set permissions to prevent other users from reading it. The same principle applies to the stacks-node user. This ensures only appropriate processes can access sensitive configuration details.
+{% endstep %}
+
+{% step %}
+### Harden the systemd configuration for the stacks-signer
+
+Hardening systemd can reduce blast radius if an attacker gains control of the stacks-signer process. An example stacks-signer.service systemd unit is shown below. This unit prevents certain filesystem writes and otherwise restricts the process.
+
+{% code title="stacks-signer.service" %}
+```ini
+[Unit]
+Description=Stacks Signer
+After=network.target
+StartLimitBurst=3
+StartLimitIntervalSec=300
+ConditionFileIsExecutable=/usr/local/bin/stacks-signer
+ConditionPathExists=/etc/stacks/signer
+ConditionFileNotEmpty=/etc/stacks/signer/signer-config.toml
+
+[Service]
+ExecStart=/usr/local/bin/stacks-signer run --config /home/etc/stacks/signer/signer-config.toml
+User={{ svc_user }}
+Group={{ svc_user }}
+Type=simple
+Restart=on-failure
+TimeoutStopSec=600
+KillSignal=SIGTERM
+#KillSignal=SIGINT
+
+# Provide a private /tmp and /var/tmp.
+PrivateTmp=true
+
+# Mount /usr, /boot/ and /etc read-only for the process.
+ProtectSystem=full
+
+# Deny access to /home, /root and /run/user
+ProtectHome=true
+
+# Disallow the process and all of its children to gain
+
+# new privileges through execve().
+NoNewPrivileges=true
+
+# Use a new /dev namespace only populated with API pseudo devices
+
+# such as /dev/null, /dev/zero and /dev/random.
+PrivateDevices=true
+
+[Install]
+WantedBy=multi-user.target
+```
+{% endcode %}
+
+Read more about systemd hardening: https://www.ctrl.blog/entry/systemd-service-hardening.html
+{% endstep %}
+
+{% step %}
+### Restrict access to unnecessary ports and protocols
+
+The stacks-signer requires outbound TCP access to the stacks-node, but typically no other inbound network exposure is needed (except for OS updates and administrative access). Restrict network access to the minimum required for operation.
+{% endstep %}
+
+{% step %}
+### Harden the operating system
+
+A few practical OS hardening measures:
+
+* Run stacks-signer as an unprivileged user (not root).
+* Set permissions on the stacks-signer key/config to be readable only by the user running the stacks-signer process, e.g.:
+ * sudo chmod 600 signer/signer-config.toml
+* Require public-key authentication for SSH and disable SSH root login.
+* Consider running sshd on a non-standard port to reduce noise from port scanners and credential-stuffing attacks.
+{% endstep %}
+{% endstepper %}
+
+This post outlines essential operational security best practices for Stacks Signers, key actors in the Nakamoto architecture.
+
+By implementing these strategies, signer operators can effectively mitigate risks and maintain the security and reliability of the Stacks network.
diff --git a/docs/operate/run-a-signer/signer-quickstart.md b/docs/operate/run-a-signer/signer-quickstart.md
new file mode 100644
index 0000000000..0617f3f84b
--- /dev/null
+++ b/docs/operate/run-a-signer/signer-quickstart.md
@@ -0,0 +1,461 @@
+# Signer Quickstart
+
+{% hint style="info" %}
+**Current Signer and Stacks Node Versions**
+
+**Stacks Signer - latest**
+
+* [Docker Image](https://hub.docker.com/layers/blockstack/stacks-signer/latest)
+* [GitHub Release](https://github.com/stacks-network/stacks-core/releases/latest)
+
+**Stacks Node - latest**
+
+* [Docker Image](https://hub.docker.com/layers/blockstack/stacks-core/latest)
+* [GitHub Release](https://github.com/stacks-network/stacks-core/releases/latest)
+{% endhint %}
+
+If you want to get up and running as an active signer as quickly as possible, here is a list of the commands you need to run and actions to take.
+
+If you are not familiar with how signing works yet, be sure to check out the [Signing concept guide](https://app.gitbook.com/s/H74xqoobupBWwBsVMJhK/block-production/signing).
+
+If you would like a more detailed walkthrough of all of these steps, take a look at the [Running a Signer](file:///) guide.
+
+{% hint style="danger" %}
+The CLI examples below may show outdated release versions. For the latest releases, always refer to the links above in the top info block.
+{% endhint %}
+
+{% stepper %}
+{% step %}
+### Prerequisites
+
+{% tabs %}
+{% tab title="Mainnet" %}
+```bash
+# Create the required directories
+mkdir -p ~/stacks-signer/data
+mkdir -p ~/stacks-node/data
+
+# Install needed packages
+sudo apt install -y npm wget unzip jq tar
+
+# Install Stacks CLI globally
+npm install --global @stacks/cli
+
+# Generate a new account and store details in a file
+stx make_keychain | jq > ~/stacks-signer/keychain.json
+```
+{% endtab %}
+
+{% tab title="Testnet" %}
+```bash
+# Create the required directories
+mkdir -p ~/stacks-signer/data
+mkdir -p ~/stacks-node/data
+
+# Install needed packages
+sudo apt install -y npm wget unzip jq tar
+
+# Install Stacks CLI globally
+npm install --global @stacks/cli
+
+# Generate a new account and store details in a file
+
+# '-t' option makes this a testnet account
+stx make_keychain -t | jq > ~/stacks-signer/keychain.json
+```
+{% endtab %}
+{% endtabs %}
+
+The account file previously created looks like this:
+
+```json
+{
+ "mnemonic": "aaa bbb ccc ddd ...",
+ "keyInfo": {
+ "privateKey": "65f3...",
+ "publicKey": "03a3...",
+ "address": "SP1G...",
+ "btcAddress": "19tg...",
+ "wif": "Kzdt...",
+ "index": 0
+ }
+}
+```
+
+From this file, you'll need the `privateKey` value.
+{% endstep %}
+
+{% step %}
+### Set Up Your Stacks Signer
+
+#### Download the stacks-signer binary
+
+Official binaries are available from the [Stacks Core releases page on Github](https://github.com/stacks-network/stacks-core/releases). Each release includes pre-built binaries. Download the [latest signer release ZIP file](https://github.com/stacks-network/stacks-core/releases/latest) for your server’s architecture and decompress it. Inside of that folder is a `stacks-signer` binary.
+
+Assuming a `Linux x64 glibc` machine, the commands to download and uncompress the signer binary look like this:
+
+```bash
+# The CLI examples below may show outdated release versions.
+# Enter the signer directory
+cd ~/stacks-signer
+
+# Download the signer binary zip
+wget https://github.com/stacks-network/stacks-core/releases/latest/download/linux-glibc-x64.zip
+
+# Unzip the signer binary archive
+unzip linux-glibc-x64.zip
+```
+
+#### Create the configuration file
+
+Create the configuration file required to start the signer (be sure to replace `` and `` with your auth token and private key values):
+
+{% tabs %}
+{% tab title="Mainnet" %}
+```bash
+# The CLI examples below may show outdated release versions.
+# Set environment variables
+AUTH_TOKEN= # Used for signer-node authentication
+PRIVATE_KEY= # privateKey from Step 1, this is the signer's private key
+
+# Create the signer's configuration file
+cat < ~/stacks-signer/signer-config.toml
+node_host = "127.0.0.1:20443"
+endpoint = "127.0.0.1:30000"
+network = "mainnet"
+db_path = "$HOME/stacks-signer/data/signer.sqlite"
+auth_password = "$AUTH_TOKEN"
+stacks_private_key = "$PRIVATE_KEY"
+metrics_endpoint = "127.0.0.1:9154"
+block_proposal_timeout_ms = 180000
+tenure_idle_timeout_secs = 120
+EOF
+```
+{% endtab %}
+
+{% tab title="Testnet" %}
+```bash
+# Set environment variables
+AUTH_TOKEN= # Used for signer-node authentication
+PRIVATE_KEY= # privateKey from Step 1, this is the signer's private key
+
+# Create the signer's configuration file
+cat < ~/stacks-signer/signer-config.toml
+node_host = "127.0.0.1:20443"
+endpoint = "127.0.0.1:30000"
+network = "testnet"
+db_path = "$HOME/stacks-signer/data/signer.sqlite"
+auth_password = "$AUTH_TOKEN"
+stacks_private_key = "$PRIVATE_KEY"
+metrics_endpoint = "127.0.0.1:9154"
+block_proposal_timeout_ms = 180000
+EOF
+```
+{% endtab %}
+{% endtabs %}
+
+#### Verify the setup
+
+To ensure the signer has been set up correctly, you can run the following commands:
+
+```bash
+# The CLI examples below may show outdated release versions.
+# Verify the signer's version
+~/stacks-signer/stacks-signer --version
+
+# Output:
+stacks-signer stacks-signer signer-3.1.0.0.5.0 (release/signer-3.1.0.0.5.0:513dbc5, release build, linux [x86_64])
+
+# Verify the config file
+~/stacks-signer/stacks-signer check-config -c ~/stacks-signer/signer-config.toml
+
+# Output:
+Config:
+Stacks node host: 127.0.0.1:20443
+Signer endpoint: 127.0.0.1:30000
+Stacks address: SP1G... # address from keychain file
+Public key: 03a3... # publicKey from keychain file
+Network: mainnet # or testnet
+Chain ID: 0x1 # or 0x80000000 for testnet
+Database path: /home/admin/stacks-signer/data/signer.sqlite
+Metrics endpoint: 127.0.0.1:9154
+```
+
+#### Start the signer
+
+If the outputs of the previous commands are correct, you can proceed and start the signer:
+
+```bash
+~/stacks-signer/stacks-signer run -c ~/stacks-signer/signer-config.toml
+```
+{% endstep %}
+
+{% step %}
+### Optional: Set up a Bitcoin node (strongly recommended)
+
+In order to optimize signer health and performance, we highly recommend setting up your own Bitcoin node rather than relying on a third-party node.
+
+We have created guides for running both a [full Bitcoin node](../readme/run-a-bitcoin-node.md) and a [pruned Bitcoin node](../readme/run-a-pruned-bitcoin-node.md) you can follow.
+{% endstep %}
+
+{% step %}
+### Set Up Your Stacks Node
+
+#### Download the stacks-node binary
+
+Official binaries are available from the [Stacks Core releases page on Github](https://github.com/stacks-network/stacks-core/releases). Each release includes pre-built binaries. Download the [latest node release ZIP file](https://github.com/stacks-network/stacks-core/releases/latest) for your server’s architecture and decompress it. Inside of that folder is a `stacks-node` binary.
+
+Assuming a `Linux x64 glibc` machine, the commands to download and uncompress the node binary look like this:
+
+```bash
+# The CLI examples below may show outdated release versions.
+# Enter the node directory
+cd ~/stacks-node
+
+# Download the node binary zip
+wget https://github.com/stacks-network/stacks-core/releases/latest/download/linux-glibc-x64.zip
+
+# Unzip the node binary archive
+unzip linux-glibc-x64.zip
+```
+
+#### Create the configuration file
+
+Create the configuration file required to start the node (be sure to replace `` with your auth token value):
+
+{% tabs %}
+{% tab title="Mainnet" %}
+{% hint style="warning" %}
+For mainnet, we strongly recommended that you run your own bitcoin node (you can follow guides on how to run a [full Bitcoin node](https://docs.stacks.co/guides-and-tutorials/nodes-and-miners/run-a-bitcoin-node) or a [pruned Bitcoin node](https://docs.stacks.co/guides-and-tutorials/nodes-and-miners/run-a-pruned-bitcoin-node)) in order to ensure you have no connection issues when downloading bitcoin blocks. A hosted bitcoin node may cause your stacks node to fall behind tip and remain unsynced.
+
+If you run your own bitcoin node, you'll have to update `peer_host` and optionally add `rpc_port`, `peer_port`, `username` and `password` fields under the `[burnchain]` section of the node's configuration file.
+{% endhint %}
+
+```bash
+# The CLI examples below may show outdated release versions.
+# Set environment variables
+AUTH_TOKEN= # Used for signer-node authentication, same token as the one set up in the signer configuration
+
+# Create the node's configuration file
+cat < ~/stacks-node/node-config.toml
+[node]
+working_dir = "$HOME/stacks-node/data"
+rpc_bind = "127.0.0.1:20443"
+p2p_bind = "0.0.0.0:20444"
+prometheus_bind = "127.0.0.1:9153"
+bootstrap_node = "02196f005965cebe6ddc3901b7b1cc1aa7a88f305bb8c5893456b8f9a605923893@seed.mainnet.hiro.so:20444,02539449ad94e6e6392d8c1deb2b4e61f80ae2a18964349bc14336d8b903c46a8c@cet.stacksnodes.org:20444,02ececc8ce79b8adf813f13a0255f8ae58d4357309ba0cedd523d9f1a306fcfb79@sgt.stacksnodes.org:20444,0303144ba518fe7a0fb56a8a7d488f950307a4330f146e1e1458fc63fb33defe96@est.stacksnodes.org:20444"
+stacker = true
+
+[burnchain]
+chain = "bitcoin"
+mode = "mainnet"
+peer_host = "bitcoin.mainnet.stacks.org"
+
+[connection_options]
+auth_token = "$AUTH_TOKEN"
+
+[[events_observer]]
+endpoint = "127.0.0.1:30000"
+events_keys = ["stackerdb", "block_proposal", "burn_blocks"]
+EOF
+```
+{% endtab %}
+
+{% tab title="Testnet" %}
+```bash
+# Set environment variables
+AUTH_TOKEN= # Used for signer-node authentication, same token as the one set up in the signer configuration
+
+# Create the node's configuration file
+cat < ~/stacks-node/node-config.toml
+[node]
+working_dir = "$HOME/stacks-node/data"
+rpc_bind = "127.0.0.1:20443"
+p2p_bind = "0.0.0.0:20444"
+bootstrap_node = "029266faff4c8e0ca4f934f34996a96af481df94a89b0c9bd515f3536a95682ddc@seed.testnet.hiro.so:30444"
+prometheus_bind = "127.0.0.1:9153"
+stacker = true
+pox_sync_sample_secs = 30
+always_use_affirmation_maps = true
+require_affirmed_anchor_blocks = true
+
+[burnchain]
+mode = "krypton"
+peer_host = "bitcoin.regtest.hiro.so"
+peer_port = 18444
+pox_prepare_length = 100
+pox_reward_length = 900
+
+[connection_options]
+auth_token = "$AUTH_TOKEN"
+private_neighbors = false
+
+[[events_observer]]
+endpoint = "127.0.0.1:30000"
+events_keys = ["stackerdb", "block_proposal", "burn_blocks"]
+
+[[ustx_balance]]
+address = "ST2QKZ4FKHAH1NQKYKYAYZPY440FEPK7GZ1R5HBP2"
+amount = 10000000000000000
+
+[[ustx_balance]]
+address = "ST319CF5WV77KYR1H3GT0GZ7B8Q4AQPY42ETP1VPF"
+amount = 10000000000000000
+
+[[ustx_balance]]
+address = "ST221Z6TDTC5E0BYR2V624Q2ST6R0Q71T78WTAX6H"
+amount = 10000000000000000
+
+[[ustx_balance]]
+address = "ST2TFVBMRPS5SSNP98DQKQ5JNB2B6NZM91C4K3P7B"
+amount = 10000000000000000
+
+[[burnchain.epochs]]
+epoch_name = "1.0"
+start_height = 0
+
+[[burnchain.epochs]]
+epoch_name = "2.0"
+start_height = 0
+
+[[burnchain.epochs]]
+epoch_name = "2.05"
+start_height = 1
+
+[[burnchain.epochs]]
+epoch_name = "2.1"
+start_height = 2
+
+[[burnchain.epochs]]
+epoch_name = "2.2"
+start_height = 3
+
+[[burnchain.epochs]]
+epoch_name = "2.3"
+start_height = 4
+
+[[burnchain.epochs]]
+epoch_name = "2.4"
+start_height = 5
+
+[[burnchain.epochs]]
+epoch_name = "2.5"
+start_height = 6
+
+[[burnchain.epochs]]
+epoch_name = "3.0"
+start_height = 1_900
+
+[[burnchain.epochs]]
+epoch_name = "3.1"
+start_height = 2_000
+EOF
+```
+{% endtab %}
+{% endtabs %}
+
+#### Optional: Start the node with a data archive
+
+You can [download a chainstate archive](https://archive.hiro.so/) in order to quickly sync your node, otherwise it will take a long time to get up-to-date with the other nodes.
+
+{% tabs %}
+{% tab title="Mainnet" %}
+```bash
+# Enter the node's datadir
+cd ~/stacks-node/data
+
+# Download the archive
+wget https://archive.hiro.so/mainnet/stacks-blockchain/mainnet-stacks-blockchain-latest.tar.gz
+
+# Decompress the archive
+tar -xvf mainnet-stacks-blockchain-latest.tar.gz
+
+# Remove the archive
+rm mainnet-stacks-blockchain-latest.tar.gz
+```
+{% endtab %}
+
+{% tab title="Testnet" %}
+```bash
+# Enter the node's datadir
+cd ~/stacks-node/data
+
+# Download the archive
+wget https://archive.hiro.so/testnet/stacks-blockchain/testnet-stacks-blockchain-latest.tar.gz
+
+# Decompress the archive
+tar -xvf testnet-stacks-blockchain-latest.tar.gz
+
+# Remove the archive
+rm testnet-stacks-blockchain-latest.tar.gz
+```
+{% endtab %}
+{% endtabs %}
+
+#### Verify the setup
+
+To ensure the node has been set up correctly, you can run the following commands:
+
+```bash
+# The CLI examples below may show outdated release versions.
+# Verify the node's version
+~/stacks-node/stacks-node version
+
+# Output:
+INFO [1738695915.769633] [testnet/stacks-node/src/main.rs:278] [main] stacks-node 3.1.0.0.5 (release/3.1.0.0.5:513dbc5, release build, linux [x86_64])
+stacks-node 3.1.0.0.5 (release/3.1.0.0.5:513dbc5, release build, linux [x86_64])
+
+# Verify the node's config
+~/stacks-node/stacks-node check-config --config ~/stacks-node/node-config.toml
+
+# Output:
+INFO [1738695915.769633] [testnet/stacks-node/src/main.rs:278] [main] stacks-node 3.1.0.0.5 (release/3.1.0.0.5:513dbc5, release build, linux [x86_64])
+INFO [1729788064.913175] [testnet/stacks-node/src/main.rs:318] [main] Loading config at path /home/admin/stacks-node/node-config.toml
+INFO [1729788064.969551] [testnet/stacks-node/src/main.rs:331] [main] Loaded config!
+```
+
+#### Start the node
+
+If the outputs of the previous commands are correct, you can proceed and start the node:
+
+```bash
+~/stacks-node/stacks-node start --config ~/stacks-node/node-config.toml
+```
+{% endstep %}
+
+{% step %}
+### Generate your signer signature
+
+In order to stack, you'll need your signer signature. The fields required are further explained in the [Generate a signer key signature](https://docs.stacks.co/guides-and-tutorials/stack-stx/stacking-flow#step-2-generate-a-signer-key-signature) guide.
+
+The command to generate a signature looks like this:
+
+```bash
+~/stacks-signer/stacks-signer generate-stacking-signature \
+ --method stack-stx \
+ --max-amount 1000000000000 \
+ --auth-id 195591226970828652622091037492597751808 \
+ --period 12 \
+ --reward-cycle 100 \
+ --pox-address 19tg... \
+ --config ~/stacks-signer/signer-config.toml \
+ --json
+```
+
+The generated JSON can be then copy-pasted directly in the [Leather Earn](https://earn.leather.io/) website mentioned in the next step.
+{% endstep %}
+
+{% step %}
+### Start stacking
+
+The simplest route is to solo stack. You can do that by using [Leather Earn](https://earn.leather.io/). Click on the 'Stack Independently' button and follow the instructions there.
+
+If you would like to learn more about solo stacking or running a pool operator, take a look at the [Stack STX](https://docs.stacks.co/guides-and-tutorials/stack-stx) guide.
+{% endstep %}
+
+{% step %}
+### Monitoring
+
+If you would like to learn more about monitoring your signer and its corresponding node, you can check the [How to Monitor a Signer](https://docs.stacks.co/guides-and-tutorials/running-a-signer/how-to-monitor-signer) guide.
+{% endstep %}
+{% endstepper %}
diff --git a/docs/operate/snapshot-the-chainstate.md b/docs/operate/snapshot-the-chainstate.md
new file mode 100644
index 0000000000..9486830d0c
--- /dev/null
+++ b/docs/operate/snapshot-the-chainstate.md
@@ -0,0 +1,222 @@
+# Snapshot the Chainstate
+
+{% hint style="info" %}
+**Intended audience**: Solo Stackers, Stacking pool operators, and node operators who need to create reliable chainstate backups.
+{% endhint %}
+
+Regular snapshots of your Stacks chainstate help you recover quickly when things go wrong. This guide shows you how to create and manage chainstate snapshots properly.
+
+{% hint style="warning" %}
+**Critical**: Always shut down your Stacks node properly before creating a snapshot. Creating snapshots while the node is running will result in corrupted chainstate data.
+{% endhint %}
+
+### Shutdown Procedure
+
+To produce a valid chainstate backup, the node should be stopped gracefully before making a copy. The following steps will correctly shutdown the Stacks node:
+
+{% stepper %}
+{% step %}
+### Check node status before shutdown
+
+```bash
+# Verify if the node is responsive
+curl http://localhost:20443/v2/info
+```
+{% endstep %}
+
+{% step %}
+### Initiate graceful shutdown
+
+* For Docker: `docker stop stacks-node` (allows at least 10 seconds for graceful shutdown)
+* For systemd: `systemctl stop stacks-node`
+* For manual processes:
+
+```bash
+kill $(ps aux | grep stacks-node | grep -v grep | awk '{print $2}')
+```
+{% endstep %}
+
+{% step %}
+### Verify complete shutdown
+
+```bash
+# Ensure no stacks-node processes are running
+ps aux | grep stacks-node
+```
+{% endstep %}
+{% endstepper %}
+
+### Overview of Snapshot Methods
+
+There are two primary approaches for creating Stacks chainstate snapshots:
+
+1. **File-based snapshots** - compress up the chainstate folder
+2. **Volume snapshots** - snapshot the entire disk/volume
+
+Each method has its advantages depending on your infrastructure setup and recovery requirements.
+
+### File-Based Snapshots
+
+This method involves compressing the chainstate directory and storing it locally, or uploading to a cloud storage service.
+
+#### Steps (see [Example Automation Code section](snapshot-the-chainstate.md#example-automation-code) below)
+
+1. **Stop the Stacks node gracefully**
+2. **Create compressed archive**
+3. **Upload to cloud storage or save it locally**
+4. **Restart the Stacks node**
+
+### Volume-Based Snapshots
+
+This method creates block-level snapshots of the entire storage volume containing the chainstate. Different filesystems have different tools:
+
+* **ZFS**: Use `zfs snapshot` - [OpenZFS documentation](https://openzfs.github.io/openzfs-docs/man/v2.3/8/zfs-snapshot.8.html)
+* **XFS**: Use `xfsdump` - [XFS documentation](https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/7/html/storage_administration_guide/xfsbackuprestore)
+* **ext4**: Use LVM snapshots - [LVM guide](https://kerneltalks.com/disk-management/how-to-guide-lvm-snapshot/)
+
+You can also use cloud provider snapshot tools (AWS EBS, Azure Disk, GCP Persistent Disk).
+
+#### Steps
+
+1. **Stop the Stacks node gracefully**
+2. **Create volume snapshot** using ZFS or cloud provider tools
+3. **Restart the Stacks node**
+
+### How to Restore
+
+After restoring the chainstate, you can check for corruption by waiting for a few blocks to download and ensuring the node syncs correctly.
+
+#### From File Snapshots
+
+1. Stop the Stacks node
+2. Download and extract the snapshot
+3. Replace the chainstate directory
+4. Restart the node
+
+#### From Volume Snapshots
+
+1. Stop the Stacks node
+2. Create a new volume from the snapshot
+3. Attach the volume to your instance
+4. Update mount points if necessary
+5. Restart the node
+
+### Example Automation Code
+
+Here's a simple script that handles both file and volume snapshots on AWS.
+
+{% code title="snapshot.sh" %}
+```
+#!/bin/bash
+set -euo pipefail
+
+# Configuration variables - modify these for your setup
+SERVICE_NAME="stacks-node" # systemd service name
+SNAPSHOT_DIR="/var/stacks/mainnet" # path to chainstate directory
+SNAPSHOT_BASE="/tmp" # temporary directory for archives
+EBS_VOLUME_ID="vol-1234567890abcdef0" # EBS volume ID containing chainstate
+S3_BUCKET="s3://my-stacks-snapshots" # S3 bucket for archive storage
+SNAPSHOT_TYPE="archive" # Options: ebs, archive, or both
+
+# Stop the Stacks node service gracefully
+stop_service() {
+ echo "Stopping $SERVICE_NAME..."
+ sudo systemctl stop "$SERVICE_NAME"
+}
+
+# Start the Stacks node service
+start_service() {
+ echo "Starting $SERVICE_NAME..."
+ sudo systemctl start "$SERVICE_NAME"
+}
+
+# Create compressed archive and upload to S3
+snapshot_archive() {
+ echo "Creating archive snapshot..."
+
+ # Generate timestamp and version info for filename
+ TIMESTAMP=$(date +"%Y%m%d")
+ DIR_NAME=$(basename "$SNAPSHOT_DIR")
+ VERSION=$(stacks-node version 2>&1 | tail -n 1 | awk '{print $2}')
+ DEST="$SNAPSHOT_BASE/$DIR_NAME-$VERSION-$TIMESTAMP.tar.zst"
+
+ # Create compressed archive (using zstd for better compression)
+ tar -cf - -C "$(dirname $SNAPSHOT_DIR)" "$(basename $SNAPSHOT_DIR)" | pzstd -o "$DEST"
+ echo "Archive created at: $DEST"
+
+ # Upload to S3
+ echo "Uploading to S3..."
+ aws s3 cp "$DEST" "$S3_BUCKET/"
+ echo "S3 upload complete: $S3_BUCKET/$(basename "$DEST")"
+
+ # Clean up local archive
+ rm "$DEST"
+}
+
+# Create EBS volume snapshot
+snapshot_ebs() {
+ echo "Creating EBS snapshot of $EBS_VOLUME_ID..."
+
+ # Generate description with timestamp
+ TIMESTAMP=$(date +"%Y%m%d")
+ DESC="Stacks Node Snapshot - $TIMESTAMP"
+
+ # Create snapshot with tags
+ SNAPSHOT_ID=$(aws ec2 create-snapshot \
+ --volume-id "$EBS_VOLUME_ID" \
+ --description "$DESC" \
+ --tag-specifications "ResourceType=snapshot,Tags=[{Key=Name,Value=Stacks Snapshot},{Key=type,Value=chainstate}]" \
+ --query 'SnapshotId' --output text)
+
+ echo "EBS Snapshot ID: $SNAPSHOT_ID"
+}
+
+# Main execution function
+main() {
+ case "$SNAPSHOT_TYPE" in
+ ebs)
+ stop_service
+ snapshot_ebs
+ start_service
+ ;;
+ archive)
+ stop_service
+ snapshot_archive
+ start_service
+ ;;
+ both)
+ stop_service
+ snapshot_archive # Create archive first
+ snapshot_ebs # Then EBS snapshot
+ start_service
+ ;;
+ *)
+ echo "Invalid snapshot type: $SNAPSHOT_TYPE. Available options: ebs, archive, or both."
+ exit 1
+ ;;
+ esac
+
+ echo "Snapshot process completed successfully!"
+}
+
+# Execute main function
+main
+```
+{% endcode %}
+
+#### How to Use
+
+1. **Edit the variables** at the top of the script for your setup
+2. **Make it executable**: `chmod +x snapshot.sh`
+3. **Run it**: `./snapshot.sh`
+4. **Schedule it with cron** for daily backups:
+
+ ```
+ # Daily snapshot at 2 AM
+ 0 2 * * * /path/to/snapshot.sh
+ ```
+
+#### What You Need
+
+* AWS CLI set up with the right permissions
+* `pzstd` installed (comes with the zstd package)
diff --git a/docs/operate/stacking-stx/README.md b/docs/operate/stacking-stx/README.md
new file mode 100644
index 0000000000..e6c3a1167c
--- /dev/null
+++ b/docs/operate/stacking-stx/README.md
@@ -0,0 +1,128 @@
+# Stacking STX
+
+Stacking is an essential component of Stacks.
+
+There are three different ways you can potentially stack your STX tokens and we have a dedicated guide for each of these scenarios.
+
+If you aren't familiar with how stacking works, especially as it relates to signing after the Nakamoto upgrade, be sure to check out the following concept guides:
+
+* [Stackers and signing](https://app.gitbook.com/s/H74xqoobupBWwBsVMJhK/block-production/signing)
+* [Stacking](https://app.gitbook.com/s/H74xqoobupBWwBsVMJhK/block-production/stacking)
+
+In Nakamoto, stacking flows have significant changes in comparison to previous versions of Stacks. Because Nakamoto requires stackers to run a signer, which validates blocks produced by Stacks miners, stackers need to provide new information when making Stacking transactions.
+
+These changes affect both solo Stacking and delegated Stacking. This document outlines the new flows for solo stacking. The next doc outlines the flow and steps for operating a pool.
+
+The following sections will walk you through how to begin operating as a solo stacker.
+
+Stacking utilizes the `pox-4` contract. There is a detailed [walkthrough of the stacking contract](https://app.gitbook.com/s/GVj1Z9vMuEOMe7oH7Wnq/clarity/example-contracts/stacking) that you can look at to see what functions are being called at each phase and some common errors you may encounter. This will be especially useful for pool operators who need to call these functions.
+
+This doc is also useful if you run into errors when calling stacking functions, as it both walks through several common error scenarios and walks through each function call so you can more easily trace what might be happening.
+
+Before we get into the step-by-step of how to actually stack, it's important to make sure you have an understanding of the different roles, processes and functions involved in Stacking.
+
+### Definitions and Roles
+
+* **Stacker**: an entity locking their STX to receive PoX rewards. This is a broad term including solo Stackers and Stackers who use pools.
+* **Solo stacker**: an entity that locks their own STX and runs a signer. They don’t receive delegation.
+* **Delegator**: a stacker who locks their STX by delegating to a pool operator that runs a signer. They don’t run the signer.
+* **Pool operator**: an entity that runs a Signer and allows others to delegate their STX to them. A pool operator doesn’t need to Stack their own STX, but they can. They will also run a signer, but the pool operator and signer address may be different
+* **Signer**: an entity that runs the stacks-signer software and participates in block validation. This can be either a solo Stacker or an entity receiving delegated STX. Depending on context, this may also refer to the signer software that validates blocks.
+
+{% hint style="info" %}
+It's important to understand that in the context of the pool operator and signer, these are likely the same _entity_ but may not be the same Stacks address.
+
+This distinction will be discussed further as we cover the step-by-step process below.
+{% endhint %}
+
+Below are the primary ways you can stack:
+
+{% stepper %}
+{% step %}
+### Solo stacking
+
+If you meet the minimum and want to [solo stack](solo-stack.md), you will either need to run a signer, collaborate with an existing one, or use [stacking.tools](https://stacking.tools/). This guide will walk you through all options.
+{% endstep %}
+
+{% step %}
+### Operate a pool
+
+You can also [operate a pool](operate-a-stacking-pool.md) and have others delegate their STX to you. If you are a pool operator, you will need to run a signer, collaborate with an existing one, or use [stacking.tools](https://stacking.tools/).
+{% endstep %}
+
+{% step %}
+### Stack with a pool
+
+If you do not meet the minimum amount of STX to solo stack, you can [delegate your STX to a pool operator ](stack-with-a-pool.md)and have them stack on your behalf. The minimum stacking amount is dynamic and can be found by visiting the https://api.hiro.so/v2/pox endpoint and looking at the `min_threshold_ustx` field. Note it is denoted in uSTX (1 STX = 1,000,000 uSTX). This is the most common stacking scenario.
+{% endstep %}
+{% endstepper %}
+
+As you read through these, it may be helpful to follow along with the functions in the [pox-4 contract](https://explorer.hiro.so/txid/SP000000000000000000002Q6VF78.pox-4?chain=mainnet) to get an idea of what each function is doing.
+
+### Relationship between manual stacking transactions and the running signer
+
+This section describes the various transactions that signer entities need to make in order to be registered as a signer for a certain reward cycle. The order of operations between the automated signer and the stacking transactions that need to be done “manually” is important for ensuring that a signer is fully set up for a certain reward cycle.
+
+#### Prerequisite: ensure the signer is hosted and running
+
+It's important to emphasize the importance of getting the signer running in a hosted environment before making Stacking transactions. If the signer doesn’t do that, they run the risk of being registered as a signer without their signer software being ready to run DKG and other important consensus mechanisms.
+
+Some of the important things to double check to ensure the signer is “running” are:
+
+* The signer software is configured with a private key that the user can access (either through SSH or other means). This is important because their signer needs to utilize this private key to generate signer key signatures that are used in Stacking transactions.
+* The signer software is properly configured to make RPC calls to a Stacks node. This refers to the `endpoint` signer configuration field. If properly configured, there should be logs in the Stacks node that show the RPC calls being made from the signer.
+* The stacks node is properly configured to send events to the signer. This refers to the \[`event_observers`] field in the Stacks Node’s configuration. If properly configured, the signer should have logs indicating that it’s receiving events from the Stacks node.
+
+### How a signer becomes registered in the signer set
+
+Each of the stacking transactions described above are done “manually”. More specifically, this means that none of these transactions are executed automatically by the signer software. The transactions must be done “out of band”.
+
+In order for a signer to actually be registered in a reward cycle, there need to be manual transactions made in the `pox-4` contract. While the signer software is running, it is continually polling the Stacks node and asking “am I a signer in reward cycle N?”.
+
+If these manual transactions are confirmed, and the signer has enough STX associated with the signer’s public key, the signer will be registered as a signer in the signer set.
+
+#### Solo stacking
+
+The workflow for solo stackers is simpler, because there are less stacking transactions that need to be made.
+
+For solo stacking, the only transaction that needs to be made is `stack-stx`. Included in this transaction’s payload is the signer’s public key.
+
+In order for the signer to be registered in reward cycle N+1, the `stack-stx` transaction must be confirmed during the first 2000 blocks of reward cycle N. The last 100 blocks of cycle N (the “prepare phase”) is where DKG occurs.
+
+The start of the prepare phase is when Stacks nodes determine the official signer set of the next reward cycle.
+
+#### Delegated Stacking
+
+The workflow for delegated signers is more complex, because it requires more transactions.
+
+This workflow is explained more in detail in the [operate a pool](operate-a-stacking-pool.md) guide, but the high-level workflow is:
+
+{% stepper %}
+{% step %}
+### Stackers delegate their STX to a pool operator
+
+Stackers delegate their STX to a pool operator.
+{% endstep %}
+
+{% step %}
+### The pool operator approves specific stackers
+
+The pool operator makes `delegate-stack-stx` transactions to “approve” specific stackers. This needs to be called for every individual stacker that delegates to them.
+{% endstep %}
+
+{% step %}
+### The pool operator commits delegated STX
+
+The pool operator makes a `stack-aggregation-commit` transaction to “commit” all of its delegated STX up to this point.
+{% endstep %}
+{% endstepper %}
+
+Similar to solo stacking, these steps must be made before the prepare phase of an upcoming reward cycle.
+
+### Once a signer is registered in the signer set
+
+During the prepare phase before a reward cycle, Stacks nodes automatically determine the signer set for the upcoming cycle. When this occurs, the Stacks nodes make an “internal” transaction to update the `.signers` contract with the list of signers.
+
+The signer software is continuously polling the Stacks node to see if it is registered for a cycle. If the signer software finds that it is registered (by matching its public key to the signers stored in the `signers` contract) it begins performing its duties as a signer.
+
+During the prepare phase, the signers perform DKG through StackerDB messages. Once an aggregate public key is determined, the signer automatically makes a `vote-for-aggregate-key` transaction. No out-of-band action is needed to be taken for this to occur.
diff --git a/docs/operate/stacking-stx/increase-stacked-position.md b/docs/operate/stacking-stx/increase-stacked-position.md
new file mode 100644
index 0000000000..6ba205b031
--- /dev/null
+++ b/docs/operate/stacking-stx/increase-stacked-position.md
@@ -0,0 +1,495 @@
+# Increase Stacked Position
+
+This guide explains how to increase your stacked STX position. The process depends on your role:
+
+* **Solo Stackers** use the `stack-increase` function.
+* **Delegators** must first revoke their current delegation using `revoke-delegate-stx` and then re-delegate with a higher amount to the same pool operator using `delegate-stx`.
+* **Pool Operators** increase their delegators' locked amount by calling `delegate-stack-increase` and then stacking the increased amount with either `stack-aggregation-commit-indexed` (if not already committed) or `stack-aggregation-increase` (if the commit has already been made).
+
+## Solo Stackers
+
+Solo stackers can add more STX to their active stacking position by calling the `stack-increase` function. The new amount takes effect from the next stacking cycle.
+
+The `stack-increase` function locks an additional amount of STX from your account. Your account must be actively stacking and not delegating, and you must have enough unlocked STX to cover the increase.
+
+
+
+Function source code
+
+```clojure
+;; Increase the number of STX locked.
+;; *New in Stacks 2.1*
+;; This method locks up an additional amount of STX from `tx-sender`'s, indicated
+;; by `increase-by`. The `tx-sender` must already be Stacking & must not be
+;; straddling more than one signer-key for the cycles effected.
+;; Refer to `verify-signer-key-sig` for more information on the authorization parameters
+;; included here.
+(define-public (stack-increase
+ (increase-by uint)
+ (signer-sig (optional (buff 65)))
+ (signer-key (buff 33))
+ (max-amount uint)
+ (auth-id uint))
+ (let ((stacker-info (stx-account tx-sender))
+ (amount-stacked (get locked stacker-info))
+ (amount-unlocked (get unlocked stacker-info))
+ (unlock-height (get unlock-height stacker-info))
+ (cur-cycle (current-pox-reward-cycle))
+ (first-increased-cycle (+ cur-cycle u1))
+ (stacker-state (unwrap! (map-get? stacking-state
+ { stacker: tx-sender })
+ (err ERR_STACK_INCREASE_NOT_LOCKED)))
+ (cur-pox-addr (get pox-addr stacker-state))
+ (cur-period (get lock-period stacker-state)))
+ ;; tx-sender must be currently locked
+ (asserts! (> amount-stacked u0)
+ (err ERR_STACK_INCREASE_NOT_LOCKED))
+ ;; must be called with positive `increase-by`
+ (asserts! (>= increase-by u1)
+ (err ERR_STACKING_INVALID_AMOUNT))
+ ;; stacker must have enough stx to lock
+ (asserts! (>= amount-unlocked increase-by)
+ (err ERR_STACKING_INSUFFICIENT_FUNDS))
+ ;; must be called directly by the tx-sender or by an allowed contract-caller
+ (asserts! (check-caller-allowed)
+ (err ERR_STACKING_PERMISSION_DENIED))
+ ;; stacker must be directly stacking
+ (asserts! (> (len (get reward-set-indexes stacker-state)) u0)
+ (err ERR_STACKING_IS_DELEGATED))
+ ;; stacker must not be delegating
+ (asserts! (is-none (get delegated-to stacker-state))
+ (err ERR_STACKING_IS_DELEGATED))
+
+ ;; Validate that amount is less than or equal to `max-amount`
+ (asserts! (>= max-amount (+ increase-by amount-stacked)) (err ERR_SIGNER_AUTH_AMOUNT_TOO_HIGH))
+
+ ;; Verify signature from delegate that allows this sender for this cycle
+ (try! (consume-signer-key-authorization cur-pox-addr cur-cycle "stack-increase" cur-period signer-sig signer-key increase-by max-amount auth-id))
+
+ ;; update reward cycle amounts
+ (asserts! (is-some (fold increase-reward-cycle-entry
+ (get reward-set-indexes stacker-state)
+ (some { first-cycle: first-increased-cycle,
+ reward-cycle: (get first-reward-cycle stacker-state),
+ stacker: tx-sender,
+ add-amount: increase-by,
+ signer-key: signer-key })))
+ (err ERR_INVALID_INCREASE))
+ ;; NOTE: stacking-state map is unchanged: it does not track amount-stacked in PoX-4
+ (ok { stacker: tx-sender, total-locked: (+ amount-stacked increase-by)})))
+```
+
+
+
+Arguments:
+
+* Increase by: the amount of uSTX to add to your lock amount.
+* Signer public key: the public key used for signing. This can stay the same, or you can use a new key.
+* Signer signature: a signature proving control of your signing key.
+* Max Amount: used to validate the signer signature provided. It represents the maximum number of uSTX (1 STX = 1,000,000 uSTX) that can be stacked in this transaction.
+* Auth Id: used to validate the signer signature provided. It is a random integer that prevents re-use of this particular signer signature.
+
+## Delegators
+
+Delegators have to increase their delegated amount in two steps.
+
+{% stepper %}
+{% step %}
+### Revoke Your Current Delegation
+
+Before increasing your delegation, cancel your current delegation through the `revoke-delegate-stx` function, so that you can delegate an increased amount of STX afterwards.
+
+
+
+Function source code
+
+```clojure
+;; Revokes the delegation to the current stacking pool.
+;; New in pox-4: Fails if the delegation was already revoked.
+;; Returns the last delegation state.
+(define-public (revoke-delegate-stx)
+ (let ((last-delegation-state (get-check-delegation tx-sender)))
+ ;; must be called directly by the tx-sender or by an allowed contract-caller
+ (asserts! (check-caller-allowed)
+ (err ERR_STACKING_PERMISSION_DENIED))
+ (asserts! (is-some last-delegation-state) (err ERR_DELEGATION_ALREADY_REVOKED))
+ (asserts! (map-delete delegation-state { stacker: tx-sender }) (err ERR_DELEGATION_ALREADY_REVOKED))
+ (ok last-delegation-state)))
+```
+
+
+{% endstep %}
+
+{% step %}
+### Delegate with a Higher Amount
+
+After revoking, call the `delegate-stx` function with your new, higher amount. This function does not directly delegate the STX, but rather allows the pool operator to issue the stacking lock on behalf of the user calling this function.
+
+
+
+Function source code
+
+```clojure
+;; Delegate to `delegate-to` the ability to stack from a given address.
+;; This method _does not_ lock the funds, rather, it allows the delegate
+;; to issue the stacking lock.
+;; The caller specifies:
+;; * amount-ustx: the total amount of ustx the delegate may be allowed to lock
+;; * until-burn-ht: an optional burn height at which this delegation expires
+;; * pox-addr: an optional address to which any rewards *must* be sent
+(define-public (delegate-stx (amount-ustx uint)
+ (delegate-to principal)
+ (until-burn-ht (optional uint))
+ (pox-addr (optional { version: (buff 1), hashbytes: (buff 32) })))
+
+ (begin
+ ;; must be called directly by the tx-sender or by an allowed contract-caller
+ (asserts! (check-caller-allowed)
+ (err ERR_STACKING_PERMISSION_DENIED))
+
+ ;; delegate-stx no longer requires the delegator to not currently
+ ;; be stacking.
+ ;; delegate-stack-* functions assert that
+ ;; 1. users can't swim in two pools at the same time.
+ ;; 2. users can't switch pools without cool down cycle.
+ ;; Other pool admins can't increase or extend.
+ ;; 3. users can't join a pool while already directly stacking.
+
+ ;; pox-addr, if given, must be valid
+ (match pox-addr
+ address
+ (asserts! (check-pox-addr-version (get version address))
+ (err ERR_STACKING_INVALID_POX_ADDRESS))
+ true)
+
+ ;; tx-sender must not be delegating
+ (asserts! (is-none (get-check-delegation tx-sender))
+ (err ERR_STACKING_ALREADY_DELEGATED))
+
+ ;; add delegation record
+ (map-set delegation-state
+ { stacker: tx-sender }
+ { amount-ustx: amount-ustx,
+ delegated-to: delegate-to,
+ until-burn-ht: until-burn-ht,
+ pox-addr: pox-addr })
+
+ (ok true)))
+```
+
+
+
+Arguments:
+
+* Amount: Denoted in uSTX (1 STX = 1,000,000 uSTX).
+* Delegate to: the STX address of the pool operator they're delegating to.
+* Until burn height: optional BTC block height when the delegation expires.
+* Pox Address: optional BTC address that, if specified, the signer must use to accept this delegation.
+
+{% hint style="info" %}
+Make sure the revocation is successful before initiating a new delegation. Otherwise, the `delegate-stx` transaction will fail.
+{% endhint %}
+{% endstep %}
+{% endstepper %}
+
+## Pool Operators
+
+Pool operators can increase the total stacking amount through a two-step process. First, update the delegation's locked amount with `delegate-stack-increase`. Then, stack the increased amount by committing it in a future cycle, or increasing an already committed position.
+
+### Increase the Locked Amount
+
+The `delegate-stack-increase` function allows a pool operator to add more STX to the existing locked position for a given delegator. It performs necessary checks and updates the delegation state with the increased amount.
+
+
+
+Function source code
+
+```clojure
+;; As a delegator, increase an active Stacking lock, issuing a "partial commitment" for the
+;; increased cycles.
+;; *New in Stacks 2.1*
+;; This method increases `stacker`'s current lockup and partially commits the additional
+;; STX to `pox-addr`
+(define-public (delegate-stack-increase
+ (stacker principal)
+ (pox-addr { version: (buff 1), hashbytes: (buff 32) })
+ (increase-by uint))
+ (let ((stacker-info (stx-account stacker))
+ (existing-lock (get locked stacker-info))
+ (available-stx (get unlocked stacker-info))
+ (unlock-height (get unlock-height stacker-info)))
+
+ ;; must be called with positive `increase-by`
+ (asserts! (>= increase-by u1)
+ (err ERR_STACKING_INVALID_AMOUNT))
+
+ (let ((unlock-in-cycle (burn-height-to-reward-cycle unlock-height))
+ (cur-cycle (current-pox-reward-cycle))
+ (first-increase-cycle (+ cur-cycle u1))
+ (last-increase-cycle (- unlock-in-cycle u1))
+ (cycle-count (try! (if (<= first-increase-cycle last-increase-cycle)
+ (ok (+ u1 (- last-increase-cycle first-increase-cycle)))
+ (err ERR_STACKING_INVALID_LOCK_PERIOD))))
+ (new-total-locked (+ increase-by existing-lock))
+ (stacker-state
+ (unwrap! (map-get? stacking-state { stacker: stacker })
+ (err ERR_STACK_INCREASE_NOT_LOCKED))))
+
+ ;; must be called directly by the tx-sender or by an allowed contract-caller
+ (asserts! (check-caller-allowed)
+ (err ERR_STACKING_PERMISSION_DENIED))
+
+ ;; stacker must not be directly stacking
+ (asserts! (is-eq (len (get reward-set-indexes stacker-state)) u0)
+ (err ERR_STACKING_NOT_DELEGATED))
+
+ ;; stacker must be delegated to tx-sender
+ (asserts! (is-eq (unwrap! (get delegated-to stacker-state)
+ (err ERR_STACKING_NOT_DELEGATED))
+ tx-sender)
+ (err ERR_STACKING_PERMISSION_DENIED))
+
+ ;; stacker must be currently locked
+ (asserts! (> existing-lock u0)
+ (err ERR_STACK_INCREASE_NOT_LOCKED))
+
+ ;; stacker must have enough stx to lock
+ (asserts! (>= available-stx increase-by)
+ (err ERR_STACKING_INSUFFICIENT_FUNDS))
+
+ ;; stacker must have delegated to the caller
+ (let ((delegation-info (unwrap! (get-check-delegation stacker) (err ERR_STACKING_PERMISSION_DENIED)))
+ (delegated-to (get delegated-to delegation-info))
+ (delegated-amount (get amount-ustx delegation-info))
+ (delegated-pox-addr (get pox-addr delegation-info))
+ (delegated-until (get until-burn-ht delegation-info)))
+ ;; must have delegated to tx-sender
+ (asserts! (is-eq delegated-to tx-sender)
+ (err ERR_STACKING_PERMISSION_DENIED))
+ ;; must have delegated enough stx
+ (asserts! (>= delegated-amount new-total-locked)
+ (err ERR_DELEGATION_TOO_MUCH_LOCKED))
+ ;; if pox-addr is set, must be equal to pox-addr
+ (asserts! (match delegated-pox-addr
+ specified-pox-addr (is-eq pox-addr specified-pox-addr)
+ true)
+ (err ERR_DELEGATION_POX_ADDR_REQUIRED))
+ ;; delegation must not expire before lock period
+ (asserts! (match delegated-until
+ until-burn-ht
+ (>= until-burn-ht unlock-height)
+ true)
+ (err ERR_DELEGATION_EXPIRES_DURING_LOCK)))
+
+ ;; delegate stacking does minimal-can-stack-stx
+ (try! (minimal-can-stack-stx pox-addr new-total-locked first-increase-cycle (+ u1 (- last-increase-cycle first-increase-cycle))))
+
+ ;; register the PoX address with the amount stacked via partial stacking
+ ;; before it can be included in the reward set, this must be committed!
+ (add-pox-partial-stacked pox-addr first-increase-cycle cycle-count increase-by)
+
+ ;; stacking-state is unchanged, so no need to update
+
+ ;; return the lock-up information, so the node can actually carry out the lock.
+ (ok { stacker: stacker, total-locked: new-total-locked}))))
+```
+
+
+
+Arguments:
+
+* Stacker: the STX address of the delegator.
+* Pox Address: the BTC address of the pool operator where they will receive the BTC rewards. If the delegator has set his own BTC address in the `delegate-stx` call, this address will have to be the same one.
+* Increase by: the amount of uSTX to add to the delegator's locked amount.
+
+
+
+## Stack the Increased Amount
+
+Once the locked amount is updated, the operator must commit the change. There are two functions that can be used to stack the increased amount:
+
+{% stepper %}
+{% step %}
+#### If the Commit Has Not Yet Been Made: stack-aggregation-commit-indexed
+
+This function stacks the total locked amount for an upcoming reward cycle. Note that the `stack-aggregation-commit-indexed` function wraps the `inner-stack-aggregation-commit` function. The wrapped inner function is included here.
+
+
+
+Function source code
+
+```clojure
+;; Commit partially stacked STX and allocate a new PoX reward address slot.
+;; This allows a stacker/delegate to lock fewer STX than the minimal threshold in multiple transactions,
+;; so long as: 1. The pox-addr is the same.
+;; 2. This "commit" transaction is called _before_ the PoX anchor block.
+;; This ensures that each entry in the reward set returned to the stacks-node is greater than the threshold,
+;; but does not require it be all locked up within a single transaction
+;;
+;; Returns (ok uint) on success, where the given uint is the reward address's index in the list of reward
+;; addresses allocated in this reward cycle. This index can then be passed to `stack-aggregation-increase`
+;; to later increment the STX this PoX address represents, in amounts less than the stacking minimum.
+;;
+;; *New in Stacks 2.1.*
+(define-private (inner-stack-aggregation-commit (pox-addr { version: (buff 1), hashbytes: (buff 32) })
+ (reward-cycle uint)
+ (signer-sig (optional (buff 65)))
+ (signer-key (buff 33))
+ (max-amount uint)
+ (auth-id uint))
+ (let ((partial-stacked
+ ;; fetch the partial commitments
+ (unwrap! (map-get? partial-stacked-by-cycle { pox-addr: pox-addr, sender: tx-sender, reward-cycle: reward-cycle })
+ (err ERR_STACKING_NO_SUCH_PRINCIPAL))))
+ ;; must be called directly by the tx-sender or by an allowed contract-caller
+ (asserts! (check-caller-allowed)
+ (err ERR_STACKING_PERMISSION_DENIED))
+ (let ((amount-ustx (get stacked-amount partial-stacked)))
+ (try! (consume-signer-key-authorization pox-addr reward-cycle "agg-commit" u1 signer-sig signer-key amount-ustx max-amount auth-id))
+ (try! (can-stack-stx pox-addr amount-ustx reward-cycle u1))
+ ;; Add the pox addr to the reward cycle, and extract the index of the PoX address
+ ;; so the delegator can later use it to call stack-aggregation-increase.
+ (let ((add-pox-addr-info
+ (add-pox-addr-to-ith-reward-cycle
+ u0
+ { pox-addr: pox-addr,
+ first-reward-cycle: reward-cycle,
+ num-cycles: u1,
+ reward-set-indexes: (list),
+ stacker: none,
+ signer: signer-key,
+ amount-ustx: amount-ustx,
+ i: u0 }))
+ (pox-addr-index (unwrap-panic
+ (element-at (get reward-set-indexes add-pox-addr-info) u0))))
+
+ ;; don't update the stacking-state map,
+ ;; because it _already has_ this stacker's state
+ ;; don't lock the STX, because the STX is already locked
+ ;;
+ ;; clear the partial-stacked state, and log it
+ (map-delete partial-stacked-by-cycle { pox-addr: pox-addr, sender: tx-sender, reward-cycle: reward-cycle })
+ (map-set logged-partial-stacked-by-cycle { pox-addr: pox-addr, sender: tx-sender, reward-cycle: reward-cycle } partial-stacked)
+ (ok pox-addr-index)))))
+```
+
+
+
+Arguments:
+
+* Pox Address: the BTC address to receive rewards.
+* Reward-cycle: a reward cycle in the future.
+* Signer public key: the public key of your signer.
+* Signer signature: a signature proving control of your signing key.
+* Max Amount: used to validate the signer signature provided.
+* Auth Id: used to validate the signer signature provided.
+{% endstep %}
+
+{% step %}
+#### If the Commit Has Already Been Made: stack-aggregation-increase
+
+If you have previously committed an amount, you can further increase the stacked position by calling `stack-aggregation-increase`. This function adds an additional amount of STX to the already committed delegation.
+
+
+
+Function source code
+
+```clojure
+;; Commit partially stacked STX to a PoX address which has already received some STX (more than the Stacking min).
+;; This allows a delegator to lock up marginally more STX from new delegates, even if they collectively do not
+;; exceed the Stacking minimum, so long as the target PoX address already represents at least as many STX as the
+;; Stacking minimum.
+;;
+;; The `reward-cycle-index` is emitted as a contract event from `stack-aggregation-commit` when the initial STX are
+;; locked up by this delegator. It must be passed here to add more STX behind this PoX address. If the delegator
+;; called `stack-aggregation-commit` multiple times for the same PoX address, then any such `reward-cycle-index` will
+;; work here.
+;;
+;; *New in Stacks 2.1*
+;;
+(define-public (stack-aggregation-increase (pox-addr { version: (buff 1), hashbytes: (buff 32) })
+ (reward-cycle uint)
+ (reward-cycle-index uint))
+ (let ((partial-stacked
+ ;; fetch the partial commitments
+ (unwrap! (map-get? partial-stacked-by-cycle { pox-addr: pox-addr, sender: tx-sender, reward-cycle: reward-cycle })
+ (err ERR_STACKING_NO_SUCH_PRINCIPAL))))
+
+ ;; must be called directly by the tx-sender or by an allowed contract-caller
+ (asserts! (check-caller-allowed)
+ (err ERR_STACKING_PERMISSION_DENIED))
+
+ ;; reward-cycle must be in the future
+ (asserts! (> reward-cycle (current-pox-reward-cycle))
+ (err ERR_STACKING_INVALID_LOCK_PERIOD))
+
+ (let ((amount-ustx (get stacked-amount partial-stacked))
+ ;; reward-cycle must point to an existing record in reward-cycle-total-stacked
+ ;; infallible; getting something from partial-stacked-by-cycle succeeded so this must succeed
+ (existing-total (unwrap-panic (map-get? reward-cycle-total-stacked { reward-cycle: reward-cycle })))
+ ;; reward-cycle and reward-cycle-index must point to an existing record in reward-cycle-pox-address-list
+ (existing-entry (unwrap! (map-get? reward-cycle-pox-address-list { reward-cycle: reward-cycle, index: reward-cycle-index })
+ (err ERR_DELEGATION_NO_REWARD_SLOT)))
+ (increased-ustx (+ (get total-ustx existing-entry) amount-ustx))
+ (total-ustx (+ (get total-ustx existing-total) amount-ustx)))
+
+ ;; must be stackable
+ (try! (minimal-can-stack-stx pox-addr total-ustx reward-cycle u1))
+
+ ;; new total must exceed the stacking minimum
+ (asserts! (<= (get-stacking-minimum) total-ustx)
+ (err ERR_STACKING_THRESHOLD_NOT_MET))
+
+ ;; there must *not* be a stacker entry (since this is a delegator)
+ (asserts! (is-none (get stacker existing-entry))
+ (err ERR_DELEGATION_WRONG_REWARD_SLOT))
+
+ ;; the given PoX address must match the one on record
+ (asserts! (is-eq pox-addr (get pox-addr existing-entry))
+ (err ERR_DELEGATION_WRONG_REWARD_SLOT))
+
+ ;; update the pox-address list -- bump the total-ustx
+ (map-set reward-cycle-pox-address-list
+ { reward-cycle: reward-cycle, index: reward-cycle-index }
+ { pox-addr: pox-addr,
+ total-ustx: increased-ustx,
+ stacker: none,
+ ;; TODO: this must be authorized with a signature, or tx-sender allowance!
+ signer: (get signer existing-entry) })
+
+ ;; update the total ustx in this cycle
+ (map-set reward-cycle-total-stacked
+ { reward-cycle: reward-cycle }
+ { total-ustx: total-ustx })
+
+ ;; don't update the stacking-state map,
+ ;; because it _already has_ this stacker's state
+ ;; don't lock the STX, because the STX is already locked
+ ;;
+ ;; clear the partial-stacked state, and log it
+ (map-delete partial-stacked-by-cycle { pox-addr: pox-addr, sender: tx-sender, reward-cycle: reward-cycle })
+ (map-set logged-partial-stacked-by-cycle { pox-addr: pox-addr, sender: tx-sender, reward-cycle: reward-cycle } partial-stacked)
+ (ok true))))
+```
+
+
+
+Arguments:
+
+* Pox Address: the BTC address to receive rewards.
+* Reward Cycle: a reward cycle in the future.
+* Reward Cycle Index: the index returned by `stack-aggregation-commit-indexed`.
+* Signer signature: a signature proving control of your signing key.
+* Signer public key: the public key of your signer.
+* Max Amount: used to validate the signer signature provided.
+* Auth Id: used to validate the signer signature provided.
+{% endstep %}
+{% endstepper %}
+
+{% hint style="warning" %}
+* Sequential Process: First call `delegate-stack-increase` to update the locked amount of a delegation. Then, commit the change:
+ * Use `stack-aggregation-commit-indexed` if this is the first commit in the given cycle.
+ * Use `stack-aggregation-increase` if you have already committed in the cycle you want to increase.
+
+Failing to commit (or properly increase after a commit) will result in the increased delegation not taking effect in upcoming stacking cycles.
+{% endhint %}
diff --git a/docs/operate/stacking-stx/operate-a-stacking-pool.md b/docs/operate/stacking-stx/operate-a-stacking-pool.md
new file mode 100644
index 0000000000..af5832a237
--- /dev/null
+++ b/docs/operate/stacking-stx/operate-a-stacking-pool.md
@@ -0,0 +1,589 @@
+# Operate a Stacking Pool
+
+This doc assumes you are familiar with stacking at a conceptual level. If not, you may want to read the [Stacking](https://app.gitbook.com/s/H74xqoobupBWwBsVMJhK/block-production/stacking) concept guide.
+
+The guide below applies to those who want to operate a pool, meaning they want to have stackers delegate STX tokens to them. If you choose to operate a pool you will either need to run your own signer or collaborate with one.
+
+### Pool Operator Stacking Flow
+
+For pool operators, the flow is a bit different than solo stacking. Remember that as a pool operator, other stackers are delegating their STX to you to stack on behalf of them. This additional role adds a couple of extra steps to your stacking flow if operating as a pool operator.
+
+Similar to the changes to solo Stacking, the big difference for delegation flows is the inclusion of signer keys and signatures. Because pool operators need to make transactions to “finalize” a delegation, these new arguments add new complexities to the stacking flow.
+
+#### Delegator initiates delegation
+
+{% hint style="info" %}
+This step is not required to apply to pool operators/signers. It is included here to illustrate the end-to-end flow, but if you are operating as a pool operator/signer you will not have to perform this step. Instead, users delegate their STX to you as the pool operator.
+{% endhint %}
+
+The first step, where the delegator sets up their delegation to a pool operator, is to call `delegate-stx`. This function does not directly delegate the STX, but rather allows the pool operator to issue the stacking lock on behalf of the user calling this function. You can think of calling this function as the delegator giving permission to the pool operator to stack on their behalf.
+
+
+
+Function source code
+
+```clojure
+;; Delegate to `delegate-to` the ability to stack from a given address.
+;; This method _does not_ lock the funds, rather, it allows the delegate
+;; to issue the stacking lock.
+;; The caller specifies:
+;; * amount-ustx: the total amount of ustx the delegate may be allowed to lock
+;; * until-burn-ht: an optional burn height at which this delegation expires
+;; * pox-addr: an optional address to which any rewards *must* be sent
+(define-public (delegate-stx (amount-ustx uint)
+ (delegate-to principal)
+ (until-burn-ht (optional uint))
+ (pox-addr (optional { version: (buff 1), hashbytes: (buff 32) })))
+
+ (begin
+ ;; must be called directly by the tx-sender or by an allowed contract-caller
+ (asserts! (check-caller-allowed)
+ (err ERR_STACKING_PERMISSION_DENIED))
+
+ ;; delegate-stx no longer requires the delegator to not currently
+ ;; be stacking.
+ ;; delegate-stack-* functions assert that
+ ;; 1. users can't swim in two pools at the same time.
+ ;; 2. users can't switch pools without cool down cycle.
+ ;; Other pool admins can't increase or extend.
+ ;; 3. users can't join a pool while already directly stacking.
+
+ ;; pox-addr, if given, must be valid
+ (match pox-addr
+ address
+ (asserts! (check-pox-addr-version (get version address))
+ (err ERR_STACKING_INVALID_POX_ADDRESS))
+ true)
+
+ ;; tx-sender must not be delegating
+ (asserts! (is-none (get-check-delegation tx-sender))
+ (err ERR_STACKING_ALREADY_DELEGATED))
+
+ ;; add delegation record
+ (map-set delegation-state
+ { stacker: tx-sender }
+ { amount-ustx: amount-ustx,
+ delegated-to: delegate-to,
+ until-burn-ht: until-burn-ht,
+ pox-addr: pox-addr })
+
+ (ok true)))
+```
+
+
+
+The arguments here are unchanged from previous versions of PoX:
+
+* Amount: Denoted in uSTX (1 STX = 1,000,000 uSTX)
+* Delegate to: the STX address of the pool operator they're delegating to. Note that this is different from the “signer key” used. Instead, this is the STX address that is used to make PoX transactions.
+* Until burn height: an optional argument representing the BTC block height when the delegation expires. If none is used, the delegation permission expires only when explicitly revoked.
+* Pox Address: an optional BTC address that, if specified, the signer must use to accept this delegation
+
+#### Pool operator “activates” the delegation
+
+Just as in the older PoX contract, after a delegator calls the `delegate-stx` function, the pool operator calls `delegate-stack-stx` to commit the delegator’s STX.
+
+
+
+Function source code
+
+```clojure
+;; As a delegate, stack the given principal's STX using partial-stacked-by-cycle
+;; Once the delegate has stacked > minimum, the delegate should call stack-aggregation-commit
+(define-public (delegate-stack-stx (stacker principal)
+ (amount-ustx uint)
+ (pox-addr { version: (buff 1), hashbytes: (buff 32) })
+ (start-burn-ht uint)
+ (lock-period uint))
+ ;; this stacker's first reward cycle is the _next_ reward cycle
+ (let ((first-reward-cycle (+ u1 (current-pox-reward-cycle)))
+ (specified-reward-cycle (+ u1 (burn-height-to-reward-cycle start-burn-ht)))
+ (unlock-burn-height (reward-cycle-to-burn-height (+ (current-pox-reward-cycle) u1 lock-period))))
+ ;; the start-burn-ht must result in the next reward cycle, do not allow stackers
+ ;; to "post-date" their `stack-stx` transaction
+ (asserts! (is-eq first-reward-cycle specified-reward-cycle)
+ (err ERR_INVALID_START_BURN_HEIGHT))
+
+ ;; must be called directly by the tx-sender or by an allowed contract-caller
+ (asserts! (check-caller-allowed)
+ (err ERR_STACKING_PERMISSION_DENIED))
+
+ ;; stacker must have delegated to the caller
+ (let ((delegation-info (unwrap! (get-check-delegation stacker) (err ERR_STACKING_PERMISSION_DENIED))))
+ ;; must have delegated to tx-sender
+ (asserts! (is-eq (get delegated-to delegation-info) tx-sender)
+ (err ERR_STACKING_PERMISSION_DENIED))
+ ;; must have delegated enough stx
+ (asserts! (>= (get amount-ustx delegation-info) amount-ustx)
+ (err ERR_DELEGATION_TOO_MUCH_LOCKED))
+ ;; if pox-addr is set, must be equal to pox-addr
+ (asserts! (match (get pox-addr delegation-info)
+ specified-pox-addr (is-eq pox-addr specified-pox-addr)
+ true)
+ (err ERR_DELEGATION_POX_ADDR_REQUIRED))
+ ;; delegation must not expire before lock period
+ (asserts! (match (get until-burn-ht delegation-info)
+ until-burn-ht (>= until-burn-ht
+ unlock-burn-height)
+ true)
+ (err ERR_DELEGATION_EXPIRES_DURING_LOCK))
+ )
+
+ ;; stacker principal must not be stacking
+ (asserts! (is-none (get-stacker-info stacker))
+ (err ERR_STACKING_ALREADY_STACKED))
+
+ ;; the Stacker must have sufficient unlocked funds
+ (asserts! (>= (stx-get-balance stacker) amount-ustx)
+ (err ERR_STACKING_INSUFFICIENT_FUNDS))
+
+ ;; ensure that stacking can be performed
+ (try! (minimal-can-stack-stx pox-addr amount-ustx first-reward-cycle lock-period))
+
+ ;; register the PoX address with the amount stacked via partial stacking
+ ;; before it can be included in the reward set, this must be committed!
+ (add-pox-partial-stacked pox-addr first-reward-cycle lock-period amount-ustx)
+
+ ;; add stacker record
+ (map-set stacking-state
+ { stacker: stacker }
+ { pox-addr: pox-addr,
+ first-reward-cycle: first-reward-cycle,
+ reward-set-indexes: (list),
+ lock-period: lock-period,
+ delegated-to: (some tx-sender) })
+
+ ;; return the lock-up information, so the node can actually carry out the lock.
+ (ok { stacker: stacker,
+ lock-amount: amount-ustx,
+ unlock-burn-height: unlock-burn-height })))
+```
+
+
+
+The arguments are:
+
+* Stacker: the STX address of the delegator
+* Amount: denoted in uSTX (1 STX = 1,000,000 uSTX)
+* Pox Address: The BTC address of the pool operator where they will receive the BTC rewards. If the delegator has set his own BTC address in the `delegate-stx` call, this address will have to be the same one, otherwise the contract call will fail.
+* Start burn height: The BTC block height in which delegation can begin. This field is used to ensure that an old transaction intended for an earlier cycle will fail, and also prevents callers from "post-dating" the call to a future cycle. The best option here is to add 1 or 2 to the current BTC block height when you initiate this transaction. Note that the delegation will not actively be stacked at this block height, but whatever reward cycle is passed in the aggregation commit function (explained below).
+* Lock period: number of cycles to lock for. If the delegator provided the until burn height argument, then the end of these cycles cannot be past the expiration provided. The maximum lock period that a pool operator can provide in this function call is 12.
+
+This step also allows the pool operator to proactively choose which Stackers they’ll accept delegation from. For “closed” pools, the pool operator will only call this function for approved Stackers. It is up to each pool operator who runs a closed pool to implement this process.
+
+This step can be repeated for multiple Stackers before going to the next step.
+
+{% hint style="info" %}
+If you look at the function source code, you'll see that the `delegate-stack-stx` function sets the stacker's first reward cycle to be the _next_ reward cycle.
+
+When generating your signature and your `stack-aggregation-commit-indexed` transaction, you'll want to make sure that the reward cycles match.
+
+So if you are in cycle 557 when you call the `delegate-stack-stx` function, you'll want to pass in cycle 558 or higher when you generate your signature and your `stack-aggregation-commit-indexed` transaction.
+
+With `stack-aggregation-commit-indexed`, the `reward-cycle` arg is saying "I'm committing these stacks to be stacked in cycle N". But the `delegate-stack-stx` transaction gets you setup for next cycles, aka 558 and higher.
+
+Also make sure that, when you generate your signature, you use 558 or higher as the reward cycle. In solo stacking methods, you use the current reward cycle in the signature, but not for `stack-aggregation-commit-indexed`. This is because with `stack-aggregation-commit-indexed` you can commit stacks for future cycles, not just the N+1 cycle.
+{% endhint %}
+
+#### Pool operator “commits” delegated STX
+
+The next step is for the pool operator to call `stack-aggregation-commit-indexed`.
+
+{% hint style="info" %}
+In the contract source code, you'll notice a similarly named function called `stack-aggregation-commit`. This is a legacy function that makes it difficult to increase the stacking amount, as it does not return the reward index of the stacking slot, which is required in order to call the `stack-aggregation-increase` function. We recommend using `stack-aggregation-commit-indexed`.
+{% endhint %}
+
+
+
+Function source code
+
+Note that the `stack-aggregation-commit-indexed` function wraps the `inner-stack-aggregation-commit` function. The wrapped inner function is included here.
+
+Check out the [deployed contract](https://explorer.hiro.so/txid/SP000000000000000000002Q6VF78.pox-4?chain=mainnet) to see the flow of contract calls.
+
+```clojure
+;; Commit partially stacked STX and allocate a new PoX reward address slot.
+;; This allows a stacker/delegate to lock fewer STX than the minimal threshold in multiple transactions,
+;; so long as: 1. The pox-addr is the same.
+;; 2. This "commit" transaction is called _before_ the PoX anchor block.
+;; This ensures that each entry in the reward set returned to the stacks-node is greater than the threshold,
+;; but does not require it be all locked up within a single transaction
+;;
+;; Returns (ok uint) on success, where the given uint is the reward address's index in the list of reward
+;; addresses allocated in this reward cycle. This index can then be passed to `stack-aggregation-increase`
+;; to later increment the STX this PoX address represents, in amounts less than the stacking minimum.
+;;
+;; *New in Stacks 2.1.*
+(define-private (inner-stack-aggregation-commit (pox-addr { version: (buff 1), hashbytes: (buff 32) })
+ (reward-cycle uint)
+ (signer-sig (optional (buff 65)))
+ (signer-key (buff 33))
+ (max-amount uint)
+ (auth-id uint))
+ (let ((partial-stacked
+ ;; fetch the partial commitments
+ (unwrap! (map-get? partial-stacked-by-cycle { pox-addr: pox-addr, sender: tx-sender, reward-cycle: reward-cycle })
+ (err ERR_STACKING_NO_SUCH_PRINCIPAL))))
+ ;; must be called directly by the tx-sender or by an allowed contract-caller
+ (asserts! (check-caller-allowed)
+ (err ERR_STACKING_PERMISSION_DENIED))
+ (let ((amount-ustx (get stacked-amount partial-stacked)))
+ (try! (consume-signer-key-authorization pox-addr reward-cycle "agg-commit" u1 signer-sig signer-key amount-ustx max-amount auth-id))
+ (try! (can-stack-stx pox-addr amount-ustx reward-cycle u1))
+ ;; Add the pox addr to the reward cycle, and extract the index of the PoX address
+ ;; so the delegator can later use it to call stack-aggregation-increase.
+ (let ((add-pox-addr-info
+ (add-pox-addr-to-ith-reward-cycle
+ u0
+ { pox-addr: pox-addr,
+ first-reward-cycle: reward-cycle,
+ num-cycles: u1,
+ reward-set-indexes: (list),
+ stacker: none,
+ signer: signer-key,
+ amount-ustx: amount-ustx,
+ i: u0 }))
+ (pox-addr-index (unwrap-panic
+ (element-at (get reward-set-indexes add-pox-addr-info) u0))))
+
+ ;; don't update the stacking-state map,
+ ;; because it _already has_ this stacker's state
+ ;; don't lock the STX, because the STX is already locked
+ ;;
+ ;; clear the partial-stacked state, and log it
+ (map-delete partial-stacked-by-cycle { pox-addr: pox-addr, sender: tx-sender, reward-cycle: reward-cycle })
+ (map-set logged-partial-stacked-by-cycle { pox-addr: pox-addr, sender: tx-sender, reward-cycle: reward-cycle } partial-stacked)
+ (ok pox-addr-index)))))
+```
+
+
+
+At this point, the STX are committed to the pool operator, and the pool operator has some “aggregate balance” of committed STX. The pool operator is not actually eligible for reward slots and signer initialization until this step is finished.
+
+The pool operator cannot call this function until the total number of STX committed is larger than the minimum threshold required to Stack. This minimum stacking threshold is a function of the total number of STX stacked divided by the available number of reward slots.
+
+{% hint style="info" %}
+This number varies and can be found by visiting the pox endpoint of Hiro's API at [https://api.hiro.so/v2/pox](https://api.hiro.so/v2/pox) and looking at the `min_threshold_ustx` field. (1 STX = 1,000,000 uSTX).
+{% endhint %}
+
+Once the threshold is reached, the pool operator calls `stack-aggregation-commit-indexed`. This is the point where you as the pool operator must provide your signer key and signer key signature. The arguments are:
+
+* Pox Address: the BTC address to receive rewards
+* Reward-cycle: a reward cycle in the future (see the note above on passing the correct reward cycle)
+* Signer public key: the public key of your signer (remember that this may be different than the address you are using to operate the pool, but this step is how you associate the two together)
+* Signer signature: A signature proving control of your signing key (details on how to do this are below)
+* Max Amount: This parameter is used to validate the signer signature provided. It represents the maximum number of uSTX (1 STX = 1,000,000 uSTX) that can be stacked in this transaction.
+* Auth Id: This parameter is used to validate the signer signature provided. It is a random integer that prevents the re-use of this particular signer signature.
+
+{% hint style="info" %}
+In the Definitions and Roles section in the previous document, we described how the pool operator and signer may be the same entity, but not necessarily have the same address.
+
+Signers who are also pool operators and wish to have STX delegated to them should have a separate keychain associated with their pool operator account in order to make Stacking transactions such as `delegate-stack-stx` and `stack-aggregation-commit-indexed`.
+
+So, as a signing entity operating a pool, you should have two accounts:
+
+* Your pool operator account, which you will use to conduct all of the stacking operations we have covered here.
+* Your signer account, which is what you used to set up your signer. This signer public key is what you will pass in to the above aggregation commit function, and is also the key you will use when generating your signer signature.
+
+If you are operating as a signer and a pool operator, you should have a separate key because you might need to rotate your signer key when necessary.
+
+The PoX contract is designed to support rotating the signer key without needing your Stackers to un-stack and re-stack later. You cannot rotate a pool operator key without needing to wait for all delegated Stackers to un-stack and finally re-stack to the new pool operator address.
+
+Because of this limitation of being unable to rotate pool operator addresses, it’s highly recommended to have a separate pool operator key. The benefit of a separate pool operator key is that it can easily be used in existing wallets, including hardware wallets.
+{% endhint %}
+
+Once this succeeds, the signer is eligible for reward slots. The number of reward slots depends on the amount of STX committed to this signer. Even if the signer commits more than the “global minimum”, the minimum amount to receive a slot depends on the amount of STX locked for each cycle.
+
+To act as a signer, each step up to this point must be taken before the prepare phase of the next cycle begins. It is crucial that the signer software is running.
+
+#### Pool operator increases amount committed
+
+Even after the signer commits to a certain amount of STX in the previous step, the signer can increase this amount once more delegations are received. The initial steps must be taken for each Stacker (`delegate-stx` and then `delegate-stack-stx`), and then `stack-aggregation-increase` can be called with the index returned from the first `stack-aggregation-commit-indexed` call and a new signature.
+
+
+
+Function source code
+
+```
+;; Commit partially stacked STX to a PoX address which has already received some STX (more than the Stacking min).
+;; This allows a delegator to lock up marginally more STX from new delegates, even if they collectively do not
+;; exceed the Stacking minimum, so long as the target PoX address already represents at least as many STX as the
+;; Stacking minimum.
+;;
+;; The `reward-cycle-index` is emitted as a contract event from `stack-aggregation-commit` when the initial STX are
+;; locked up by this delegator. It must be passed here to add more STX behind this PoX address. If the delegator
+;; called `stack-aggregation-commit` multiple times for the same PoX address, then any such `reward-cycle-index` will
+;; work here.
+;;
+;; *New in Stacks 2.1*
+;;
+(define-public (stack-aggregation-increase (pox-addr { version: (buff 1), hashbytes: (buff 32) })
+ (reward-cycle uint)
+ (reward-cycle-index uint))
+ (let ((partial-stacked
+ ;; fetch the partial commitments
+ (unwrap! (map-get? partial-stacked-by-cycle { pox-addr: pox-addr, sender: tx-sender, reward-cycle: reward-cycle })
+ (err ERR_STACKING_NO_SUCH_PRINCIPAL))))
+
+ ;; must be called directly by the tx-sender or by an allowed contract-caller
+ (asserts! (check-caller-allowed)
+ (err ERR_STACKING_PERMISSION_DENIED))
+
+ ;; reward-cycle must be in the future
+ (asserts! (> reward-cycle (current-pox-reward-cycle))
+ (err ERR_STACKING_INVALID_LOCK_PERIOD))
+
+ (let ((amount-ustx (get stacked-amount partial-stacked))
+ ;; reward-cycle must point to an existing record in reward-cycle-total-stacked
+ ;; infallible; getting something from partial-stacked-by-cycle succeeded so this must succeed
+ (existing-total (unwrap-panic (map-get? reward-cycle-total-stacked { reward-cycle: reward-cycle })))
+ ;; reward-cycle and reward-cycle-index must point to an existing record in reward-cycle-pox-address-list
+ (existing-entry (unwrap! (map-get? reward-cycle-pox-address-list { reward-cycle: reward-cycle, index: reward-cycle-index })
+ (err ERR_DELEGATION_NO_REWARD_SLOT)))
+ (increased-ustx (+ (get total-ustx existing-entry) amount-ustx))
+ (total-ustx (+ (get total-ustx existing-total) amount-ustx)))
+
+ ;; must be stackable
+ (try! (minimal-can-stack-stx pox-addr total-ustx reward-cycle u1))
+
+ ;; new total must exceed the stacking minimum
+ (asserts! (<= (get-stacking-minimum) total-ustx)
+ (err ERR_STACKING_THRESHOLD_NOT_MET))
+
+ ;; there must *not* be a stacker entry (since this is a delegator)
+ (asserts! (is-none (get stacker existing-entry))
+ (err ERR_DELEGATION_WRONG_REWARD_SLOT))
+
+ ;; the given PoX address must match the one on record
+ (asserts! (is-eq pox-addr (get pox-addr existing-entry))
+ (err ERR_DELEGATION_WRONG_REWARD_SLOT))
+
+ ;; update the pox-address list -- bump the total-ustx
+ (map-set reward-cycle-pox-address-list
+ { reward-cycle: reward-cycle, index: reward-cycle-index }
+ { pox-addr: pox-addr,
+ total-ustx: increased-ustx,
+ stacker: none,
+ ;; TODO: this must be authorized with a signature, or tx-sender allowance!
+ signer: (get signer existing-entry) })
+
+ ;; update the total ustx in this cycle
+ (map-set reward-cycle-total-stacked
+ { reward-cycle: reward-cycle }
+ { total-ustx: total-ustx })
+
+ ;; don't update the stacking-state map,
+ ;; because it _already has_ this stacker's state
+ ;; don't lock the STX, because the STX is already locked
+ ;;
+ ;; clear the partial-stacked state, and log it
+ (map-delete partial-stacked-by-cycle { pox-addr: pox-addr, sender: tx-sender, reward-cycle: reward-cycle })
+ (map-set logged-partial-stacked-by-cycle { pox-addr: pox-addr, sender: tx-sender, reward-cycle: reward-cycle } partial-stacked)
+ (ok true))))
+```
+
+
+
+***
+
+## Step by Step Stacking Guide
+
+Now that you are familiar with the overall stacking flow and the different roles played, let's dive into the step-by-step guide for actually conducting the stacking process as a pool operator.
+
+{% hint style="info" %}
+There are several ways you can go about stacking. This guide will cover using [Leather Earn](https://earn.leather.io/), which is a stacking web application and the simplest option.
+
+Additionally, you can choose to call the stacking functions directly from the [deployed contract](https://explorer.hiro.so/txid/SP000000000000000000002Q6VF78.pox-4?chain=mainnet) in the explorer.
+
+The fields and process will be the same, but the UI will differ.
+
+Finally, you can stack using JS and the [@stacks/stacking](https://github.com/stx-labs/stacks.js/tree/main/packages/stacking) package if you prefer. Again, the functions and parameters will be the same, you will just be writing your JS code directly instead of using a UI.
+
+If you are interested in using this method, you'll want to follow the [stacking guide](https://docs.hiro.so/stacks.js/guides/how-to-integrate-stacking) created by Hiro, and be sure to integrate the new parameters described in [Hiro's Nakamoto update doc](https://docs.hiro.so/nakamoto/stacks-js).
+{% endhint %}
+
+### Step 1: Run or work with a signer
+
+This is a necessary prerequisite to stacking as a pool operator. You will either need to run your own signer or work with one and have them conduct step 2 on your behalf and give you their signer signature.
+
+Running a signer involves setting up a hosted production environment that includes both a Stacks Node and the Stacks Signer. For more information, refer to the [running a signer doc](../run-a-signer/signer-quickstart.md).
+
+Once the signer software is running, you'll to keep track of the `stacks_private_key` that you used when configuring your signer software. This will be used in subsequent Stacking transactions.
+
+{% hint style="info" %}
+In the note above about pool operator vs signer keys, this corresponds to your signer key, not your pool operator wallet
+{% endhint %}
+
+### Step 2: Generate a signer key signature
+
+#### Overview of signer keys and signatures
+
+The main difference with Stacking in Nakamoto is that the Signer needs to include new parameters in their Stacking transactions. These are Clarity transactions that pool operators will call when interacting with the `pox-4.clar` contract. Interacting with that contract is how you as a pool operator actually stack the delegated STX tokens.
+
+{% hint style="info" %}
+The current pox-4 contract address can be found by visiting the following endpoint of the Hiro API: [https://api.hiro.so/v2/pox](https://api.hiro.so/v2/pox).
+
+You can then visit the [Stacks Explorer](https://explorer.hiro.so/) to view the contract and pass in the contract id.
+
+You may want to review this contract to familiarize yourself with it.
+{% endhint %}
+
+Here is an overview of the new fields you will need to pass in some of your stacking transactions:
+
+1. `signer-key`: the public key that corresponds to the `stacks_private_key` your signer is using.
+2. `signer-signature`: a signature that demonstrates that you actually control your `signer-key`. Because signer keys need to be unique, this is also a safety check to ensure that other Stackers can’t use someone else’s signer key.
+3. `max-amount`: The maximum amount of uSTX (1 STX = 1,000,000 uSTX) that can be locked in the transaction that uses this signature. For example, if calling `stack-aggregation-increase`, then this parameter dictates the maximum amount of uSTX that can be used to add more locked STX to the already committed position.
+4. `auth-id`: a random integer that prevents re-use of a particular signature, similar to how nonces are used with transactions.
+
+Signer signatures are signatures created using a particular signer key. They demonstrate that the controller of that signer key is allowing a Stacker to use their signer's public key. The signer signature’s message hash is created using the following data:
+
+* `method`: a string that indicates the Stacking method that is allowed to utilize this signature. The valid options are `stack-stx`, `stack-extend`, `stack-increase`, `agg-commit` (for `stack-aggregation-commit-indexed`) and `agg-increase` (for `stack-aggregation-increase`).
+* `max-amount`: described above.
+* `auth-id`: described above.
+* `period`: a value between 1 and 12, which indicates how long the Stacker is allowed to lock their STX for in this particular Stacking transaction. For `agg-commit`, this must be equal to 1.
+* `reward-cycle`: This represents the reward cycle in which the Stacking transaction can be confirmed (for `stack-aggregation-commit-indexed`, this has to be set to 1).
+* `pox-address`: The Bitcoin address that is allowed to be used for receiving rewards. This corresponds to the Bitcoin address associated with your signer
+* `config`: This represents the signer configuration file path where the `stacks_private_key` is located, and it is used for signing the generated signature.
+
+Now that we have an overview of role and contents of signatures, let's see how to actually generate them. You have several options available.
+
+Generating your signature with Degen Lab's stacks.tools
+
+* Degen Lab has a signature generation tool that will generate a signature using their signer. This is the quickest and simplest option. To generate a signature using this method, all you need to do is visit their [signature tool](https://signature.stacking.tools/) and pass in the relevant information as covered on the page.
+
+Generating your signature with stacks.js
+
+* The [@stacks/stacking](https://www.npmjs.com/package/@stacks/stacking) NPM package provides interfaces to generate and use signer signatures.
+* There is a function called `signPoxSignature` that will allow you to generate this signature and pass it in to the stacking function.
+* More information and code samples can be found on [Hiro's Nakamoto docs](https://docs.hiro.so/nakamoto/stacks-js).
+
+Generating your signature using the stacks-signer CLI
+
+* If you already have your signer configured and set up, you can use the `stacks-signer` CLI to generate this signature. You can either SSH into your running signer or use the `stacks-signer` CLI locally. If using the CLI locally, you will need to ensure you have a matching configuration file located on your filesystem. Having a matching configuration file is important to ensure that the signer public key you make in Stacking transactions is the same as in your hosted signer.
+
+The CLI command is:
+
+```
+```
+
+These arguments match those described in section [Overview of signer keys and signatures](solo-stack.md#overview-of-signer-keys-and-signatures), with the addition of:
+
+* `--json`, to optionally output the resulting signature in JSON.
+
+You can use the following command to generate a random `32` bit integer as `auth-id`:
+
+```
+```
+
+Once the `generate-stacking-signature` command is run, the CLI will output a JSON:
+
+```json
+{"authId":"12345","maxAmount":"1234","method":"agg-commit","period":1,"poxAddress":"bc1...","rewardCycle":100,"signerKey":"aaaaaaaa","signerSignature":"bbbbbbbbbbb"}
+```
+
+You will use the JSON when calling Stacking transactions from your pool operator address as outlined above. Remember that this may be different than your signer address.
+
+Generating your signature with Leather Earn
+
+* Leather Earn is a web application that provides an easy-to-use interface for stacking and generating signatures. We'll cover using Leather Earn for stacking at the end of this document, here we will cover how to use it to generate a signature.
+
+{% hint style="info" %}
+At the time of writing, this has only been tested using the [Leather](https://leather.io/) wallet.
+{% endhint %}
+
+You can visit [earn.leather.io](https://earn.leather.io/) to generate a signer key signature. Make sure you’re connected to the correct network.\
+To generate a signer key signature, it’s important that you’ve logged in Leather with the same secret key that was used to generate your signer key, not the account that will serve as your pool operator address. Once you’ve setup that account on Leather, you can log in to Leather Earn.\
+Click the link “Signer key signature” at the bottom of the page. This will open the “generate a signer key signature” page.
+
+The fields are:
+
+* Reward cycle:
+ * For all solo stacking transactions, this must equal the current reward cycle, not the cycle in which they will start stacking. The field defaults to the current reward cycle.
+ * For stack-aggregation-commit-indexed, this field must equal the cycle used in that function’s “reward cycle” argument. Typically, that equates to current\_cycle + 1.
+* Bitcoin address: the PoX reward address that can be used
+* Topic: the stacking function that will use this signature
+* Max amount: max amount of STX that can be used. Defaults to “max possible amount”
+* Auth ID: defaults to random int
+* Duration: must match the number of cycles used in the stacking transaction. For `stack-aggregation-commit-indexed`, use “1”.
+
+{% hint style="warning" %}
+Each of these fields must be exactly matched in order for the Stacking transaction to work. Future updates to Leather Earn will verify the signature before the transaction is made.
+{% endhint %}
+
+Click the “generate signature” button to popup a Leather page where you can generate the signature. Once you submit that popup, Leather Earn will have the signer key and signature you generated.
+
+After you sign that message, you'll see the information you can use in your Stacking transactions, including the signer public key and signature.
+
+You can click the “copy” icon next to “signer details to share with stackers”. This will copy a JSON string, which can be directly pasted into the Leather Earn page where you make your Stacking transaction. Alternatively, this information can be entered manually.
+
+We'll cover the Leather Earn pages for actually making those transactions in the next section of this document.
+
+#### Using a hardware or software wallet to generate signatures
+
+When the signer is configured with a `stacks_private_key`, the signer may want to be able to use that key in a wallet to make stacking signatures.
+
+If the signer uses a tool like [@stacks/cli](https://docs.hiro.so/get-started/command-line-interface) to generate the key, the CLI also outputs a mnemonic (aka “seed phrase”) that can be imported into a wallet. Because the Stacks CLI uses the standard derivation path for generating Stacks keys, any Stacks wallet will default to having that same private key when the wallet is imported from a derivation path. Similarly, if a hardware wallet is setup with that mnemonic, then the Signer can use a wallet like Leather to make stacking signatures.
+
+Use the following stepper for the recommended workflow for setting up a wallet to generate signatures:
+
+{% stepper %}
+{% step %}
+### Generate the keypair and configure signer
+
+1. Use @stacks/cli to generate the keychain and private key.
+ * Typically, when using a hardware wallet, it’s better to generate the mnemonic on the hardware wallet. For this use case, however, the signer software needs the private key, and hardware wallets (by design) don’t allow exporting private keys.
+2. Take the `privateKey` from the CLI output and add it to your signer’s configuration.
+3. Take the mnemonic (24 words) and either:
+ * Setup a new hardware wallet with this mnemonic
+ * Store it somewhere securely, like a password manager. When the signer needs to generate signatures for Stacking transactions, they can import it into either Leather or XVerse.
+{% endstep %}
+
+{% step %}
+### When you need to generate signatures
+
+1. Setup your wallet with your signer key’s private key. Either:
+ * Setup your Leather wallet with a Ledger hardware wallet
+ * Import your mnemonic into Leather, XVerse, or another Stacks wallet
+2. Open an app that has stacking signature functionality built-in
+3. Connect your wallet to the app (aka sign in)
+4. In the app, enter your PoX address and “submit”
+ * The app will popup a window in your wallet that prompts you to sign the information
+ * The app will show clear information about what you’re signing
+5. Create the signature
+ * If using a Ledger, confirm on your device
+6. The app will display two results:
+ * Your signer key, which is the public key associated with your signer’s key
+ * Your signer signature
+7. Finally, make a Stacking transaction using the signer key and signer signature.
+{% endstep %}
+{% endstepper %}
+
+Now that you have your signer signature generated, it's time to start stacking. This process will vary depending on your chosen method. We've included instructions for pool stacking using [Leather Earn](https://earn.leather.io/) below.
+
+### Step 3: Stack as a pool operator
+
+The first step with delegated stacking involves a stacker delegating their Stacks to a specific pool operator. Stackers can do this by visiting the “Stack in a pool” page on Leather Earn.
+
+As the pool operator, you must provide a STX address (a “pool admin address”) that will manage delegations. As discussed in previous sections, this is a separate address from the signer’s private key, and this can be any address. This address is what will be used when making transactions to confirm and aggregate delegated STX.
+
+Pool operators can log in to Leather Earn and visit [https://earn.leather.io/pool-admin](https://earn.leather.io/pool-admin) to make pool management transactions.
+
+#### delegate-stack-stx
+
+Once a user has delegated to a pool operator, the pool operator must call `delegate-stack-stx` for each individual stacker.
+
+#### stack-aggregation-commit
+
+Once a pool has enough delegated STX to become a signer, the pool admin needs to visit the `Stack Aggregation Commit` page on Leather Earn. The pool operator enters the following information:
+
+* Reward cycle: the reward cycle where the operator is “committing” delegated STX. This must be done for every individual reward cycle where the pool will be acting as a signer.
+* BTC address
+* New fields:
+ * Signer public key
+ * Signer key signature (generated in a previous step using the signer key)
+ * Auth ID
+ * Max amount
+
+Once this transaction has been confirmed, the pool operator is eligible to be a signer for an upcoming reward cycle.
+
+For more on the relationship between automated signing and manual stacking transactions, be sure to check out the main [Stack STX](file:///) doc.
diff --git a/docs/operate/stacking-stx/solo-stack.md b/docs/operate/stacking-stx/solo-stack.md
new file mode 100644
index 0000000000..9e7ec69cf9
--- /dev/null
+++ b/docs/operate/stacking-stx/solo-stack.md
@@ -0,0 +1,614 @@
+# Solo Stack
+
+This doc assumes you are familiar with stacking at a conceptual level. If not, you may want to read the [Stacking](https://app.gitbook.com/s/H74xqoobupBWwBsVMJhK/block-production/stacking) concept guide.
+
+The guide below applies to those who want to solo stack, meaning they meet the minimum stacking requirement and need to either run a signer or collaborate with a signer.
+
+{% hint style="info" %}
+There is a dapp created by Degen Lab for [solo stacking](https://solo.stacking.tools/) without needing a signer, as Degen Lab operates a signer. This is likely the easiest option for solo stacking. We'll cover this option below.
+{% endhint %}
+
+If you prefer to participate in a pool by delegating your STX, you do not need to operate a signer either. If you fall into this category, check out the [Stack with a Pool](stack-with-a-pool.md) guide.
+
+### Solo Stacker Flow
+
+{% hint style="info" %}
+Note that in order to solo stack, you need to have the minimum number of STX tokens. This number can be found by visiting the pox endpoint of Hiro's API at [https://api.mainnet.hiro.so/v2/pox](https://api.mainnet.hiro.so/v2/pox) and looking at the `min_threshold_ustx` field. (1 STX = 1,000,000 uSTX)
+{% endhint %}
+
+#### Call the function `stack-stx`
+
+
+
+Function source code
+
+```clojure
+;; Lock up some uSTX for stacking! Note that the given amount here is in micro-STX (uSTX).
+;; The STX will be locked for the given number of reward cycles (lock-period).
+;; This is the self-service interface. tx-sender will be the Stacker.
+;;
+;; * The given stacker cannot currently be stacking.
+;; * You will need the minimum uSTX threshold. This will be determined by (get-stacking-minimum)
+;; at the time this method is called.
+;; * You may need to increase the amount of uSTX locked up later, since the minimum uSTX threshold
+;; may increase between reward cycles.
+;; * You need to provide a signer key to be used in the signer DKG process.
+;; * The Stacker will receive rewards in the reward cycle following `start-burn-ht`.
+;; Importantly, `start-burn-ht` may not be further into the future than the next reward cycle,
+;; and in most cases should be set to the current burn block height.
+;;
+;; To ensure that the Stacker is authorized to use the provided `signer-key`, the stacker
+;; must provide either a signature have an authorization already saved. Refer to
+;; `verify-signer-key-sig` for more information.
+;;
+;; The tokens will unlock and be returned to the Stacker (tx-sender) automatically.
+(define-public (stack-stx (amount-ustx uint)
+ (pox-addr (tuple (version (buff 1)) (hashbytes (buff 32))))
+ (start-burn-ht uint)
+ (lock-period uint)
+ (signer-sig (optional (buff 65)))
+ (signer-key (buff 33))
+ (max-amount uint)
+ (auth-id uint))
+ ;; this stacker's first reward cycle is the _next_ reward cycle
+ (let ((first-reward-cycle (+ u1 (current-pox-reward-cycle)))
+ (specified-reward-cycle (+ u1 (burn-height-to-reward-cycle start-burn-ht))))
+ ;; the start-burn-ht must result in the next reward cycle, do not allow stackers
+ ;; to "post-date" their `stack-stx` transaction
+ (asserts! (is-eq first-reward-cycle specified-reward-cycle)
+ (err ERR_INVALID_START_BURN_HEIGHT))
+
+ ;; must be called directly by the tx-sender or by an allowed contract-caller
+ (asserts! (check-caller-allowed)
+ (err ERR_STACKING_PERMISSION_DENIED))
+
+ ;; tx-sender principal must not be stacking
+ (asserts! (is-none (get-stacker-info tx-sender))
+ (err ERR_STACKING_ALREADY_STACKED))
+
+ ;; tx-sender must not be delegating
+ (asserts! (is-none (get-check-delegation tx-sender))
+ (err ERR_STACKING_ALREADY_DELEGATED))
+
+ ;; the Stacker must have sufficient unlocked funds
+ (asserts! (>= (stx-get-balance tx-sender) amount-ustx)
+ (err ERR_STACKING_INSUFFICIENT_FUNDS))
+
+ ;; Validate ownership of the given signer key
+ (try! (consume-signer-key-authorization pox-addr (- first-reward-cycle u1) "stack-stx" lock-period signer-sig signer-key amount-ustx max-amount auth-id))
+
+ ;; ensure that stacking can be performed
+ (try! (can-stack-stx pox-addr amount-ustx first-reward-cycle lock-period))
+
+ ;; register the PoX address with the amount stacked
+ (let ((reward-set-indexes (try! (add-pox-addr-to-reward-cycles pox-addr first-reward-cycle lock-period amount-ustx tx-sender signer-key))))
+ ;; add stacker record
+ (map-set stacking-state
+ { stacker: tx-sender }
+ { pox-addr: pox-addr,
+ reward-set-indexes: reward-set-indexes,
+ first-reward-cycle: first-reward-cycle,
+ lock-period: lock-period,
+ delegated-to: none })
+
+ ;; return the lock-up information, so the node can actually carry out the lock.
+ (ok { stacker: tx-sender, lock-amount: amount-ustx, signer-key: signer-key, unlock-burn-height: (reward-cycle-to-burn-height (+ first-reward-cycle lock-period)) }))))
+```
+
+
+
+The first thing solo stackers will need to do is call the `stack-stx` function.
+
+Just like in previous versions of PoX, Stackers call `stack-stx`, but with the new arguments added in Nakamoto. The arguments are:
+
+* Amount: Denoted in uSTX (1 STX = 1,000,000 uSTX)
+* PoX Address: the BTC wallet address where to receive Stacking rewards
+* Start burn height: the current BTC block height
+* Lock period: the number of cycles to lock for (between 1 and 12)
+* Signer key: the public key that your signer is using
+* Signer signature: the signature that proves control of this signer key
+* Max Amount: This parameter is used to validate the signer signature provided. It represents the maximum number of uSTX that can be stacked in this transaction.
+* Auth Id: This parameter is used to validate the signer signature provided. It is a random integer that prevents the re-use of this particular signer signature.
+
+Solo stackers have two choices when it comes to operating as a signer. They can choose to run a signer themselves or work with a signer on their behalf.
+
+#### Option 1: Act as a signer
+
+In the “prepare phase” before the next stacking cycle (last 100 blocks), the exact set of Stackers will be selected based on the amount of STX stacked. Just like in previous versions of PoX, each Stacker will have some number of reward slots based on the amount of STX locked.
+
+It is critical that solo stackers have their signer running during this period. The prepare phase is when distributed key generation (DKG) occurs, which is used when validating blocks by signers.
+
+In general, you don’t need to do anything actively during this period, other than monitoring your signer software to ensure it’s running properly.
+
+#### Option 2: Work with a signer
+
+If you do not want to operate a signer on your own, you can work with another signer. To do this, you will need to collaborate with them to get their signer key and signer signature (details in the following sections), which will have to be passed when calling the stacking functions.
+
+Rather than needing to find a signer to collaborate with, you can use the solo stacking dapp created by Degen Lab in order to use their signer to solo stack. They've created a UI that makes this process really simple.
+
+They also have a tool for you to generate a signer signature if you prefer to call the stacking functions yourself.
+
+#### Extending the stacking period
+
+Just like in the current version of PoX, you can extend your lock period while still Stacking. The function called is `stack-extend`.
+
+
+
+Function source code
+
+```clojure
+;; Extend an active Stacking lock.
+;; *New in Stacks 2.1*
+;; This method extends the `tx-sender`'s current lockup for an additional `extend-count`
+;; and associates `pox-addr` with the rewards, The `signer-key` will be the key
+;; used for signing. The `tx-sender` can thus decide to change the key when extending.
+;;
+;; Because no additional STX are locked in this function, the `amount` field used
+;; to verify the signer key authorization is zero. Refer to `verify-signer-key-sig` for more information.
+(define-public (stack-extend (extend-count uint)
+ (pox-addr { version: (buff 1), hashbytes: (buff 32) })
+ (signer-sig (optional (buff 65)))
+ (signer-key (buff 33))
+ (max-amount uint)
+ (auth-id uint))
+ (let ((stacker-info (stx-account tx-sender))
+ ;; to extend, there must already be an etry in the stacking-state
+ (stacker-state (unwrap! (get-stacker-info tx-sender) (err ERR_STACK_EXTEND_NOT_LOCKED)))
+ (amount-ustx (get locked stacker-info))
+ (unlock-height (get unlock-height stacker-info))
+ (cur-cycle (current-pox-reward-cycle))
+ ;; first-extend-cycle will be the cycle in which tx-sender *would have* unlocked
+ (first-extend-cycle (burn-height-to-reward-cycle unlock-height))
+ ;; new first cycle should be max(cur-cycle, stacker-state.first-reward-cycle)
+ (cur-first-reward-cycle (get first-reward-cycle stacker-state))
+ (first-reward-cycle (if (> cur-cycle cur-first-reward-cycle) cur-cycle cur-first-reward-cycle)))
+
+ ;; must be called with positive extend-count
+ (asserts! (>= extend-count u1)
+ (err ERR_STACKING_INVALID_LOCK_PERIOD))
+
+ ;; stacker must be directly stacking
+ (asserts! (> (len (get reward-set-indexes stacker-state)) u0)
+ (err ERR_STACKING_IS_DELEGATED))
+
+ ;; stacker must not be delegating
+ (asserts! (is-none (get delegated-to stacker-state))
+ (err ERR_STACKING_IS_DELEGATED))
+
+ ;; Verify signature from delegate that allows this sender for this cycle
+ (try! (consume-signer-key-authorization pox-addr cur-cycle "stack-extend" extend-count signer-sig signer-key u0 max-amount auth-id))
+
+ ;; TODO: add more assertions to sanity check the `stacker-info` values with
+ ;; the `stacker-state` values
+
+ (let ((last-extend-cycle (- (+ first-extend-cycle extend-count) u1))
+ (lock-period (+ u1 (- last-extend-cycle first-reward-cycle)))
+ (new-unlock-ht (reward-cycle-to-burn-height (+ u1 last-extend-cycle))))
+
+ ;; first cycle must be after the current cycle
+ (asserts! (> first-extend-cycle cur-cycle) (err ERR_STACKING_INVALID_LOCK_PERIOD))
+ ;; lock period must be positive
+ (asserts! (> lock-period u0) (err ERR_STACKING_INVALID_LOCK_PERIOD))
+
+ ;; must be called directly by the tx-sender or by an allowed contract-caller
+ (asserts! (check-caller-allowed)
+ (err ERR_STACKING_PERMISSION_DENIED))
+
+ ;; tx-sender must be locked
+ (asserts! (> amount-ustx u0)
+ (err ERR_STACK_EXTEND_NOT_LOCKED))
+
+ ;; tx-sender must not be delegating
+ (asserts! (is-none (get-check-delegation tx-sender))
+ (err ERR_STACKING_ALREADY_DELEGATED))
+
+ ;; standard can-stack-stx checks
+ (try! (can-stack-stx pox-addr amount-ustx first-extend-cycle lock-period))
+
+ ;; register the PoX address with the amount stacked
+ ;; for the new cycles
+ (let ((extended-reward-set-indexes (try! (add-pox-addr-to-reward-cycles pox-addr first-extend-cycle extend-count amount-ustx tx-sender signer-key)))
+ (reward-set-indexes
+ ;; use the active stacker state and extend the existing reward-set-indexes
+ (let ((cur-cycle-index (- first-reward-cycle (get first-reward-cycle stacker-state)))
+ (old-indexes (get reward-set-indexes stacker-state))
+ ;; build index list by taking the old-indexes starting from cur cycle
+ ;; and adding the new indexes to it. this way, the index is valid starting from the current cycle
+ (new-list (concat (default-to (list) (slice? old-indexes cur-cycle-index (len old-indexes)))
+ extended-reward-set-indexes)))
+ (unwrap-panic (as-max-len? new-list u12)))))
+ ;; update stacker record
+ (map-set stacking-state
+ { stacker: tx-sender }
+ { pox-addr: pox-addr,
+ reward-set-indexes: reward-set-indexes,
+ first-reward-cycle: first-reward-cycle,
+ lock-period: lock-period,
+ delegated-to: none })
+
+ ;; return lock-up information
+ (ok { stacker: tx-sender, unlock-burn-height: new-unlock-ht })))))
+```
+
+
+
+You can “rotate” your signing key when extending your lock period.
+
+The arguments are:
+
+* Extend count: the number of cycles to add to your lock period. The resulting lock period cannot be larger than 12. For example, if you're currently locked with 6 cycles remaining, the maximum number you can extend is 6.
+* Pox Address: the BTC address to receive rewards
+* Signer public key: the public key used for signing. This can stay the same, or you can use a new key.
+* Signer signature: a signature proving control of your signing key
+* Max Amount: This parameter is used to validate the signer signature provided. It represents the maximum number of uSTX (1 stx = 1,000,000 uSTX) that can be stacked in this transaction.
+* Auth Id: This parameter is used to validate the signer signature provided. It is a random integer that prevents the re-use of this particular signer signature.
+
+#### Increasing the stacking amount
+
+The stacking amount can also be increased while actively Stacking. The increased position will take effect starting with the next Stacking cycle. The function called is `stack-increase`.
+
+
+
+Function source code
+
+```clojure
+;; Increase the number of STX locked.
+;; *New in Stacks 2.1*
+;; This method locks up an additional amount of STX from `tx-sender`'s, indicated
+;; by `increase-by`. The `tx-sender` must already be Stacking & must not be
+;; straddling more than one signer-key for the cycles effected.
+;; Refer to `verify-signer-key-sig` for more information on the authorization parameters
+;; included here.
+(define-public (stack-increase
+ (increase-by uint)
+ (signer-sig (optional (buff 65)))
+ (signer-key (buff 33))
+ (max-amount uint)
+ (auth-id uint))
+ (let ((stacker-info (stx-account tx-sender))
+ (amount-stacked (get locked stacker-info))
+ (amount-unlocked (get unlocked stacker-info))
+ (unlock-height (get unlock-height stacker-info))
+ (cur-cycle (current-pox-reward-cycle))
+ (first-increased-cycle (+ cur-cycle u1))
+ (stacker-state (unwrap! (map-get? stacking-state
+ { stacker: tx-sender })
+ (err ERR_STACK_INCREASE_NOT_LOCKED)))
+ (cur-pox-addr (get pox-addr stacker-state))
+ (cur-period (get lock-period stacker-state)))
+ ;; tx-sender must be currently locked
+ (asserts! (> amount-stacked u0)
+ (err ERR_STACK_INCREASE_NOT_LOCKED))
+ ;; must be called with positive `increase-by`
+ (asserts! (>= increase-by u1)
+ (err ERR_STACKING_INVALID_AMOUNT))
+ ;; stacker must have enough stx to lock
+ (asserts! (>= amount-unlocked increase-by)
+ (err ERR_STACKING_INSUFFICIENT_FUNDS))
+ ;; must be called directly by the tx-sender or by an allowed contract-caller
+ (asserts! (check-caller-allowed)
+ (err ERR_STACKING_PERMISSION_DENIED))
+ ;; stacker must be directly stacking
+ (asserts! (> (len (get reward-set-indexes stacker-state)) u0)
+ (err ERR_STACKING_IS_DELEGATED))
+ ;; stacker must not be delegating
+ (asserts! (is-none (get delegated-to stacker-state))
+ (err ERR_STACKING_IS_DELEGATED))
+
+ ;; Validate that amount is less than or equal to `max-amount`
+ (asserts! (>= max-amount (+ increase-by amount-stacked)) (err ERR_SIGNER_AUTH_AMOUNT_TOO_HIGH))
+
+ ;; Verify signature from delegate that allows this sender for this cycle
+ (try! (consume-signer-key-authorization cur-pox-addr cur-cycle "stack-increase" cur-period signer-sig signer-key increase-by max-amount auth-id))
+
+ ;; update reward cycle amounts
+ (asserts! (is-some (fold increase-reward-cycle-entry
+ (get reward-set-indexes stacker-state)
+ (some { first-cycle: first-increased-cycle,
+ reward-cycle: (get first-reward-cycle stacker-state),
+ stacker: tx-sender,
+ add-amount: increase-by,
+ signer-key: signer-key })))
+ (err ERR_INVALID_INCREASE))
+ ;; NOTE: stacking-state map is unchanged: it does not track amount-stacked in PoX-4
+ (ok { stacker: tx-sender, total-locked: (+ amount-stacked increase-by)})))
+```
+
+
+
+The arguments are:
+
+* Increase by: the amount of uSTX to add to your lock amount.
+* Signer public key: the public key used for signing. This can stay the same, or you can use a new key.
+* Signer signature: a signature proving control of your signing key
+* Max Amount: This parameter is used to validate the signer signature provided. It represents the maximum number of uSTX (1 stx = 1,000,000 uSTX) that can be stacked in this transaction.
+* Auth Id: This parameter is used to validate the signer signature provided. It is a random integer that prevents the re-use of this particular signer signature.
+
+### Step by Step Stacking Guide
+
+Now that you are familiar with the overall stacking flow and the different roles played, let's dive into the step-by-step guide for actually conducting the stacking process.
+
+{% hint style="info" %}
+There are several ways you can go about stacking. This guide will cover using Leather Earn, which is a stacking web application and the simplest option.
+
+Additionally, you can choose to call the stacking functions directly from the [deployed contract](https://explorer.hiro.so/txid/SP000000000000000000002Q6VF78.pox-4?chain=mainnet) in the explorer.
+
+The fields and process will be the same, but the UI will differ.
+
+Finally, you can stack using JS and the [@stacks/stacking](https://github.com/stx-labs/stacks.js/tree/main/packages/stacking) package if you prefer. Again, the functions and parameters will be the same, you will just be writing your JS code directly instead of using a UI.
+
+If you are interested in using this method, you'll want to follow the [stacking guide](https://docs.hiro.so/stacks.js/guides/how-to-integrate-stacking) created by Hiro, and be sure to integrate the new parameters described in [Hiro's Nakamoto update doc](https://docs.hiro.so/nakamoto/stacks-js).
+{% endhint %}
+
+### Step 1: Run or work with a signer
+
+This is a necessary prerequisite to stacking as a solo stacker or pool operator.
+
+Running a signer involves setting up a hosted production environment that includes both a Stacks Node and the Stacks Signer. For more information, refer to the [running a signer doc](../run-a-signer/).
+
+Once the signer software is running, you'll have to keep track of the `stacks_private_key` that you used when configuring your signer software. This will be used in subsequent Stacking transactions.
+
+{% hint style="info" %}
+In the note above about pool operator vs signer keys, this corresponds to your signer key, not your pool operator wallet
+{% endhint %}
+
+Alternatively, you can work with a signer and have them perform step 2 below on your behalf.
+
+### Step 2: Generate a signer key signature
+
+#### Overview of signer keys and signatures
+
+The main difference with Stacking in Nakamoto is that the Signer (either solo Stacker or signer running a pool) needs to include new parameters in their Stacking transactions. These are Clarity transactions that Stackers will call when interacting with the `pox-4.clar` contract. Interacting with this contract is how you as a Stacker actually stack your STX tokens.
+
+{% hint style="info" %}
+The current pox-4 contract address can be found by visiting the following endpoint of the Hiro API: [https://api.mainnet.hiro.so/v2/pox](https://api.mainnet.hiro.so/v2/pox).
+
+You can then visit the [Explorer](https://explorer.hiro.so/?chain=mainnet) to view the contract and pass in the contract id.
+
+You may want to review this contract to familiarize yourself with it.
+{% endhint %}
+
+Here is an overview of the fields you will need to pass. We'll cover how to get and pass these fields as we dive further into this doc:
+
+{% stepper %}
+{% step %}
+### signer-key
+
+The public key that corresponds to the `stacks_private_key` your signer is using.
+{% endstep %}
+
+{% step %}
+### signer-signature
+
+A signature that demonstrates that you actually control your `signer-key`. Because signer keys need to be unique, this is also a safety check to ensure that other Stackers can’t use someone else’s public key.
+{% endstep %}
+
+{% step %}
+### max-amount
+
+The maximum amount of uSTX (1 STX = 1,000,000 uSTX) that can be locked in the transaction that uses this signature. For example, if calling `stack-increase`, this parameter dictates the maximum amount of uSTX that can be used to add more locked STX.
+{% endstep %}
+
+{% step %}
+### auth-id
+
+A random integer that prevents the re-use of a particular signature, similar to how nonces are used with transactions. Must be less than 14 characters.
+{% endstep %}
+{% endstepper %}
+
+Signer signatures are signatures created using a particular signer key. They demonstrate that the controller of that signer key is allowing a Stacker to use their signing key. The signer signature’s message hash is created using the following data:
+
+* `method`: a string that indicates the Stacking method that is allowed to utilize this signature. The valid options are `stack-increase`, `stack-stx`, `stack-extend`, `agg-commit` (for stack-aggregation-commit-indexed), or `agg-increase` (for stack-aggregation-increase)
+* `max-amount`: described above
+* `auth-id`: described above
+* `period`: a value between 1 and 12, which indicates the number of cycles that the Stacker is allowed to lock their STX for in this particular Stacking transaction. For `agg-commit`, this must be equal to 1
+* `reward-cycle`: This represents the reward cycle in which the Stacking transaction can be confirmed. For solo stacking operations (`stack-stx`, `stack-extend` and `stack-increase`), this has to be set as the current cycle.
+* `pox-address`: The Bitcoin address that is allowed to be used for receiving rewards. This can be set to any Bitcoin address that you have access to.
+* `config`: This represents the signer configuration file path where the `stacks_private_key` is located, and it is used for signing the generated signature.
+
+Now that we have an overview of role and contents of signatures, let's see how to actually generate them. You have several options available.
+
+Generating your signature with Degen Lab's stacks.tools
+
+Degen Lab has a signature generation tool that will generate a signature using their signer. This is the quickest and simplest option. To generate a signature using this method, all you need to do is visit their [signature tool](https://signature.stacking.tools/) and pass in the relevant information as covered on this page.
+
+#### Generating your signature with stacks.js
+
+The [@stacks/stacking](https://www.npmjs.com/package/@stacks/stacking) NPM package provides interfaces to generate and use signer signatures.
+
+There is a function called `signPoxSignature` that will allow you to generate this signature and pass it in to the stacking function.
+
+More information and code samples can be found on [Hiro's Nakamoto docs](https://docs.hiro.so/nakamoto/stacks-js).
+
+#### Generating your signature using the stacks-signer CLI
+
+If you already have your signer configured and set up, you can use the `stacks-signer` CLI to generate this signature. You can either SSH into your running signer or use the `stacks-signer` CLI locally. If using the CLI locally, you will need to ensure you have a matching configuration file located on your filesystem. Having a matching configuration file is important to ensure that the signer public key you make in Stacking transactions is the same as in your hosted signer.
+
+The CLI command is:
+
+```bash
+# Max Amount equivallent to 1M STX
+
+# Auth Id should be a random string less than 14 characters
+stacks-signer generate-stacking-signature \
+ --method stack-stx \
+ --max-amount 1000000000000 \
+ --auth-id 71948271489 \
+ --period 1 \
+ --reward-cycle 100 \
+ --pox-address bc1... \
+ --config ./config.toml \
+ --json
+```
+
+These arguments match those described in section [Overview of signer keys and signatures](solo-stack.md#overview-of-signer-keys-and-signatures), with the addition of:
+
+* `--json`, to optionally output the resulting signature in JSON
+
+You can use the following command to generate a random `32` bit integer as `auth-id`:
+
+```bash
+python3 -c 'import secrets; print(secrets.randbits(32))'
+```
+
+Once the `generate-stacking-signature` command is run, the CLI will output a JSON:
+
+```json
+{"authId":"1234","maxAmount":"12345","method":"stack-stx","period":1,"poxAddress":"bc1...","rewardCycle":100,"signerKey":"aaaaaaaa","signerSignature":"bbbbbbbbbbb"}
+```
+
+You will use the JSON when calling Stacking transactions from your Stacker address as outlined above. Remember that this may be different than your signer address.
+
+#### Generating your signature with Leather Earn
+
+Leather Earn is a web application that provides an easy-to-use interface for stacking and generating signatures. We'll cover using Leather Earn for stacking at the end of this document, here we will cover how to use it to generate a signature.
+
+{% hint style="info" %}
+At the time of writing, this has only been tested using the [Leather](https://leather.io/) wallet.
+{% endhint %}
+
+You can visit [earn.leather.io](https://earn.leather.io/) to generate a signer key signature. Make sure you’re connected to the correct network.\
+To generate a signer key signature, it’s important that you’ve logged in Leather with the same secret key that was used to [generate your signer key](broken-reference), not the account that will serve as your pool operator address. Once you’ve setup that account on Leather, you can log in to Leather Earn.\
+Click the link “Signer key signature” at the bottom of the page. This will open the “generate a signer key signature” page.
+
+The fields are:
+
+* Reward cycle:
+ * For all solo stacking transactions, this must equal the current reward cycle, not the cycle in which they will start stacking. The field defaults to the current reward cycle.
+ * For stack-aggregation-commit-indexed, this field must equal the cycle used in that function’s “reward cycle” argument. Typically, that equates to current\_cycle + 1.
+* Bitcoin address: the PoX reward address that can be used
+* Topic: the stacking function that will use this signature
+* Max amount: max amount of STX that can be used. Defaults to “max possible amount”
+* Auth ID: defaults to random int
+* Duration: must match the number of cycles used in the stacking transaction. For stack-aggregation-commit-indexed, use “1”.
+
+{% hint style="warning" %}
+Each of these fields must be exactly matched in order for the Stacking transaction to work. Future updates to Leather Earn will verify the signature before the transaction is made.
+{% endhint %}
+
+Click the “generate signature” button to popup a Leather page where you can generate the signature. Once you submit that popup, Leather Earn will have the signer key and signature you generated.
+
+After you sign that message, you'll see the information you can use in your Stacking transactions, including the signer public key and signature.
+
+You can click the “copy” icon next to “signer details to share with stackers”. This will copy a JSON string, which can be directly pasted into the Leather Earn page where you make your Stacking transaction. Alternatively, this information can be entered manually.
+
+We'll cover the Leather Earn pages for actually making those transactions in the next section of this document.
+
+#### Using a hardware or software wallet to generate signatures
+
+When the signer is configured with a `stacks_private_key`, the signer may want to be able to use that key in a wallet to make stacking signatures.
+
+If the signer uses a tool like [@stacks/cli](https://docs.hiro.so/get-started/command-line-interface) to generate the key, the CLI also outputs a mnemonic (aka “seed phrase”) that can be imported into a wallet. Because the Stacks CLI uses the standard derivation path for generating Stacks keys, any Stacks wallet will default to having that same private key when the wallet is imported from a derivation path. Similarly, if a hardware wallet is setup with that mnemonic, then the Signer can use a wallet like Leather to make stacking signatures.
+
+The workflow for setting up a wallet to generate signatures:
+
+{% stepper %}
+{% step %}
+Use @stacks/cli to generate the keychain and private key.
+
+* Typically, when using a hardware wallet, it’s better to generate the mnemonic on the hardware wallet. For this use case, however, the signer software needs the private key, and hardware wallets (by design) don’t allow exporting private keys.
+{% endstep %}
+
+{% step %}
+Take the `privateKey` from the CLI output and add it to your signer’s configuration.
+{% endstep %}
+
+{% step %}
+Take the mnemonic (24 words) and either:
+
+* Setup a new hardware wallet with this mnemonic, or
+* Store it somewhere securely, like a password manager. When the signer needs to generate signatures for Stacking transactions, they can import it into either Leather or XVerse.
+{% endstep %}
+{% endstepper %}
+
+When the user needs to generate signatures:
+
+{% stepper %}
+{% step %}
+Set up your wallet with your signer key’s private key. Either:
+
+* Setup your Leather wallet with a Ledger hardware wallet, or
+* Import your mnemonic into Leather, XVerse, or another Stacks wallet.
+{% endstep %}
+
+{% step %}
+Open an app that has stacking signature functionality built-in.
+{% endstep %}
+
+{% step %}
+Connect your wallet to the app (aka sign in).
+{% endstep %}
+
+{% step %}
+In the app, enter your PoX address and “submit”.
+
+* The app will popup a window in your wallet that prompts you to sign the information and will show clear information about what you’re signing.
+{% endstep %}
+
+{% step %}
+Create the signature.
+
+* If using a Ledger, confirm on your device.
+{% endstep %}
+
+{% step %}
+The app will display two results:
+
+* Your signer key, which is the public key associated with your signer’s key.
+* Your signer signature.
+{% endstep %}
+
+{% step %}
+Finally, make a Stacking transaction using the signer key and signer signature.
+{% endstep %}
+{% endstepper %}
+
+Now that you have your signer signature generated, it's time to start stacking. This process will vary depending on your chosen method. We've included instructions for solo stacking using [Leather Earn](https://earn.leather.io/) below.
+
+### Step 3: Stack your STX
+
+#### stack-stx
+
+To start, you'll visit [Leather Earn](https://earn.leather.io/) and click the “Stack independently” button on the home page.
+
+This page will allow you to input the following input:
+
+* The amount of STX you want to lock
+* The duration (in number of cycles) to lock for
+* Your BTC address where you will receive Stacking rewards
+* New fields:
+ * Your signer public key
+ * Your signer key signature (this is what you generated in the previous step)
+ * Auth ID
+ * Max amount
+
+#### stack-extend
+
+If you want to extend the time that your STX will be locked for, you can use the stack-extend page on Leather Earn.
+
+If you’re already stacking, the home page will provide a link to “view stacking details”. From there, you can choose to extend.
+
+On this page are the following fields:
+
+* The number of cycles you want to extend for
+* Your BTC address to receive rewards
+* New fields:
+ * Signer public key
+ * Signer key signature
+ * Auth ID
+ * Max amount
+
+#### stack-increase
+
+If you want to increase the amount of STX locked, you can use the stack-increase page on Leather Earn.
+
+If you’re already stacking, the home page will provide a link to “view stacking details”. From there, you can choose to increase.
+
+On this page are the following fields:
+
+* The amount of STX you want to increase by
+* New fields:
+ * Signer public key
+ * Signer key signature
+ * Auth ID
+ * Max amount
diff --git a/docs/operate/stacking-stx/stack-with-a-pool.md b/docs/operate/stacking-stx/stack-with-a-pool.md
new file mode 100644
index 0000000000..138c8f2984
--- /dev/null
+++ b/docs/operate/stacking-stx/stack-with-a-pool.md
@@ -0,0 +1,65 @@
+# Stack with a Pool
+
+The most common stacking scenario is to be an individual stacker that does not meet the stacking minimum and to stack with a pool.
+
+This is also the least complex version and is very easy to accomplish.
+
+Be sure you are familiar with the [concept of stacking](https://app.gitbook.com/s/H74xqoobupBWwBsVMJhK/block-production/stacking) before digging into this.
+
+The dynamic minimum required to stack STX changes based on the total liquid supply of STX in the network and can be found by looking at the `pox` endpoint of the Hiro API: [https://api.hiro.so/v2/pox](https://api.hiro.so/v2/pox).
+
+If you do not meet this minimum, you'll need to delegate your STX to a pool operator.
+
+This is a non-custodial delegation, meaning that your STX do not actually leave your wallet.
+
+{% hint style="info" %}
+Pool operators have a lot of control over exactly how they implement stacking. Usually users will be interacting with a wrapper contract that the pool operator has created to utilize the core stacking contract.
+{% endhint %}
+
+Delegating your STX to a pool operator involves a few steps:
+
+{% stepper %}
+{% step %}
+### Find a pool
+
+The first step is to find a stacking pool you would like to stack with. Pool operators have a lot of control over exactly how they implement stacking and reward distribution, and they all do things a bit differently, so it's important to do your research. The Stacks website has a great [page on stacking](https://www.stacks.co/learn/stacking) that links to several pool operators for you to research.
+{% endstep %}
+
+{% step %}
+### Use the pool's UI to call the delegate function
+
+After you've chosen your pool operator, you'll need to get set up with a [Stacks-compatible wallet](https://www.stacks.co/explore/ecosystem?category=All+Teams#wallets) like Leather, Xverse, or Asigna.
+
+Then you'll use your chosen pool operator's UI to call their delegation function. You may need to pass a couple of parameters here like how long you want to grant delegation permission for.
+{% endstep %}
+
+{% step %}
+### Pool operator stacks tokens
+
+Once you grant permission for the pool operator to delegate, they will take over and call a separate function in the stacking contract to actually stack those delegated tokens. At this point your STX will be locked.
+
+Depending on how the pool operator handles things, they may offer the option to automatically continue to stack your STX for up to 12 continuous cycles.
+{% endstep %}
+
+{% step %}
+### Pool operator allocates rewards
+
+Next, the pool operator will track what proportion of rewards you should earn based on the proportion of STX you delegated. If distributing rewards directly in Bitcoin, the pool operator will need to take custody of the Bitcoin and manually distribute it.
+
+This is why it is important to do your research and stack with a pool operator whose reward distribution mechanism you trust. Different operators have different methods to make this process transparent and as trust-minimized as possible.
+{% endstep %}
+
+{% step %}
+### Pool operator distributes rewards
+
+Finally, the pool operator will distribute those rewards to you in either BTC or STX, depending on the model they use.
+{% endstep %}
+{% endstepper %}
+
+If you want to learn more about the specific functions and the contract that handles the stacking process, be sure to take a look at the [stacking contract walkthrough](https://app.gitbook.com/s/GVj1Z9vMuEOMe7oH7Wnq/clarity/example-contracts/stacking).
+
+### Liquid Stacking
+
+Liquid stacking is when you delegate your STX tokens to a liquid stacking provider and they issue you a new token such as stSTX that you can then use in the ecosystem. This makes it so that stackers can still use their STX to participate in DeFi protocols and other apps even while their STX are locked.
+
+This works a bit differently than traditional stacking and links to liquid stacking providers for you to research can be found on the [Stacks website](https://www.stacks.co/learn/stacking).
diff --git a/docs/operate/stacking-stx/stop-stacking.md b/docs/operate/stacking-stx/stop-stacking.md
new file mode 100644
index 0000000000..fcca8c5d8f
--- /dev/null
+++ b/docs/operate/stacking-stx/stop-stacking.md
@@ -0,0 +1,67 @@
+# Stop Stacking
+
+When you decide it's time to stop stacking your STX tokens, the process depends on whether you are stacking solo or delegating your tokens to a pool operator. This guide explains the steps for both scenarios.
+
+***
+
+## Stopping Solo Stacking
+
+When stacking solo using the `stack-stx` function, your STX is locked for a fixed period (the lock period) defined when you initiated stacking or when you extended the lock period. **No additional action is required to stop stacking**, you simply have to wait until the lock period expires.
+
+{% hint style="info" %}
+In solo stacking, both the `stack-stx` and `stack-extend` functions emits an event that includes the `unlock-burn-height` field. This is the burn block height at which your tokens will be automatically unlocked.
+{% endhint %}
+
+## Stopping Pooled Stacking
+
+If you're stacking with a pool (where you delegate your STX via the `delegate-stx` function), the process to stop stacking requires one extra step before your STX is eventually unlocked.
+
+{% stepper %}
+{% step %}
+### Revoke Delegation
+
+Before your STX can be unlocked, you must cancel the delegation with the pool operator. This is done by calling the `revoke-delegate-stx` function through the pool's interface, or within the [pox-4](https://explorer.hiro.so/txid/SP000000000000000000002Q6VF78.pox-4?chain=mainnet) contract.
+
+
+
+Function source code
+
+```clojure
+;; Revokes the delegation to the current stacking pool.
+;; New in pox-4: Fails if the delegation was already revoked.
+;; Returns the last delegation state.
+(define-public (revoke-delegate-stx)
+ (let ((last-delegation-state (get-check-delegation tx-sender)))
+ ;; must be called directly by the tx-sender or by an allowed contract-caller
+ (asserts! (check-caller-allowed)
+ (err ERR_STACKING_PERMISSION_DENIED))
+ (asserts! (is-some last-delegation-state) (err ERR_DELEGATION_ALREADY_REVOKED))
+ (asserts! (map-delete delegation-state { stacker: tx-sender }) (err ERR_DELEGATION_ALREADY_REVOKED))
+ (ok last-delegation-state)))
+```
+
+
+
+Calling `revoke-delegate-stx` cancels your STX delegation, revoking the pool operator's access to further lock/stack your funds. Even after revoking the delegation, your STX will remain locked until the end of the last stacking cycle chosen by the pool (can be at most 12 cycles in the future).
+
+{% hint style="warning" %}
+Failing to revoke your delegation will mean that you continue to allow the pool to stack your STX until the reach of the burn block height mentioned in the delegate function (`delegate-stx`). Ensure that you have successfully called `revoke-delegate-stx` if you want to stop stacking sooner.
+{% endhint %}
+{% endstep %}
+
+{% step %}
+### Wait for Funds to Unlock
+
+After revoking your delegation, your STX tokens will still remain locked until the last stacking cycle chosen by the pool operator completes. The unlock occurs automatically at the predefined unlock burn height for that cycle.
+
+{% hint style="info" %}
+Even in pooled stacking, the unlocking mechanism follows the same blockchain timing as solo stacking. Revoking delegation only stops future stacking actions, it does not immediately unlock your tokens.
+{% endhint %}
+{% endstep %}
+{% endstepper %}
+
+## Considerations
+
+* Monitor Your Stacking Status: Use your wallet's interface or the [Hiro Explorer](https://explorer.hiro.so/?chain=mainnet) to track the status of your lock period and confirm when your tokens are available.
+* Using the API: Hiro's API offers an endpoint to [Get account STX balance](https://docs.hiro.so/stacks/api/accounts/stx-balances), which contains the `burnchain_unlock_height` height, representing the burn block height where your STX unlocks.
+* Plan Ahead: Since the unlocking is bound to cycle's timing, plan your stacking period or revocation accordingly to minimize delays in accessing your funds.
diff --git a/docs/press-and-reports/.gitbook.yaml b/docs/press-and-reports/.gitbook.yaml
new file mode 100644
index 0000000000..77d87e4766
--- /dev/null
+++ b/docs/press-and-reports/.gitbook.yaml
@@ -0,0 +1,30 @@
+root: ./
+
+redirects:
+ bitcoin-theses-and-reports/bitcoin-theses: README.md
+ bitcoin-theses-and-reports/bitcoin-reports: bitcoin-theses-and-reports/bitcoin-reports.md
+
+ # 2024 press-and-top-links redirects
+ press-and-top-links/2024/january-2024: press-and-top-links/2024/january-2024.md
+ press-and-top-links/2024/february-2024: press-and-top-links/2024/february-2024.md
+ press-and-top-links/2024/march-2024: press-and-top-links/2024/march-2024.md
+ press-and-top-links/2024/april-2024: press-and-top-links/2024/april-2024.md
+ press-and-top-links/2024/may-2024: press-and-top-links/2024/may-2024.md
+ press-and-top-links/2024/june-2024: press-and-top-links/2024/june-2024.md
+ press-and-top-links/2024/july-2024: press-and-top-links/2024/july-2024.md
+ press-and-top-links/2024/august-2024: press-and-top-links/2024/august-2024.md
+ press-and-top-links/2024/september-2024: press-and-top-links/2024/september-2024.md
+ press-and-top-links/2024/october-2024: press-and-top-links/2024/october-2024.md
+ press-and-top-links/2024/november-2024: press-and-top-links/2024/november-2024.md
+ press-and-top-links/2024/december-2024: press-and-top-links/2024/december-2024.md
+
+ # 2025 press-and-top-links redirects
+ press-and-top-links/2025/january-2025: press-and-top-links/2025/january-2025.md
+ press-and-top-links/2025/february-2025: press-and-top-links/2025/february-2025.md
+ press-and-top-links/2025/march-2025: press-and-top-links/2025/march-2025.md
+ press-and-top-links/2025/april-2025: press-and-top-links/2025/april-2025.md
+ press-and-top-links/2025/may-2025: press-and-top-links/2025/may-2025.md
+ press-and-top-links/2025/june-2025: press-and-top-links/2025/june-2025.md
+ press-and-top-links/2025/july-2025: press-and-top-links/2025/july-2025.md
+ press-and-top-links/2025/august-2025: press-and-top-links/2025/august-2025.md
+ press-and-top-links/2025/september-2025: press-and-top-links/2025/september-2025.md
diff --git a/docs/press-and-reports/.gitbook/assets/theses.svg b/docs/press-and-reports/.gitbook/assets/theses.svg
new file mode 100644
index 0000000000..779857b113
--- /dev/null
+++ b/docs/press-and-reports/.gitbook/assets/theses.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/press-and-reports/README.md b/docs/press-and-reports/README.md
new file mode 100644
index 0000000000..d057fa03ee
--- /dev/null
+++ b/docs/press-and-reports/README.md
@@ -0,0 +1,26 @@
+---
+description: >-
+ This list will be updated monthly and capture notable investor theses or
+ industry commentary on Stacks and the Bitcoin ecosystem.
+cover: .gitbook/assets/theses.svg
+coverY: 0
+---
+
+# Bitcoin Theses
+
+| Title | Outlet / Author | Date |
+| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------- | ------------: |
+| [TradFi Tomorrow: DeFi and the Rise of Extensible Finance](https://www.paradigm.xyz/2025/03/tradfi-tomorrow-defi-and-the-rise-of-extensible-finance) | Paradigm | March 2025 |
+| 💭 [It's time to make your It’s time to make your BTC productive again](https://medium.com/@aspendigitalAMP/its-time-to-make-your-btc-productive-again-7532ea788a32) | Aspen Digital | March 2025 |
+| 💭 [The Bitcoin Renaissance: Unlocking Trillions in Value](https://www.forbes.com/sites/leeorshimron/2024/08/13/the-bitcoin-renaissance-unlocking-trillions-in-value/) | Leeor Shimron, Forbes | August 2024 |
+| 💭 [My journey with the Blockchain Ecosystem and why do I like Stacks?](https://www.linkedin.com/pulse/my-journey-blockchain-ecosystem-why-do-i-like-stacks-ali-farid-khwaja-wkybf?ref=stacksblog) | Ali Farid Khwaja | July 2024 |
+| 🖋️ [Bitcoin and Future Infracon Highlights](https://arkstreamcapital.medium.com/arkstream-capital-bitcoin-and-future-infracon-highlights-b9b3ac4777cd) | Arkstream Capital | June 2024 |
+| 📊 [The Build on Bitcoin Era is Here](https://mythofmoney.substack.com/p/build-on-bitcoin-era-is-here) | Myth of Money | February 2024 |
+| 📊 [2024 Bitcoin Halving: This Time It's Different](https://www.grayscale.com/research/reports/2024-halving-this-time-its-actually-different) | Grayscale | February 2024 |
+| 🌱 [The Year Ahead](https://panteracapital.com/blockchain-letter/the-year-ahead-2024/) | Pantera | January 2024 |
+| 🌱 [State of Bitcoin Q4 2023](https://messari.io/report/state-of-bitcoin-q4-2023) | Messari | January 2024 |
+| 🖋️ [Notable Moments for Bitcoin in 2024](https://trustmachines.co/blog/notable-moments-for-bitcoin-in-2024/?ref=stacksblog) | Trust Machines | January 2024 |
+| 📙 [Bitcoin Layers: Tapestry of a Trustless Financial Era](https://bitcoinlayersreport.com/) | Spartan Group | December 2023 |
+| 🧪 [A Technical History of Blockchain Design, Innovation, and Narratives](https://foundationcapital.com/a-technical-history-of-blockchain-design-innovation-and-narratives-part-i/) | Foundation Capital | December 2023 |
+| 📊 [2024 Crypto Market Outlook](https://www.coinbase.com/nl/institutional/research-insights/research/market-intelligence/2024-crypto-market-outlook) | Coinbase | December 2023 |
+| 👀 [STX Thesis Update](https://medium.com/@halp1120/stx-thesis-update-cd09b7f2cce8) | Hal Press | December 2023 |
diff --git a/docs/press-and-reports/SUMMARY.md b/docs/press-and-reports/SUMMARY.md
new file mode 100644
index 0000000000..f74f6c56dd
--- /dev/null
+++ b/docs/press-and-reports/SUMMARY.md
@@ -0,0 +1,34 @@
+# Table of contents
+
+## Bitcoin Theses & Reports
+
+* [Bitcoin Theses](README.md)
+* [Bitcoin Reports](bitcoin-theses-and-reports/bitcoin-reports.md)
+
+## Press & Top Links
+
+* [2024](press-and-top-links/2024/README.md)
+ * [January 2024](press-and-top-links/2024/january-2024.md)
+ * [February 2024](press-and-top-links/2024/february-2024.md)
+ * [March 2024](press-and-top-links/2024/march-2024.md)
+ * [April 2024](press-and-top-links/2024/april-2024.md)
+ * [May 2024](press-and-top-links/2024/may-2024.md)
+ * [June 2024](press-and-top-links/2024/june-2024.md)
+ * [July 2024](press-and-top-links/2024/july-2024.md)
+ * [August 2024](press-and-top-links/2024/august-2024.md)
+ * [September 2024](press-and-top-links/2024/september-2024.md)
+ * [October 2024](press-and-top-links/2024/october-2024.md)
+ * [November 2024](press-and-top-links/2024/november-2024.md)
+ * [December 2024](press-and-top-links/2024/december-2024.md)
+* [2025](press-and-top-links/2025/README.md)
+ * [January 2025](press-and-top-links/2025/january-2025.md)
+ * [February 2025](press-and-top-links/2025/february-2025.md)
+ * [March 2025](press-and-top-links/2025/march-2025.md)
+ * [April 2025](press-and-top-links/2025/april-2025.md)
+ * [May 2025](press-and-top-links/2025/may-2025.md)
+ * [June 2025](press-and-top-links/2025/june-2025.md)
+ * [July 2025](press-and-top-links/2025/july-2025.md)
+ * [August 2025](press-and-top-links/2025/august-2025.md)
+ * [September 2025](press-and-top-links/2025/september-2025.md)
+ * [October 2025](press-and-top-links/2025/september-2025-1.md)
+ * [November 2025](press-and-top-links/2025/september-2025-2.md)
diff --git a/docs/press-and-reports/bitcoin-theses-and-reports/bitcoin-reports.md b/docs/press-and-reports/bitcoin-theses-and-reports/bitcoin-reports.md
new file mode 100644
index 0000000000..83f5cb18cf
--- /dev/null
+++ b/docs/press-and-reports/bitcoin-theses-and-reports/bitcoin-reports.md
@@ -0,0 +1,31 @@
+---
+description: >-
+ This list will be updated monthly and capture notable investor theses or
+ industry commentary on Stacks and the Bitcoin ecosystem.
+---
+
+# Bitcoin Reports
+
+| Title | Outlet / Author | Date |
+| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------- | -------------- |
+| 🧪 [Unlocking Bitcoin \[Presentation\]: The Bitcoin Tipping Point](https://syphercapital.substack.com/p/unlocking-bitcoin-presentation-the) | Sypher Capital | March 2025 |
+| 📊 [State of Crypto: 2025 Market Outlet](https://www.globalxetfs.com.au/state-of-crypto-2025-market-outlook/) | Global X | February 2025 |
+| 🟧 [Stacks Q4 2024 Brief](https://messari.io/report/stacks-q4-2024-brief) | Messari | February 2025 |
+| 📈 [Top 'Made in USA' Coins by MarketCap](https://x.com/Stacks/status/1881640502149390473?utm_source=stackssnacks.com\&utm_medium=newsletter\&utm_campaign=stacks-thrives-amid-regulatory-changes-stacking-dao-unveils-sbtc-product&_bhlid=42f17e5c11b1222a7ddd2cf3de42eb1c121496bc) | CoinGecko | January 2025 |
+| 📙 [GTM in Asia Report: The Driving Force Behind Crypto Market Growth](https://www.theblock.co/post/333733/foresight-ventures-and-primitive-ventures-unveil-game-changing-apac-crypto-go-to-market-insights) | Primitive Ventures | January 2025 |
+| 📈 [Top 10 Digital Assets Market Predictions](https://x.com/AspenDigitalAMP/status/1877289981166731741) | Aspen Digital | January 2025 |
+| 📙 [State of Tokenized BTC: A $1 Trillion Opportunity](https://app.gitbook.com/s/H74xqoobupBWwBsVMJhK/sbtc/sbtc-operations/deposit) | Bitcoin Builders Association | December 2024 |
+| 🟧 [Our Thesis on Stacks](https://candidcontemplation.substack.com/p/our-thesis-on-stx) | Portal Ventures | December 2024 |
+| 📊 [Scaling Bitcoin](https://www.gsr.io/reports/scaling-bitcoin/) | GSR | November 2024 |
+| 📊 [Bitcoin L2s: A Modular Future](https://www.galaxy.com/insights/research/bitcoin-layer-2-modular-future/) | Galaxy Digital | November 2024 |
+| 📊 [Crypto Sectors in Q4 2024](https://www.grayscale.com/research/market-commentary/grayscale-research-insights-crypto-sectors-in-q4-2024) | Grayscale | September 2024 |
+| 📈 [Stacks August 2024 Snapshot](https://x.com/signal21btc/status/1833117479024963728) | Signal21 | August 2024 |
+| 🟧 [Building Block: Stacks](https://www.grayscale.com/research/reports/building-block-stacks?ref=stacksblog) | Grayscale | August 2024 |
+| 📙 [Bitcoin Layer 2 Ecosystems](https://unhashed.aarna.ai/p/bitcoin-layer2-ecosystems?ref=stacksblog) | Alpha Unhashed | June 2024 |
+| 📙 [Stacks Snapshot June 2024](https://app.signal21.io/reports/stacks-snapshot-june-2024) | Signal21 | June 2024 |
+| 🧪 [The Future of Bitcoin #3: Scaling Bitcoin](https://www.binance.com/en/research/analysis/the-future-of-bitcoin-3-scaling-bitcoin?ref=stacksblog) | Binance Research | May 2024 |
+| 🟧 [Q4 2023: No Denying Demand For Bitcoin L2s](https://newsletters.stacks.org/p/q4-2023) | Stacks Foundation | January 2024 |
+| 📊 [Stacks established developers up 51%](https://flight.beehiiv.net/v2/clicks/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1cmwiOiJodHRwczovL3R3aXR0ZXIuY29tL0tlblRoZVJvZ2Vycy9zdGF0dXMvMTc0ODA2MDU5OTcwMjE5MjYyNj9zPTIwJnJlZj1zdGFja3NibG9nJnV0bV9zb3VyY2U9c3RhY2tzc25hY2tzLmNvbSZ1dG1fbWVkaXVtPXJlZmVycmFsJnV0bV9jYW1wYWlnbj1kaXNjb3Zlci1zdGFja3MtaW4tc3BhcnRhbi1ncm91cC1iaXRjb2luLWwyLXJlcG9ydC1lbGVjdHJpYy1jYXBpdGFsLWRldmVsb3Blci1yZXBvcnQiLCJwb3N0X2lkIjoiZTdmYWFkODEtZmI3Ni00MjBmLTk3YWItNGJjMjdmM2RiYjdiIiwicHVibGljYXRpb25faWQiOiIzY2ZhYmZjYy0xNDU5LTQ0NTAtODI3MC1iOGJmM2RkMmFiOTciLCJ2aXNpdF90b2tlbiI6ImQxNDQwNWJiLWMxOWEtNDJiYi05NGQxLTY4MmRiNzZkOWQ3ZSIsImlhdCI6MTcwODA5NzQyMSwiaXNzIjoib3JjaGlkIn0.t0UBYmIXoMyGWCemN_n36kslOn35rIcv2v7LQR3nMLs) | Electric Capital | January 2024 |
+| 📙 [Binance Research: Top 10 Narratives to Follow in 2024](https://public.bnbstatic.com/static/files/research/top-10-narratives.pdf) | Binance Research | December 2023 |
+| 📙 [Bitcoin Layers Report: Tapestry of a Trustless Financial Era](https://bitcoinlayersreport.com/) | Spartan Group | December 2023 |
+
diff --git a/docs/press-and-reports/press-and-top-links/2024/README.md b/docs/press-and-reports/press-and-top-links/2024/README.md
new file mode 100644
index 0000000000..ba259fbbf3
--- /dev/null
+++ b/docs/press-and-reports/press-and-top-links/2024/README.md
@@ -0,0 +1,57 @@
+---
+description: >-
+ This page indexes top stories, press, and reports related to Stacks on a
+ monthly basis.
+---
+
+# 2024
+
+For weekly stories delivered to your inbox, subscribe to [Stacks Snacks](https://stackssnacks.com/). For quarterly ecosystem recaps, subscribe to the [Stacks Foundation newsletter](https://newsletters.stacks.org/).
+
+{% content-ref url="/broken/pages/cd2e8707fe40b8a43e40923a688434e9aaf4922e" %}
+[Broken link](/broken/pages/cd2e8707fe40b8a43e40923a688434e9aaf4922e)
+{% endcontent-ref %}
+
+{% content-ref url="/broken/pages/29b9f8cda45db86fe5031ee567341583324e2f6b" %}
+[Broken link](/broken/pages/29b9f8cda45db86fe5031ee567341583324e2f6b)
+{% endcontent-ref %}
+
+{% content-ref url="/broken/pages/e7761aa2c81d3c8245dbc54570199f1aebd91325" %}
+[Broken link](/broken/pages/e7761aa2c81d3c8245dbc54570199f1aebd91325)
+{% endcontent-ref %}
+
+{% content-ref url="/broken/pages/bbb9712e169fccb44833d8d9f0d98ad2bccd62f2" %}
+[Broken link](/broken/pages/bbb9712e169fccb44833d8d9f0d98ad2bccd62f2)
+{% endcontent-ref %}
+
+{% content-ref url="/broken/pages/aec6e9d8a50d144e48a1dfdc8af0e834cd9af457" %}
+[Broken link](/broken/pages/aec6e9d8a50d144e48a1dfdc8af0e834cd9af457)
+{% endcontent-ref %}
+
+{% content-ref url="/broken/pages/629cc20de749db943380bddf1d69842a2863033c" %}
+[Broken link](/broken/pages/629cc20de749db943380bddf1d69842a2863033c)
+{% endcontent-ref %}
+
+{% content-ref url="/broken/pages/cf07211cab8be8b227dee91931874e3fe5792b8d" %}
+[Broken link](/broken/pages/cf07211cab8be8b227dee91931874e3fe5792b8d)
+{% endcontent-ref %}
+
+{% content-ref url="/broken/pages/1fc9a3503ea5c373fb758dc9be7401b5f70501d4" %}
+[Broken link](/broken/pages/1fc9a3503ea5c373fb758dc9be7401b5f70501d4)
+{% endcontent-ref %}
+
+{% content-ref url="/broken/pages/db2a454141ac04ca7ea4bc2666e5af5fab4deb68" %}
+[Broken link](/broken/pages/db2a454141ac04ca7ea4bc2666e5af5fab4deb68)
+{% endcontent-ref %}
+
+{% content-ref url="/broken/pages/4050fecb50c952b844915fafb1b214eb349e1931" %}
+[Broken link](/broken/pages/4050fecb50c952b844915fafb1b214eb349e1931)
+{% endcontent-ref %}
+
+{% content-ref url="/broken/pages/68a55e4003881342d50a527d6f8e683cd5803dde" %}
+[Broken link](/broken/pages/68a55e4003881342d50a527d6f8e683cd5803dde)
+{% endcontent-ref %}
+
+{% content-ref url="/broken/pages/bd6ef1fe15c0f8e10163ba8857053effe9eb20da" %}
+[Broken link](/broken/pages/bd6ef1fe15c0f8e10163ba8857053effe9eb20da)
+{% endcontent-ref %}
diff --git a/docs/press-and-reports/press-and-top-links/2024/april-2024.md b/docs/press-and-reports/press-and-top-links/2024/april-2024.md
new file mode 100644
index 0000000000..345d3349e1
--- /dev/null
+++ b/docs/press-and-reports/press-and-top-links/2024/april-2024.md
@@ -0,0 +1,20 @@
+# April 2024
+
+| Title | Outlet/Author |
+| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ |
+| 👀 [Disruptor To Disruptee: Bitcoin Institutionalization Needs L2 Shakeup](https://www.forbes.com/sites/nimrodlehavi/2024/04/11/disruptor-to-disruptee-bitcoin-institutionalization-needs-l2-shakeup/?sh=1745f76c629b) | Forbes |
+| 🟪 [Q\&A: What will the Bitcoin halving mean for Bitcoin L2s?](https://blockworks.co/news/bitcoin-halving-layer-2-impact-stacks) | Blockworks |
+| [Bitcoin Layer 2 Stacks Prepares for Nakamoto Upgrade, its Largest Hard-Fork Ever](https://thedefiant.io/news/blockchains/bitcoin-layer-2-stacks-prepares-for-nakamoto-upgrade-its-largest-hard-fork-ever) | The Defiant |
+| 🟧 [Stacks, Bitcoin Layers, and the Nakamoto Upgrade: Here’s What’s Going On](https://decrypt.co/225801/stacks-stx-nakamoto-upgrade-bitvm-rollups-defi) | Decrypt |
+| 📈 [BTCFi is an ‘enormous opportunity’ to make Bitcoin a productive asset — Stacks](https://cointelegraph.com/news/btcfi-opportunity-make-bitcoin-productive-asset) | Cointelegraph |
+| ₿ [‘Real opportunity’ for Bitcoin Runes will come after first wave of investor hype](https://cointelegraph.com/news/real-opportunity-bitcoin-runes-after-first-wave-investor-hype) | Cointelegraph |
+| 🟧 [OG Bitcoin L2 Stacks Is Getting a Major Overhaul](https://www.coindesk.com/tech/2024/04/16/og-bitcoin-l2-stacks-is-getting-a-major-overhaul/) | Coindesk |
+| 📻 [Bitcoin L2 with Muneeb Ali of Stacks and Andy Fajar Handika of Loka Mining](https://www.charlieshrem.com/bitcoin-l2-with-muneeb-ali-of-stacks-and-andy-fajar-handika-of-loka-mining/) | Charlie Shrem Show |
+| 📧 [April 15th Newsletter](https://milkroad.com/daily/what-happened-to-prices-this-weekend/?ref=stacksblog) | Milroad |
+| 🗞️ [TEAMZ Web3/AI Summit2024 Day 1 has ended successfully!](https://prtimes.jp/main/html/rd/p/000000143.000031083.html?ref=stacksblog) | PR Times (Japan) |
+| 👀 [The Bitcoin Halving's Degen Bets](https://www.bankless.com/the-bitcoin-halvings-degen-bets) | Bankless |
+| 🌱 [Top 5 Pioneering Bitcoin Projects Poised For Growth Post-2024 Halving](https://cryptodaily.co.uk/2024/04/top-5-pioneering-bitcoin-projects-poised-for-growth-post-2024-halving) | Crypto Daily UK |
+| 💰 [Spartan Capital leads $10 million strategic funding round for Bitcoin DeFi developer ALEX](https://www.theblock.co/post/284556/spartan-capital-leads-10-million-funding-round-for-bitcoin-defi-developer-alex) | The Block |
+| ₿ [‘Bitcoin has as many functionalities as other blockchains’: Trust Machines member weighs in Bitcoin DeFi](https://cryptobriefing.com/bitcoin-functionality-other-blockchains/?ref=stacksblog) | Crypto Briefing |
+| 🗞️ [A Look into The Upcoming Bitcoin Halving & Bitcoin Layer 2s](https://figment.io/insights/a-look-into-the-upcoming-bitcoin-halving-bitcoin-layer-2s/?ref=stacksblog) | Figment |
+| 📕 [Bitcoin could gain new smart-contract superpowers](https://links.coinbase.com/e/evib?_t=3aca56371967418192255878e9689713&_m=fde47e8c40c24182b7cab3a6b10c9d3a&_e=DT1gXnNeiWLsEoKsYDSIAUCWVJr21XSvYbLTlg_uJ63W2CLdvG0Q8MPxsoVG5vCKM9SLV_5n-owzOqH_yPS9iQ%3D%3D\&utm_source=stackssnacks.com\&utm_medium=referral\&utm_campaign=stacks-apps-celebrate-all-time-tvl-high-as-new-defi-protocols-emerge) with the Lightning Network and Stacks. | Coinbase Bytes |
diff --git a/docs/press-and-reports/press-and-top-links/2024/august-2024.md b/docs/press-and-reports/press-and-top-links/2024/august-2024.md
new file mode 100644
index 0000000000..4e40c6dfe7
--- /dev/null
+++ b/docs/press-and-reports/press-and-top-links/2024/august-2024.md
@@ -0,0 +1,20 @@
+# August 2024
+
+| Title | Outlet/Author |
+| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------- |
+| 🧩 [Deploy Stacks nodes on AWS with the AWS Blockchain Node Runners](https://aws.amazon.com/blogs/database/how-to-deploy-stacks-blockchain-nodes-on-aws-with-the-aws-blockchain-node-runners-stacks-blueprint/?ref=stacksblog) | Amazon Web Services |
+| 🗞️ [Bitflow and Leather Wallet Join Forces to Simplify Bitcoin L2 Asset Swaps](https://hackernoon.com/bitflow-and-leather-wallet-join-forces-to-simplify-bitcoin-l2-asset-swaps) | Hackernoon |
+| 🤝 [Aptos and Stacks Forge New Partnership for Bitcoin Innovation](https://www.altcoinbuzz.io/cryptocurrency-news/aptos-and-stacks-forge-new-partnership-for-bitcoin-innovation/) | Altcoin Buzz |
+| 🖊 [Millions of Dollars Worth of BTC Earned by New Institutional Signers Since Nakamoto Instantiation](https://stacks.org/institutional-signers-earn-millions) | Stacks Foundation |
+| 💲[Liquidium Raises $2.5M, Accelerating L1 Borrowing and Lending](https://subscribe.bitcoinbuildersassociation.com/p/liquidium-raises-25m-accelerating?ref=stacksblog) | Bitcoin Builders Association |
+| 🧡[Bitcoin Network Stacks Begins Rollout of Speed-Boosting Nakamoto Upgrade](https://decrypt.co/246543/bitcoin-stacks-rollout-speed-boosting-nakamoto-upgrade) | Decrypt |
+| 📙[Bitcoin Network Stacks Devs 'Can See the Finish Line' With Nakamoto Upgrade](https://decrypt.co/247247/bitcoin-network-stacks-devs-see-finish-line-nakamoto-upgrade) | Decrypt |
+| 📙[Stacks co-creator on how the Nakamoto upgrade will drive a $70bn market for Bitcoin DeFi](https://www.dlnews.com/articles/defi/stacks-nakamoto-upgrade-brings-bitcoin-defi-with-sbtc-token/?utm_source=telegram\&utm_medium=organic_social\&utm_campaign=) | DL News |
+| 🗞️[Bitcoin Layer-2 Network Stacks Begins Nakamoto Upgrade](https://www.coindesk.com/tech/2024/08/28/bitcoin-layer-2-network-stacks-begins-nakamoto-upgrade/amp/) | Coindesk |
+| 🗞️[Bitcoin Layer 2 Stacks readies for Nakamoto upgrade activation](https://crypto.news/bitcoin-layer-2-stacks-readies-for-nakamoto-upgrade-activation/) | Crypto News |
+| [Stacks (STX) prepares for Nakamoto upgrade: here’s what to expect](https://coinjournal.net/news/stacks-stx-prepares-for-nakamoto-upgrade-heres-what-to-expect/) 🗞️ | Coin Journal |
+| 🗞️[Stacks (STX) poised for recovery as game-changer Nakamoto upgrade approaches](https://invezz.com/news/2024/08/26/stacks-stx-poised-for-recovery-as-game-changer-nakamoto-upgrade-approaches/) | Invezz |
+| 🗞️[Bitcoin Layer-2 Stacks Set to Receive Its Nakamoto Upgrade, Will Enhance DeFi on Bitcoin](https://www.livebitcoinnews.com/bitcoin-layer-2-stacks-set-to-receive-its-nakamoto-upgrade-will-enhance-defi-on-bitcoin/) | Live Bitcoin News |
+| 🗞️[Nakamoto Activation Begins: Leading L2 Stacks Sets the Stage for a Bitcoin-Led Future](https://markets.businessinsider.com/news/currencies/nakamoto-activation-begins-leading-l2-stacks-sets-the-stage-for-a-bitcoin-led-future-1033729689) | Markets Insider |
+| 🧡 [Bitcoin L2s Are Eating the World](https://hackernoon.com/bitcoin-l2s-are-eating-the-world) | Hackernoon |
+| 💰 [The Bitcoin Renaissance: Unlocking Trillions in Value](https://www.forbes.com/sites/leeorshimron/2024/08/13/the-bitcoin-renaissance-unlocking-trillions-in-value/?ref=stacksblog) | Forbes |
diff --git a/docs/press-and-reports/press-and-top-links/2024/december-2024.md b/docs/press-and-reports/press-and-top-links/2024/december-2024.md
new file mode 100644
index 0000000000..cfd6bdf387
--- /dev/null
+++ b/docs/press-and-reports/press-and-top-links/2024/december-2024.md
@@ -0,0 +1,20 @@
+# December 2024
+
+| Article | Outlet / Author |
+| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------- |
+| 🧡 [Portal Ventures, the Leading Pre-seed VC Firm and the First to Call the Bitcoin Thesis, to Back sBTC](https://www.theblock.co/post/329292/portal-ventures-the-leading-pre-seed-vc-firm-and-the-first-to-call-the-bitcoin-thesis-to-back-sbtc?ref=stacksblog) | The Block |
+| 🧡 [LearnWeb3, the Largest Educational Platform for Web3, Set to Onboard New Wave of sBTC Developers](https://www.theblock.co/post/330037/learnweb3-the-largest-educational-platform-for-web3-set-to-onboard-new-wave-of-sbtc-developers) | The Block |
+| 🧡 [Xverse, Leading Bitcoin Ecosystem Wallet, Adopts sBTC as Preferred Scaling Solution for the Bitcoin Economy](https://www.theblock.co/post/330649/xverse-leading-bitcoin-ecosystem-wallet-adopts-sbtc-as-preferred-scaling-solution-for-the-bitcoin-economy) | The Block |
+| 🧡 [Hex Trust Expands Collaboration with Stacks Asia Foundation to Bolster sBTC Adoption](https://blockchainreporter.net/hex-trust-expands-collaboration-with-stacks-asia-foundation-to-bolster-sbtc-adoption/) | Blockchain Reporter |
+| 🧡 [Fordefi, the First MPC Wallet to Fully Support Bitcoin DeFi, Joins Cohort of sBTC Backers](https://www.theblock.co/post/331016/fordefi-the-first-mpc-wallet-to-fully-support-bitcoin-defi-joins-cohort-of-sbtc-backers) | The Block |
+| 🧡 [Travala, The #1 Bitcoin and Crypto Travel Booking Portal, Announces Support for sBTC and STX](https://www.theblock.co/post/331020/travala-the-1-bitcoin-and-crypto-travel-booking-portal-announces-support-for-sbtc-and-stx) | The Block |
+| 🚀 [Double-dipping with sBTC on Stacks](https://blockworks.co/news/stacks-sbtc-double-dipping) | Blockworks |
+| 🚀 [Bitcoin Gets DeFi Upgrade: Stacks Launches Bitcoin-Backed sBTC for Smart Contracts](https://hackernoon.com/bitcoin-gets-defi-upgrade-stacks-launches-bitcoin-backed-sbtc-for-smart-contracts) | Hackernoon |
+| 🚀 [sBTC Launches on Stacks Mainnet, Bringing Bitcoin DeFi to Life](https://beincrypto.com/sbtc-launches-on-stacks-mainnet/) | BeInCrypto |
+| 🚀 [sBTC Launches on Stacks Mainnet With Deposit-Only Functionality](https://cryptopotato.com/sbtc-launches-on-stacks-mainnet-with-deposit-only-functionality/?amp) | Crypto Potato |
+| 🚀 [Stacks Launches sBTC on Mainnet with 1,000 BTC Cap, Offering 5% Yield and Up to 60% APY Staking](https://thedefiant.io/news/blockchains/stacks-launches-sbtc-on-mainnet-1000-btc-cap-offering-5-yield-up-to-60-apy-b70deae1) | The Defiant |
+| 🚀 [sBTC Kicks Off on Stacks Mainnet: Details](https://u.today/sbtc-kicks-off-on-stacks-mainnet-details) | Crypto Economy |
+| 🟧 [Bitcoin's Memecoin-Like 'Runes' Get a Boost With AMM Launch on Stacks](https://www.coindesk.com/tech/2024/12/18/bitcoins-memecoin-like-runes-get-a-boost-with-amm-launch-on-stacks) | Coindesk |
+| 🧡 [Ankr, the #1 Provider of Bitcoin-Secured, Physical Infrastructure, Becomes Signer for Stacks as sBTC Launches](https://www.theblock.co/post/331411/ankr-the-1-provider-of-bitcoin-secured-physical-infrastructure-becomes-signer-for-stacks-as-sbtc-launches) | The Block |
+| 📙 [New Report Finds Tokenized BTC Landscape Worth $1T (18 Dec)](https://coinmarketcap.com/community/articles/6762f62b09984e48933a1ec1/) | CoinMarketCap |
+| 📙 [New Report Finds Tokenized BTC Landscape Worth $1T (18 Dec)](https://www.binance.com/en/square/post/17739664161346) | Binance |
diff --git a/docs/press-and-reports/press-and-top-links/2024/february-2024.md b/docs/press-and-reports/press-and-top-links/2024/february-2024.md
new file mode 100644
index 0000000000..a2a259bca6
--- /dev/null
+++ b/docs/press-and-reports/press-and-top-links/2024/february-2024.md
@@ -0,0 +1,33 @@
+# February 2024
+
+_For weekly stories delivered to your inbox, subscribe to_ [Stacks Snacks](https://stackssnacks.com/). _For quarterly ecosystem recaps, subscribe to the_ [Stacks Foundation newsletter](https://newsletters.stacks.org/).
+
+
+
+📊 Messari's Q4 2023 'State of Stacks' Report
+
+[https://messari.io/report/state-of-stacks-q4-2023](https://messari.io/report/state-of-stacks-q4-2023)
+
+**Key Insights**
+
+* **Stacks revenue (USD) increased 3,386% QoQ and 3,028% YoY to $637,000.** Much of this revenue was driven by inscription protocol STX20.
+* **STX’s market cap increased 203% QoQ and 598% YoY to $2.0 billion.** STX’s growth outpaced BTC and the overall crypto market.
+* **DeFi TVL (USD) increased 363% QoQ and 763% YoY to $61 million.** ALEX firmly remained the leader in TVL, but Arkadiko and StackingDAO considerably increased their own TVL dominance in Q3 and Q4.
+* **Average daily miner revenue increased 1,015% YoY to $78,000.** STX’s price increase and Stacks’ increased revenue made it significantly more profitable for Bitcoin miners to participate in Stacks’ consensus.
+* **The Nakamoto upgrade is expected in April 2024.** This update will enable faster blocks, give transactions 100% Bitcoin finality, reduce MEV, and eliminate forking on the Stacks layer to set the stage for the upcoming sBTC release.
+
+
+
+| Title | Outlet/Author |
+| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------- |
+| 🌱 [The Year Ahead](https://panteracapital.com/blockchain-letter/the-year-ahead-2024/) | Pantera Blockchain Letter |
+| 📊 [Q1 2024 Bitcoin ecosystem map](https://flight.beehiiv.net/v2/clicks/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1cmwiOiJodHRwczovL3R3aXR0ZXIuY29tL3NvcmFfdmVudHVyZXMvc3RhdHVzLzE3NTQ2ODc4ODg3NTgwODM5MjI_dXRtX3NvdXJjZT1zdGFja3NzbmFja3MuY29tJnV0bV9tZWRpdW09cmVmZXJyYWwmdXRtX2NhbXBhaWduPWFsZXgtZ292ZXJuYW5jZS1wcm9wb3NhbC1mb3IteGxuay1zdGFja2luZy1kYW8taGl0cy0zNW0taW4tdHZsIiwicG9zdF9pZCI6IjQ1NTY3YzAzLWFkZDUtNGQzNi1iZGM2LTk4Y2YwYzkyMDA5YyIsInB1YmxpY2F0aW9uX2lkIjoiM2NmYWJmY2MtMTQ1OS00NDUwLTgyNzAtYjhiZjNkZDJhYjk3IiwidmlzaXRfdG9rZW4iOiJkMTQ0MDViYi1jMTlhLTQyYmItOTRkMS02ODJkYjc2ZDlkN2UiLCJpYXQiOjE3MDgwOTcxMjksImlzcyI6Im9yY2hpZCJ9.Ga_H469MIGKuovy5WVHfd3Fit9x6IiqAr0qhNCW575E) | Sora Ventures |
+| 🪴 [Peak Total Value Locked (TVL) and Rising Developer Engagement on Stacks](https://twitter.com/HouseofChimera/status/1757792122692911207?ref=stacksblog) | House of Chimera |
+| 📊 [40% of Bitcoin developers are working on Bitcoin L2s](https://twitter.com/MohamedFFouda/status/1752407779640295480?s=20\&utm_source=stackssnacks.com\&utm_medium=referral\&utm_campaign=nakamoto-release-launch-date-velar-raises-3-5m-in-funding-round) | Mohamed Fouda |
+| 📈 [Bitcoin is 25% below its record high -- but Layer 2 Stacks is even closer](https://blockworks.co/news/layer-2-stacks-approaching-bitcoin?ref=stacksblog) | Blockworks |
+| 👛 Stacks L2 DeFi protocol [Velar raises $3.5M](https://flight.beehiiv.net/v2/clicks/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1cmwiOiJodHRwczovL3d3dy5jb2luZGVzay5jb20vYnVzaW5lc3MvMjAyNC8wMi8wMS9jcnlwdG8tc3RhcnR1cC12ZWxhci1wbGFucy1wZXJwZXR1YWwtc3dhcHMtZXhjaGFuZ2UtZm9yLWJpdGNvaW4tZGVmaS1hZnRlci1yYWlzaW5nLTMtNW0vPXR1dG1fc291cmNlPXN0YWNrc3NuYWNrcy5jb20mdXRtX21lZGl1bT1yZWZlcnJhbCZ1dG1fY2FtcGFpZ249bmFrYW1vdG8tcmVsZWFzZS1sYXVuY2gtZGF0ZS12ZWxhci1yYWlzZXMtMy01bS1pbi1mdW5kaW5nLXJvdW5kIiwicG9zdF9pZCI6ImYxODVmMmM4LTM0ZTQtNDM0My1hMWFkLTM4YmRlODAyYzY0OCIsInB1YmxpY2F0aW9uX2lkIjoiM2NmYWJmY2MtMTQ1OS00NDUwLTgyNzAtYjhiZjNkZDJhYjk3IiwidmlzaXRfdG9rZW4iOiJkMTQ0MDViYi1jMTlhLTQyYmItOTRkMS02ODJkYjc2ZDlkN2UiLCJpYXQiOjE3MDgwOTcyNDUsImlzcyI6Im9yY2hpZCJ9.FjGMmkbPat9qWNoUR5SJsfnwDWqfUQutXW-ScvveCjc) | Coindesk |
+| 📊 Report: [Stacks could present a $90 Billion opportunity](https://flight.beehiiv.net/v2/clicks/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1cmwiOiJodHRwczovL3R3aXR0ZXIuY29tL1RhbmdDaGFuMHgvc3RhdHVzLzE3NTM0MTcyNDMxMzUwMTMwMTA_dD05N19DMkItaTJqZi11OGgwZEpWV2NBJnM9MzMmdXRtX3NvdXJjZT1zdGFja3NzbmFja3MuY29tJnV0bV9tZWRpdW09cmVmZXJyYWwmdXRtX2NhbXBhaWduPW5ha2Ftb3RvLXJlbGVhc2UtbGF1bmNoLWRhdGUtdmVsYXItcmFpc2VzLTMtNW0taW4tZnVuZGluZy1yb3VuZCIsInBvc3RfaWQiOiJmMTg1ZjJjOC0zNGU0LTQzNDMtYTFhZC0zOGJkZTgwMmM2NDgiLCJwdWJsaWNhdGlvbl9pZCI6IjNjZmFiZmNjLTE0NTktNDQ1MC04MjcwLWI4YmYzZGQyYWI5NyIsInZpc2l0X3Rva2VuIjoiZDE0NDA1YmItYzE5YS00MmJiLTk0ZDEtNjgyZGI3NmQ5ZDdlIiwiaWF0IjoxNzA4MDk3MjQ1LCJpc3MiOiJvcmNoaWQifQ.dons_3VaS_GyWvr5OZs-StFlDP-PX2ToMqIVB9pGVCQ) | Tang Chan |
+| 📊 [ABCDE 2024 BTC Recap](https://flight.beehiiv.net/v2/clicks/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1cmwiOiJodHRwczovL3R3aXR0ZXIuY29tL0FCQ0RFTGFicy9zdGF0dXMvMTc0MDYyNzc3NTg2MDcyNzkxOT90PUo1ODlrWGtMNGlOblFJRXZyRW55TXcmcz0zMyZ1dG1fc291cmNlPXN0YWNrc3NuYWNrcy5jb20mdXRtX21lZGl1bT1yZWZlcnJhbCZ1dG1fY2FtcGFpZ249bmFrYW1vdG8tcmVsZWFzZS1sYXVuY2gtZGF0ZS12ZWxhci1yYWlzZXMtMy01bS1pbi1mdW5kaW5nLXJvdW5kIiwicG9zdF9pZCI6ImYxODVmMmM4LTM0ZTQtNDM0My1hMWFkLTM4YmRlODAyYzY0OCIsInB1YmxpY2F0aW9uX2lkIjoiM2NmYWJmY2MtMTQ1OS00NDUwLTgyNzAtYjhiZjNkZDJhYjk3IiwidmlzaXRfdG9rZW4iOiJkMTQ0MDViYi1jMTlhLTQyYmItOTRkMS02ODJkYjc2ZDlkN2UiLCJpYXQiOjE3MDgwOTcyNDUsImlzcyI6Im9yY2hpZCJ9.qhu0w9pHUMhY5ASnL74i7ixBbVw7LRrF3MJGJDbcoAs) | ABCDE Labs |
+| 👀 [2024 Halving: This Time It’s Actually Different](https://www.grayscale.com/research/reports/2024-halving-this-time-its-actually-different?ref=stacksblog) | Grayscale |
+| 📈 [While everyone theorizes about when $BTC will make new highs, $STX...](https://x.com/cburniske/status/1757951005654978872?t=_cLI0sby6lmp9V1Yj6-6kQ\&s=33\&ref=stacksblog) | Chris Burniske |
+| [What Are Bitcoin Layer 2 Networks?](https://academy.binance.com/en/articles/what-are-bitcoin-layer-2-networks?viastacksblog\&ref=stacksblog) | Binance Academy |
diff --git a/docs/press-and-reports/press-and-top-links/2024/january-2024.md b/docs/press-and-reports/press-and-top-links/2024/january-2024.md
new file mode 100644
index 0000000000..773d8ffad9
--- /dev/null
+++ b/docs/press-and-reports/press-and-top-links/2024/january-2024.md
@@ -0,0 +1,15 @@
+# January 2024
+
+For weekly stories delivered to your inbox, subscribe to [Stacks Snacks](https://stackssnacks.com/). For quarterly ecosystem recaps, subscribe to the [Stacks Foundation newsletter](https://newsletters.stacks.org/).
+
+
+
+📙 Bitcoin Layers Report by Spartan Group
+
+**Tapestry of a Trustless Financial Era**
+
+Diving deep into the layers of Bitcoin's blossoming ecosystem, the first edition of the Bitcoin Layers Report unveils the emerging reality of a financial world where trust is embedded in technology rather than institutions. As Bitcoin evolves beyond a Store of Value, we stand on the cusp of a revolution in trustless finance and a new era of economic possibilities. [https://bitcoinlayersreport.com/](https://bitcoinlayersreport.com/)
+
+
+
+
diff --git a/docs/press-and-reports/press-and-top-links/2024/july-2024.md b/docs/press-and-reports/press-and-top-links/2024/july-2024.md
new file mode 100644
index 0000000000..9738d92a0d
--- /dev/null
+++ b/docs/press-and-reports/press-and-top-links/2024/july-2024.md
@@ -0,0 +1,21 @@
+---
+description: >-
+ Bitcoin Summer continued in July: BitGo stepped up to join the Stacks signer
+ network, Stacks teams Bitflow and Hermetica landed their own media and
+ builders everywhere convened in Nashville.
+---
+
+# July 2024
+
+| Title | Outlet / Author |
+| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------- |
+| 📈 [All Time High in Monthly Active Accounts for Stacks](https://app.signal21.io/stacks?utm_source=stackssnacks.com\&utm_medium=referral\&utm_campaign=all-time-high-in-monthly-active-accounts-for-stacks) | Signal21 |
+| 💎 [Bitflow Unveils Liquidity Hub Upgrade, Enabling Functionality Like Ethereum DeFi](https://blockchainreporter.net/bitflow-unveils-liquidity-hub-upgrade-enabling-functionality-like-ethereum-defi/) | Blockchain Reporter |
+| 💎 [Bitflow’s Liquidity Hub Elevates Bitcoin DeFi to Ethereum DeFi Ecosystem Standard](https://coinmarketcap.com/community/articles/667c6188dd97c85264ba1fc1/) | CoinMarketCap |
+| [Hermetica's Synthetic Dollar Sparks DeFi Revolution](https://hackernoon.com/hermeticas-synthetic-dollar-sparks-defi-revolution?ref=stacksblog) | Hackernoon |
+| 🛡️ [Hypernative Bolsters Bitcoin L2 Security as Stacks Ecosystem Gets Real-Time Protection](https://hackernoon.com/hypernative-bolsters-bitcoin-l2-security-as-stacks-ecosystem-gets-real-time-protection) | Hackernoon |
+| 🎫 [Bitcoin Builders Conference Set to Spotlight Innovation and the Future of the Bitcoin Economy](https://decrypt.co/239086/bitcoin-builders-conference-set-to-spotlight-innovation-and-the-future-of-the-bitcoin-economy) | Decrypt |
+| 🪙 [Bitcoin Developers Launch BTC-Backed Stablecoin As Rune Token](https://decrypt.co/239925/bitcoin-developers-launch-btc-backed-stablecoin-as-rune-token) | Decrypt |
+| 📰 [BitGo integrates Stacks for Bitcoin rewards, following institutional Bitcoin demand](https://cointelegraph.com/news/bitgo-stacks-bitcoin-rewards-institutional-bitcoin-demand) | CoinTelegraph |
+| 📰 [BitGo Launches Support for Bitcoin L2 Stacks and sBTC](https://cryptopotato.com/bitgo-launches-support-for-bitcoin-l2-stacks-and-sbtc/?amp) | Crypto Potato |
+| 🟧 [Protocol Village: Bitrue Ventures Launches $40M Fund for 'Nascent Web3 Companies'](https://www.coindesk.com/tech/2024/07/17/protocol-village/) | Coindesk |
diff --git a/docs/press-and-reports/press-and-top-links/2024/june-2024.md b/docs/press-and-reports/press-and-top-links/2024/june-2024.md
new file mode 100644
index 0000000000..35069d5129
--- /dev/null
+++ b/docs/press-and-reports/press-and-top-links/2024/june-2024.md
@@ -0,0 +1,13 @@
+# June 2024
+
+| Title | Outlet/Author |
+| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------- |
+| 📊 [Layer-2 Networks Mark The Dawn Of A New Golden Age For Bitcoin](https://www.analyticsinsight.net/cryptocurrency-analytics-insight/layer-2-networks-mark-the-dawn-of-a-new-golden-age-for-bitcoin?ref=stacksblog) | Analytics Insight |
+| 📈 [Stacks Layer 2 for Bitcoin already hosts projects, STX token among top gainers](https://www.cryptopolitan.com/stacks-layer-2-bitcoin-stx-token-top-gainers/?ref=stacksblog) | Cryptopolitan |
+| 📖 [Top Bitcoin Layer 2 Projects & Coins in 2024](https://cryptonews.com/cryptocurrency/bitcoin-layer-2-projects/?ref=stacksblog/) | Cryptonews |
+| 📖 [Layer-2 Networks Mark The Dawn Of A New Golden Age For Bitcoin](https://www.analyticsinsight.net/cryptocurrency-analytics-insight/layer-2-networks-mark-the-dawn-of-a-new-golden-age-for-bitcoin) | Analytics Insight |
+| 🧩 [Haruko Integrates Stacks to Deliver Institutional Asset Management on Bitcoin L2](https://www.financemagnates.com/thought-leadership/haruko-integrates-stacks-to-deliver-institutional-asset-management-on-bitcoin-l2/) | Finance Magnates |
+| 🧩 [Haruko to enhance digital asset management with Stacks integration](https://finbold.com/haruko-to-enhance-digital-asset-management-with-stacks-integration/) | Finbold |
+| 🧩 [Haruko to Streamline Bitcoin Asset Management With Stacks Integration](https://u.today/haruko-to-streamline-bitcoin-asset-management-with-stacks-integration) | U Today |
+| 💲 [Stacking DAO Bi-Weekly Update: $560k in Stacking rewards over two cycles](https://medium.com/@stackingdao/stacking-dao-bi-weekly-update-560k-in-stacking-rewards-over-two-cycles-c012256c1622) | Medium |
+| 🧩 [Kiln: We're thrilled to unveil our latest integration](https://x.com/Kiln_finance/status/1797612820537729354?ref=stacksblog) | Kiln |
diff --git a/docs/press-and-reports/press-and-top-links/2024/march-2024.md b/docs/press-and-reports/press-and-top-links/2024/march-2024.md
new file mode 100644
index 0000000000..c135319f4c
--- /dev/null
+++ b/docs/press-and-reports/press-and-top-links/2024/march-2024.md
@@ -0,0 +1,9 @@
+# March 2024
+
+* 🔏 [Bitcoin layer-2 Stacks partners with eight companies ahead of its Nakamoto upgrade](https://cryptobriefing.com/stacks-network-expansion-new-signers/) — Crypto Briefing
+* 🤝 [Stacks expands with Blockdaemon, Near Foundation amid Bitcoin surge](https://cointelegraph.com/news/stacks-welcomes-new-signers-blockdaemon-near-foundation-bitcoin-surge) — Cointelegraph
+* 📈 [More Validation for Bitcoin Builders: Industry Leaders to Integrate Stacks, the Leading Bitcoin L2](https://www.benzinga.com/pressreleases/24/03/37487866/more-validation-for-bitcoin-builders-industry-leaders-to-integrate-stacks-the-leading-bitcoin-l2) — Benzinga
+* 💼 [Bitcoin layer-2 Stacks partners with eight companies ahead of its Nakamoto upgrade](https://www.coindesk.com/tech/2024/04/16/og-bitcoin-l2-stacks-is-getting-a-major-overhaul/) — Coindesk
+* 🔏 [Stacks L2 Bolsters Network Security with 8 New Signers](https://www.cryptotimes.io/2024/03/06/stacks-l2-bolsters-network-security-with-8-new-signers/) — The Crypto Times
+* 📈 [Stacks: The Nakamoto Upgrade](https://twitter.com/FTI_DA/status/1771166481880944693?utm_source=stackssnacks.com\&utm_medium=referral\&utm_campaign=franklin-templeton-highlights-the-nakamoto-release-velar-amm-mainnet) — Franklin Templeton
+* 🪴 [Stacks reaches 1,000,000 unique wallets](https://flight.beehiiv.net/v2/clicks/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1cmwiOiJodHRwczovL3R3aXR0ZXIuY29tL1N0YWNrcy9zdGF0dXMvMTc2NTg2NTQzOTc2OTMwNTU3MT91dG1fc291cmNlPXN0YWNrc3NuYWNrcy5jb20mdXRtX21lZGl1bT1yZWZlcnJhbCZ1dG1fY2FtcGFpZ249bmFrYW1vdG8tcmVsZWFzZS12b3RpbmctcGVyaW9kLWVuZHMtY2VsZWJyYXRpbmctb25lLW1pbGxpb24tdW5pcXVlLXdhbGxldHMiLCJwb3N0X2lkIjoiYTY0NTBlYTAtY2U4MC00ZjRlLTg0YjMtNjNmNWFhNzRiMTY1IiwicHVibGljYXRpb25faWQiOiIzY2ZhYmZjYy0xNDU5LTQ0NTAtODI3MC1iOGJmM2RkMmFiOTciLCJ2aXNpdF90b2tlbiI6ImRhZTNjOGUxLWVkZTUtNDQxMC1hNWFkLTU3MTc2NmYyMGQ3OSIsImlhdCI6MTcxMzcyNTM5MiwiaXNzIjoib3JjaGlkIn0.allLoCyKRwaGltRK4_zwV80JFbHr6s8SGxr7zPwSZ44) — Signal21
diff --git a/docs/press-and-reports/press-and-top-links/2024/may-2024.md b/docs/press-and-reports/press-and-top-links/2024/may-2024.md
new file mode 100644
index 0000000000..393a1a7ef7
--- /dev/null
+++ b/docs/press-and-reports/press-and-top-links/2024/may-2024.md
@@ -0,0 +1,20 @@
+# May 2024
+
+| Title | Outlet/Author |
+| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------- |
+| [👀 Stacks active accounts reach record high amid growing interest in Bitcoin DeFi](https://cointelegraph.com/news/bitcoin-defi-surge-stacks-l2-record-users) | Cointelegraph |
+| [🗞️ Newsletter: BTC’s Streak Is Coming To An End](https://milkroad.com/daily/btcs-streak-is-coming-to-an-end-%EF%B8%8F/?ref=stacksblog) | Milkroad |
+| [📕 The Imperative for Bitcoin Layers](https://chorus.one/articles/the-imperative-for-bitcoin-layers-2?ref=stacksblog) | Chorus One |
+| [First Bitcoin-backed synthetic dollar to launch with 25% yield](https://cointelegraph.com/news/hermetica-usdh-bitcoin-backed-synthetic-dollar) | Cointelegraph |
+| [🔗 Stacks, Moonriver, Hedera Network and Iron Fish Join Axelar’s Interchain Amplifier](https://cryptonews.com/news/stacks-hedera-network-and-iron-fish-join-axelar-interchain.htm) | Crypto News |
+| [🔗 Axelar Integrates With Stacks To Bridge Bitcoin Across Over 65 Blockchains](https://cryptodaily.co.uk/news-in-crypto/coincodex:axelar-integrates-with-stacks-to-bridge-bitcoin-across-over-65-blockchains) | Crypto Daily UK |
+| 🌱 [LunarCrush Unveils AI-Driven Web3 Platform for Creators](https://www.altcoinbuzz.io/cryptocurrency-news/lunarcrush-unveils-ai-driven-web3-platform-for-creators/) | Altcoin Buzz |
+| [Despite Bitcoin price volatility, factors point to BTC’s long-term success](https://cointelegraph.com/news/bitcoin-price-volatility-btc-success) | CoinTelegraph |
+| [Satoshi’s Vision Or Not, Bitcoin DeFi Is Here To Stay](https://www.thestreet.com/crypto/markets/satoshis-vision-or-not-bitcoin-defi-is-here-to-stay-) | The Street |
+| [📣 Stacks Foundation joins Uphold to drive Bitcoin adoption](https://www.binance.com/en/square/post/8093584158561) | Binance Square |
+| [Stacks & Uphold Team Up to Boost Bitcoin Beyond Just a Store of Value](https://coinpaper.com/4190/stacks-and-uphold-team-up-to-boost-bitcoin-beyond-just-a-store-of-value) | Coinpaper |
+| [Stacks and Uphold Partner Up to Boost Bitcoin Adoption](https://coinmarketcap.com/community/articles/66437419d7905c7145a4c38e/) | CoinMarketCap |
+| [Stacks & Uphold Team Up to Boost Bitcoin Beyond Just a Store of Value](https://coinstats.app/news/e879f032aa90aad3a51213254a35691ddc897bbfc7200d3d95b95ff87bb4ca0e_Stacks-%26-Uphold-Team-Up-to-Boost-Bitcoin-Beyond-Just-a-Store-of-Value/) | CoinStats |
+| [Stacks Foundation joins Uphold to drive Bitcoin adoption](https://www.coinlive.com/id/news-flash/514530) | CoinLive |
+| [Stacks Partners With Uphold To Further Increase Bitcoin Adoption](https://www.investingcube.com/stacks-partners-with-uphold-to-further-increase-bitcoin-adoption/) | InvestingCube |
+| [Stacks and Uphold Partner Up to Boost Bitcoin Adoption](https://www.cryptotimes.io/2024/05/14/stacks-and-uphold-partner-up-to-boost-bitcoin-adoption/) | Crypto Times |
diff --git a/docs/press-and-reports/press-and-top-links/2024/november-2024.md b/docs/press-and-reports/press-and-top-links/2024/november-2024.md
new file mode 100644
index 0000000000..feb35d0bdf
--- /dev/null
+++ b/docs/press-and-reports/press-and-top-links/2024/november-2024.md
@@ -0,0 +1,8 @@
+# November 2024
+
+| Article | Outlet / Author |
+| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------- |
+| 🧡 [CoinFlip, the #1 Global Bitcoin ATM Network Is Making Programmable Bitcoin More Accessible with Stacks, the Leading Bitcoin L2](https://www.theblock.co/post/327328/coinflip-the-1-global-bitcoin-atm-network-is-making-programmable-bitcoin-more-accessible-with-stacks-the-leading-bitcoin-l2) | TheBlock |
+| 🧡 [Leading Crowdsourced Security Platform Immunefi Teams Up with Asymmetric Research & Bitcoin L2 Labs to Bolster sBTC Security](https://www.theblock.co/post/326835/leading-crowdsourced-security-platform-immunefi-teams-up-with-asymmetric-research-bitcoin-l2-labs-to-bolster-sbtc-security) | TheBlock |
+| 🧡 [CoinFlip, the #1 Global Bitcoin ATM Network Is Making Programmable Bitcoin More Accessible with Stacks, the Leading Bitcoin L2](https://coinmarketcap.com/community/articles/673e0069c291c94bd18e68fb/) | CoinMarketCap |
+| 🧡 [Bitcoin Frontier Fund, Home of the Top Bitcoin Accelerator, To Invest in Teams Built on sBTC](https://www.theblock.co/post/328240/bitcoin-frontier-fund-home-of-the-top-bitcoin-accelerator-to-invest-in-teams-built-on-sbtc) | TheBlock |
diff --git a/docs/press-and-reports/press-and-top-links/2024/october-2024.md b/docs/press-and-reports/press-and-top-links/2024/october-2024.md
new file mode 100644
index 0000000000..9997e79848
--- /dev/null
+++ b/docs/press-and-reports/press-and-top-links/2024/october-2024.md
@@ -0,0 +1,11 @@
+# October 2024
+
+| Article | Outlet/Author |
+| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------- |
+| 🚀 [Stacks fortifies Bitcoin ties with Nakamoto upgrade](https://blockworks.co/news/stacks-sbtc-bitcoin-alignment-nakamoto?ref=stacksblog) | Blockworks |
+| 🚀 [Stacks, Prominent Bitcoin Layer-2 Project, Activates Long-Awaited 'Nakamoto' Upgrade](https://www.coindesk.com/tech/2024/10/29/stacks-prominent-bitcoin-layer-2-project-activates-long-awaited-nakamoto-upgrade/?ref=stacksblog) | Coindesk |
+| 🤝 [Asymmetric Research Joins Stacks Ecosystem as Security Contributor to Bitcoin L2](https://hackernoon.com/asymmetric-research-joins-stacks-ecosystem-as-security-contributor-to-bitcoin-l2) | Hackernoon |
+| 🟧 [A Beginner's Guide to Bitcoin Layers](https://www.hiro.so/blog/read-a-beginners-guide-to-bitcoin-layers?ref=stacksblog) | Hiro |
+| 🌱 [Bitcoin-backed stablecoin developer Hermetica raises $1.7M in seed funding](https://www.theblock.co/post/321141/bitcoin-backed-stablecoin-developer-hermetica-raises-1-7-million-in-seed-funding?ref=stacksblog) | The Block |
+| 🌱 [Blockstream raises $210M to accelerate Bitcoin adoption](https://subscribe.bitcoinbuildersassociation.com/p/blockstream-raises-210m-to-accelerate?ref=stacksblog) | Bitcoin Builders Association |
+| 🟧 [BoostVC, Draper Associates, and Thesis Announce BitcoinFi Accelerator](https://subscribe.bitcoinbuildersassociation.com/p/boostvc-draper-associates-and-thesis?ref=stacksblog) | Bitcoin Builders Association |
diff --git a/docs/press-and-reports/press-and-top-links/2024/september-2024.md b/docs/press-and-reports/press-and-top-links/2024/september-2024.md
new file mode 100644
index 0000000000..571e6f2805
--- /dev/null
+++ b/docs/press-and-reports/press-and-top-links/2024/september-2024.md
@@ -0,0 +1,16 @@
+# September 2024
+
+| Article | Outlet / Author |
+| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------- |
+| 📈 [New Milestone for Bitcoin DeFi: Over 1,400 Smart Contracts Deployed on Stacks](https://coinchapter.com/new-milestone-for-bitcoin-defi-over-1400-smart-contracts-deployed-on-stacks-even-before-major-upgrade/) | Coin Chapter |
+| 📈 [Bitcoin layer-2 Stacks witnessed 1,400 smart contract deployments month over month](https://www.livebitcoinnews.com/stacks-registers-unseen-smart-contract-deployment-days-away-from-its-nakamoto-upgrade/) | Live Bitcoin News |
+| 🗞️ [Stacks' smart contracts reach record high ahead of Nakamoto upgrade](https://cointelegraph.com/news/stacks-record-smart-contracts-nakamoto-upgrade?ref=stacksblog) | Cointelegraph |
+| 🤝🏻 [Anchorage Digital Announces Custody Support for Stacks](https://x.com/Stacks/status/1831335327300309174?utm_source=stackssnacks.com\&utm_medium=referral\&utm_campaign=anchorage-digital-supporting-stacks-btc-bash-and-other-highlights) | X / Anchorage Digital |
+| 🚀 [Hermetica Labs Launches USDh, the first Bitcoin-native synthetic USD](https://cryptobriefing.com/bitcoin-synthetic-dollar-25-percent-yield/?ref=stacksblog) | Crypto Briefing |
+| 💡 [What is sBTC? A Guide to the Non-Custodial Native Bitcoin DeFi](https://www.xverse.app/blog/what-is-sbtc?ref=stacksblog) | Xverse |
+| ₿ [Over $1.5B worth of BTC is now locked in Bitcoin Layers](https://subscribe.bitcoinbuildersassociation.com/p/over-15b-worth-of-btc-is-now-locked?ref=stacksblog) | Bitcoin Builders Association |
+| 🤝 [Stacks x Aptos Foundations Join Forces to Bring Bitcoin to Aptos Network via sBTC](https://decrypt.co/249825/bitcoin-stacks-l2-brings-its-sbtc-to-the-aptos-network) | Decrypt |
+| 🖼️ [Gamma's United Bitcoin Ordinals and Stacks Platform Enters Beta](https://nftinsider.io/gamma-bitcoin-beta/?ref=stacksblog) | NFT Insider |
+| 🤝 [Tokensoft partners with Stacks Foundation and Bitcoin Frontier Fund to Accelerate Bitcoin Builders](https://cryptobriefing.com/bitcoin-builders-acceleration-partnership/?ref=stacksblog) | Crypto Briefing |
+| 🗞️ [Stacks Asia Foundation Launches with $15M in Funding to Boost Bitcoin Layer-2 Adoption](https://coinmarketcap.com/community/articles/66e2998ae0c16b2dea22b4f1/?ref=stacksblog) | CoinMarketCap |
+| 🚀 [Zest Introduces BTCz, leveraging Babylon and Stacks](https://subscribe.bitcoinbuildersassociation.com/p/zest-introduces-btcz-leveraging-babylon?ref=stacksblog) | Zest |
diff --git a/docs/press-and-reports/press-and-top-links/2025/README.md b/docs/press-and-reports/press-and-top-links/2025/README.md
new file mode 100644
index 0000000000..0a4fd73593
--- /dev/null
+++ b/docs/press-and-reports/press-and-top-links/2025/README.md
@@ -0,0 +1,5 @@
+# 2025
+
+For weekly stories delivered to your inbox, subscribe to [Stacks Snacks](https://stackssnacks.com/). For quarterly ecosystem recaps, subscribe to the [Stacks Foundation newsletter](https://newsletters.stacks.org/).
+
+
diff --git a/docs/press-and-reports/press-and-top-links/2025/april-2025.md b/docs/press-and-reports/press-and-top-links/2025/april-2025.md
new file mode 100644
index 0000000000..eaf41ee051
--- /dev/null
+++ b/docs/press-and-reports/press-and-top-links/2025/april-2025.md
@@ -0,0 +1,12 @@
+# April 2025
+
+| Article Title & Link | Media Outlet |
+| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
+| [🧡 Experts: Gold’s Rise Doesn’t Undermine Bitcoin’s Digital Gold Status](https://news.bitcoin.com/experts-golds-rise-doesnt-undermine-bitcoins-digital-gold-status/) | Bitcoin.com |
+| [🗞️ Veteran crypto exchange Bitfinex bets big on Bitcoin-based DeFi, deepens integration with Stacks](https://u.today/bitfinex-lists-stx-token-by-stacks-becomes-network-signer) | U Today |
+| [🟧 Bitfinex Throws Its Full Weight Behind Bitcoin’s Leading Layer-2 Stacks](https://www.coincarp.com/learn/bitfinex-throws-its-full-weight-behind-bitcoins-leading-layer-2-stacks/) | Coincarp |
+| [🚀 Hex Trust Expands Institutional Support for Stacks (STX) and sBTC Amid Growing Adoption](https://www.dlnews.com/research/external/hex-trust-expands-institutional-support-for-stacks-stx-and-sbtc-amid-growing-adoption/) | DL News |
+| [🟧 Hermetica brings 5% yield to Bitcoin traders on Velar PerpDEX](https://crypto.news/hermetica-brings-5-yield-to-bitcoin-traders-on-velar-perpdex/) | Crypto.News |
+| [🗞️ BitGo Launches Institutional Support for SBTC, Expanding Bitcoin DeFi Accessibility (22 Apr)](https://www.binance.com/en/square/post/23264351434353) | Binance |
+| [🪙 Stacks' STX Is Week's Best Performer as Bitgo Link Seen Boosting Institutional Use](https://www.coindesk.com/markets/2025/04/25/stacks-stx-is-week-s-best-performer-as-bitgo-link-seen-boosting-institutional-use) | Coindesk |
+| [🚀 Stacks Asia bets big on Middle East Bitcoin boom with Abu Dhabi partnership](https://cointelegraph.com/news/stacks-asia-adgm-partnership-boosts-bitcoin-adoption-middle-east) | Cointelegraph |
diff --git a/docs/press-and-reports/press-and-top-links/2025/august-2025.md b/docs/press-and-reports/press-and-top-links/2025/august-2025.md
new file mode 100644
index 0000000000..3ae0a4769c
--- /dev/null
+++ b/docs/press-and-reports/press-and-top-links/2025/august-2025.md
@@ -0,0 +1,5 @@
+# August 2025
+
+| Article Title & Link | Outlet |
+| ----------------------------------------------------------------------------------------------------------------------------- | -------------- |
+| [BTCFi #2: Inside the Infrastructure Layer of BTCFi](https://x.com/Tiger_Research_/status/1957703731308556340?ref=stacksblog) | Tiger Research |
diff --git a/docs/press-and-reports/press-and-top-links/2025/february-2025.md b/docs/press-and-reports/press-and-top-links/2025/february-2025.md
new file mode 100644
index 0000000000..87753f567f
--- /dev/null
+++ b/docs/press-and-reports/press-and-top-links/2025/february-2025.md
@@ -0,0 +1,14 @@
+# February 2025
+
+| Article | Publication / Link |
+| -------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| 🧡 Bitcoin's Correlation With Markets Grows, Challenging 'Safe Haven' Narrative | [Bitcoin.com](http://bitcoin.com/) |
+| 🪙 How sBTC Unlocks Bitcoin DeFi – And Why It Matters | [Coincu.com](http://coincu.com/) |
+| 🟧 sBTC Is Fast Emerging As The Missing Link In Bitcoin’s Cross-Chain Evolution | [Bitcoinist](https://bitcoinist.com/sbtc-is-fast-emerging-as-the-missing-link-in-bitcoins-cross-chain-evolution/) |
+| 🧡 The Overlooked Bitcoin Layer-2 Sector: Why and What to Expect Moving Forward | [Binance](https://www.binance.com/en-IN/square/post/20381520919281) |
+| 🟧 Bitcoin L2 ‘honeymoon phase’ is over, most projects will fail — Muneeb Ali | [CoinTelegraph](https://cointelegraph.com/news/bitcoin-layer2-projects-fade-stacks-muneeb-ali) |
+| 🗞️ Blockchair Launches Stacks Explorer, Enhancing Bitcoin Layer 2 Visibility and sBTC Support | [DL News](https://www.dlnews.com/research/external/blockchair-launches-stacks-explorer-enhancing-bitcoin-layer-2-visibility-and-sbtc-support/) |
+| 🗞️ Blockchair Launches Stacks Explorer, Enhancing Bitcoin Layer 2 Visibility and sBTC Support | [CoinMarketCap](https://coinmarketcap.com/community/articles/67bf2560ae03156d954313b6/) |
+| 🟧 SNZ, UTXO Capital, Jump Crypto Among Leaders to Deposit Early in sBTC, Unlocking Bitcoin DeFi Utility | [Decrypt](https://decrypt.co/307910/snz-utxo-capital-jump-crypto-among-leaders-to-deposit-early-in-sbtc-unlocking-bitcoin-defi-utility) |
+| 🚀 Stacks’ sBTC Sees Rapid Adoption as Second Cap Hits 3,000 BTC Limit | [Bitcoinist](https://bitcoinist.com/stacks-sbtc-sees-rapid-adoption-as-second-cap-hits-3000-btc-limit/) |
+| 🚀 SNZ, UTXO Capital, Jump Crypto Among Leaders to Deposit Early in sBTC, Unlocking Bitcoin DeFi Utility | [DL News](https://www.dlnews.com/research/external/snz-utxo-capital-jump-crypto-among-leaders-to-deposit-early-in-sbtc-unlocking-bitcoin-defi-utility/) |
diff --git a/docs/press-and-reports/press-and-top-links/2025/january-2025.md b/docs/press-and-reports/press-and-top-links/2025/january-2025.md
new file mode 100644
index 0000000000..785cbb435f
--- /dev/null
+++ b/docs/press-and-reports/press-and-top-links/2025/january-2025.md
@@ -0,0 +1,18 @@
+# January 2025
+
+For weekly stories delivered to your inbox, subscribe to [Stacks Snacks](https://stackssnacks.com/). For quarterly ecosystem recaps, subscribe to the [Stacks Foundation newsletter](https://newsletters.stacks.org/).
+
+| Article | Outlet/Publication |
+| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------- |
+| [🧡 Stacks’ Muneeb Ali: Let the Bitcoin L2s Bloom](https://www.coindesk.com/consensus-hong-kong-2025-coverage/2025/01/13/stacks-muneeb-ali-let-the-bitcoin-l2s-bloom) | Coindesk |
+| [🚀 Why Stacks Is Leading the Bitcoin Layer 2 Revolution](https://www.crypto-news-flash.com/why-stacks-is-leading-the-bitcoin-layer-2-revolution/) | Crypto News Flash |
+| [🗞️ Bitcoin-Based Stablecoin USDh Secures $3M in Liquidity](https://www.coindesk.com/tech/2025/01/22/bitcoin-based-stablecoin-usdh-secures-usd3m-in-liquidity) | Coindesk |
+| [🗞️ Hermetica's Bold Move to Dominate Stacks DeFi With its USDh Stablecoin and sBTC Yield Trade Program](https://hackernoon.com/hermeticas-bold-move-to-dominate-stacks-defi-with-its-usdh-stablecoin-and-sbtc-yield-trade-program) | Hackernoon |
+| [🪙 Hermetica Launches New sBTC Yield Product, USDh Liquidity Faces Boost](https://u.today/hermetica-launches-new-sbtc-yield-product-usdh-liquidity-faces-boost) | U Today |
+| [🪙 Hermetica Unveils $sBTC for Yield-Bearing $USDh in Partnership with Zest Protocol](https://blockchainreporter.net/hermetica-unveils-sbtc-for-yield-bearing-usdh-in-partnership-with-zest-protocol/) | Blockchain Reporter |
+| [🪙 USDh set to become the leading stablecoin on Stacks as Hermetica introduces sBTC yield product](https://invezz.com/news/2025/01/23/usdh-set-to-become-the-leading-stablecoin-on-stacks-as-hermetica-introduces-sbtc-yield-product/) | Invezz |
+| [🧡 Making Bitcoin Go Further: How sBTC Is Expanding the Possibilities of DeFi](https://bitcoinist.com/making-bitcoin-go-further-how-sbtc-is-expanding-the-possibilities-of-defi/) | Bitcoinist |
+| [🚀 Bitcoin DeFi: The Most Pivotal Innovation On Bitcoin’s Evolutionary Path](https://www.cryptopolitan.com/bitcoin-defi-the-most-pivotal-innovation-on-bitcoins-evolutionary-path/) | Cryptopolitan |
+| [🟧 Stacks Bridges the Gap to Bitcoin as Strategic US Reserve Materializes](https://www.financemagnates.com/thought-leadership/stacks-bridges-the-gap-to-bitcoin-as-strategic-us-reserve-materializes/) | Finance Magnates |
+| [🗞️ Bitcoin DeFi Protocol Velar Unveils .BTC Name Grant Program for Unified Identities on Stacks](https://cryptopotato.com/bitcoin-defi-protocol-velar-unveils-btc-name-grant-program-for-unified-identities-on-stacks/) | CryptoPotato |
+| [🚀](https://www.crypto-news-flash.com/why-stacks-is-leading-the-bitcoin-layer-2-revolution/) [Bitcoin DeFi: The Most Pivotal Innovation On Bitcoin’s Evolutionary Path](https://www.cryptopolitan.com/bitcoin-defi-the-most-pivotal-innovation-on-bitcoins-evolutionary-path/?ref=stacksblog) | Cryptopolitan |
diff --git a/docs/press-and-reports/press-and-top-links/2025/july-2025.md b/docs/press-and-reports/press-and-top-links/2025/july-2025.md
new file mode 100644
index 0000000000..8e4874aea3
--- /dev/null
+++ b/docs/press-and-reports/press-and-top-links/2025/july-2025.md
@@ -0,0 +1,6 @@
+# July 2025
+
+| Article Title & Link | Outlet |
+| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------- |
+| 📰 [$1.5B Stacks sBTC and STX Adopt Wormhole NTT Standard to Expand Multichain](https://wormhole.com/blog/usd1-5b-stacks-sbtc-and-stx-adopt-wormhole-ntt-standard-to-expand-multichain?ref=stacksblog) | Wormhole Blog |
+| [Top Interop Protocol Wormhole Adds Stacks to Bridge Bitcoin to Multi-Chain DeFi](https://thedefiant.io/news/defi/wormhole-integrates-stacks-tokens-for-multi-chain-bitcoin-defi) | The Defiant |
diff --git a/docs/press-and-reports/press-and-top-links/2025/june-2025.md b/docs/press-and-reports/press-and-top-links/2025/june-2025.md
new file mode 100644
index 0000000000..147803e46b
--- /dev/null
+++ b/docs/press-and-reports/press-and-top-links/2025/june-2025.md
@@ -0,0 +1,7 @@
+# June 2025
+
+| Article Title & Link | Outlet |
+| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------- |
+| 📰 [Stacks to be Showcased at Blockchain and Digital Assets Virtual Investor Conference on June 5](https://www.globenewswire.com/news-release/2025/06/04/3093569/0/en/Stacks-to-be-Showcased-at-Blockchain-and-Digital-Assets-Virtual-Investor-Conference-on-June-5th.html) | Globe Newswire |
+| 🤝 [Copper Launches Support for sBTC](https://www.crowdfundinsider.com/2025/06/241658-digital-assets-copper-introduces-sbtc-stacking-functionality/) | Crowdfund Insider |
+| 🧩 [Hex Trust Adds sBTC Support and SIP-010 Integration](https://bitcolumnist.com/release/hex-trust-integrates-sbtc-via-sip-010-to-enable-institutional-bitcoin-defi-access/) | BitColumnist |
diff --git a/docs/press-and-reports/press-and-top-links/2025/march-2025.md b/docs/press-and-reports/press-and-top-links/2025/march-2025.md
new file mode 100644
index 0000000000..23b8215866
--- /dev/null
+++ b/docs/press-and-reports/press-and-top-links/2025/march-2025.md
@@ -0,0 +1,7 @@
+# March 2025
+
+* 🟧 [America’s Crypto Renaissance: Why Stacks and Bitcoin Layers Are Poised for Growth](https://www.cryptopolitan.com/americas-crypto-renaissance-why-stacks-and-bitcoin-layers-are-poised-for-growth/) — Cryptopolitan
+* 🧡 [Bitcoin Layers and the Path to Universal Utility](https://www.google.com/url?q=https://cfc-stmoritz.com/industry-insights/bitcoin-layers-and-the-path-to-universal-utility?utm_source%3DCfC%2BSt.%2BMoritz%2B-%2BGlobal%2BMailing%2BList%26utm_campaign%3D61bc405f9f-EMAIL_CAMPAIGN_2024_04_03_02_27_COPY_01%26utm_medium%3Demail%26utm_term%3D0_-4a9e5b2e5d-296312470\&sa=D\&source=editors\&ust=1743526707117175\&usg=AOvVaw2GQInrk1FYUbGiwB0hw6Jt) — Cfc Moritz (Kyle Ellicott)
+* 🚀 [Velar PerpDex Launches on Stacks as First Bitcoin-Native Perpetual DEX](https://www.dlnews.com/research/external/velar-perpdex-launches-on-stacks-as-first-bitcoin-native-perpetual-dex/) — DL News
+* 🧡 [Stacks Reaches New All-Time High TVL](https://x.com/signal21btc/status/1902742256068514010) — Signal21
+
diff --git a/docs/press-and-reports/press-and-top-links/2025/may-2025.md b/docs/press-and-reports/press-and-top-links/2025/may-2025.md
new file mode 100644
index 0000000000..d833dcc6ea
--- /dev/null
+++ b/docs/press-and-reports/press-and-top-links/2025/may-2025.md
@@ -0,0 +1,8 @@
+# May 2025
+
+| Article Title & Link | Media Outlet |
+| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------- |
+| 🚀 [Stacks roadmap update and STX surge](https://blockchain.news/flashnews/stacks-announces-new-roadmap-after-nakamoto-and-sbtc-launch-key-updates-for-crypto-traders-in-2025) | Blockchain News |
+| 🤝 [Stacks Asia partners with HEX Trust](https://cointelegraph.com/news/stacks-asia-hex-trust-bitcoin-defi-opportunity) | Cointelegraph |
+| 📈 [STX rallies 30% ahead of mainnet upgrade](https://cointelegraph.com/news/stacks-stx-makes-30-gain-as-mainnet-upgrade-and-stablecoin-launch-approach) | Cointelegraph |
+| 💡 [Tech Expert Predicts $1 Million Bitcoin — 'Only One More 10x Left'](https://www.binance.com/en-IN/square/post/24043258936257) | Binance |
diff --git a/docs/press-and-reports/press-and-top-links/2025/september-2025-1.md b/docs/press-and-reports/press-and-top-links/2025/september-2025-1.md
new file mode 100644
index 0000000000..11da2bfd2f
--- /dev/null
+++ b/docs/press-and-reports/press-and-top-links/2025/september-2025-1.md
@@ -0,0 +1,5 @@
+# October 2025
+
+| Article Title & Link | Outlet |
+| ------------------------------------------------------------------------------------------------------------------------------- | ---------------------- |
+| [Dual Stacking: What It Means for Stackers and the Broader Ecosystem](https://stacks.org/dual-stacking-overview?ref=stacksblog) | Stacks Foundation Blog |
diff --git a/docs/press-and-reports/press-and-top-links/2025/september-2025-2.md b/docs/press-and-reports/press-and-top-links/2025/september-2025-2.md
new file mode 100644
index 0000000000..4c4e3f40af
--- /dev/null
+++ b/docs/press-and-reports/press-and-top-links/2025/september-2025-2.md
@@ -0,0 +1,5 @@
+# November 2025
+
+| Article Title & Link | Outlet |
+| -------------------------------------------------------------------------------------------------------------------------------------- | ----------- |
+| [Stacks to integrate Circle xReserve for USDC interoperability](https://www.stacks.co/blog/stacks-circle-xreserve-usdc?ref=stacksblog) | Stacks Labs |
diff --git a/docs/press-and-reports/press-and-top-links/2025/september-2025.md b/docs/press-and-reports/press-and-top-links/2025/september-2025.md
new file mode 100644
index 0000000000..40690b8583
--- /dev/null
+++ b/docs/press-and-reports/press-and-top-links/2025/september-2025.md
@@ -0,0 +1,6 @@
+# September 2025
+
+| Article Title & Link | Outlet |
+| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------- |
+| [LAB: Africa’s First Bitcoin Layer 2 Development Hub & Incubator](https://stacks.org/let-africa-build?ref=stacksblog) | Stacks Foundation Blog |
+| [Unlocking Bitcoin's value - Will the BTCFi narrative push Stacks to $20?](https://eng.ambcrypto.com/unlocking-bitcoins-value-will-the-btcfi-narrative-push-stacks-stx-to-20/) | AMB Crypto |
diff --git a/docs/reference/.gitbook.yaml b/docs/reference/.gitbook.yaml
new file mode 100644
index 0000000000..b7d427cf03
--- /dev/null
+++ b/docs/reference/.gitbook.yaml
@@ -0,0 +1,17 @@
+root: ./
+
+redirects:
+
+ reference/api: rpc-api.md
+ reference/the-stack: README.md
+ reference/functions: clarity/functions.md
+ reference/keywords: clarity/keywords.md
+ reference/types: clarity/types.md
+ reference/stacks-node-configuration: stacks-node-configuration.md
+ reference/sample-configuration-files: signer-configuration.md
+
+ # example-contracts redirects
+ example-contracts/audited-starter-contracts: clarity/example-contracts/audited-starter-contracts.md
+ example-contracts/bns: clarity/example-contracts/bns.md
+ example-contracts/multi-send: clarity/example-contracts/multi-send.md
+ example-contracts/stacking: clarity/example-contracts/stacking.md
diff --git a/docs/reference/.gitbook/assets/Frame 316124591.jpg b/docs/reference/.gitbook/assets/Frame 316124591.jpg
new file mode 100644
index 0000000000..1dabccaed3
Binary files /dev/null and b/docs/reference/.gitbook/assets/Frame 316124591.jpg differ
diff --git a/docs/reference/.gitbook/assets/image (2).png b/docs/reference/.gitbook/assets/image (2).png
new file mode 100644
index 0000000000..0f36a116df
Binary files /dev/null and b/docs/reference/.gitbook/assets/image (2).png differ
diff --git a/docs/reference/.gitbook/assets/image.png b/docs/reference/.gitbook/assets/image.png
new file mode 100644
index 0000000000..991aad3d4f
Binary files /dev/null and b/docs/reference/.gitbook/assets/image.png differ
diff --git a/docs/reference/README.md b/docs/reference/README.md
new file mode 100644
index 0000000000..daab2b8a5d
--- /dev/null
+++ b/docs/reference/README.md
@@ -0,0 +1,103 @@
+# Developer Stack
+
+source: Hiro Youtube
+
+New to developing on Stacks or looking for a quick reference guide for all the important components and links? You're in the right place.
+
+We'll go over all the building blocks you need to be aware of to build high-quality Stacks dapps. This page exists to serve as a reference to the Stacks developer's tool chest. In addition to the tools below, stacks.co houses an index of [apps, services, and other integrations available on Stacks](https://www.stacks.co/explore/ecosystem?category=All+Teams#tools).
+
+### Building Blocks
+
+#### Clarity
+
+[Clarity](https://app.gitbook.com/s/H74xqoobupBWwBsVMJhK/clarity/overview) is the smart contract language on Stacks. If you want to build the next decentralized social network, DeFi protocol, or any other Stacks dapp, you'll need to know Clarity.
+
+#### Post Conditions
+
+[Post conditions](https://app.gitbook.com/s/H74xqoobupBWwBsVMJhK/transactions/post-conditions) are a cool feature of the Stacks blockchain that allow you to verify the legitimacy of a transaction on the client side before it is executed. This adds an additional layer of defense against malicious smart contracts.
+
+#### Proof of Transfer
+
+[PoX](https://app.gitbook.com/s/H74xqoobupBWwBsVMJhK/stacks-101/proof-of-transfer) is the unique consensus mechanism of Stacks that facilitates new block production and also allows Stackers to earn real Bitcoin yield by participating in locking their STX tokens.
+
+#### Stacking
+
+Speaking of [Stacking](https://app.gitbook.com/s/H74xqoobupBWwBsVMJhK/block-production/stacking), it's the mechanism that helps to secure the Stacks chain and allows Stackers to earn real Bitcoin yield transferred by miners.
+
+#### SIP-009 and SIP-010 Tokens
+
+Fungible and non-fungible tokens in Clarity are defined by [SIP-009](file:///) and [SIP-010](https://github.com/stacksgov/sips/blob/main/sips/sip-010/sip-010-fungible-token-standard.md) standards. You can learn more about how to work with these tokens in the Clarity book.
+
+#### sBTC
+
+[sBTC](https://docs.stacks.co/sbtc) is the trust-minimized 2-way peg for Bitcoin on the Stacks network. sBTC operates as a SIP-010 token and comes with a [stacks.js library](https://docs.stacks.co/build/misc.-guides/sbtc/how-to-use-the-sbtc-js-library-for-bridging) so it's easy for devs to work with. [Utilizing sBTC](https://docs.stacks.co/build/misc.-guides/sbtc/sbtc-builder-quickstart) in your contract is as simple as calling the `sbtc-token` contract's transfer function.
+
+### Tools
+
+#### Wallets
+
+Wallets are a key tool in any web3 ecosystem, and Stacks is no different. There are several options available including:
+
+* [Leather](https://leather.io/)
+* [Xverse](https://www.xverse.app/)
+* [Asigna](https://asigna.io/)
+
+#### Platform
+
+The [Hiro Platform](https://www.hiro.so/platform) is your all-in-one cloud development environment for Stacks development, and is integrated with most of the tools listed below.
+
+It's by far the easiest way to get up and running quickly. Plus, they have SSH integration.
+
+#### Explorer
+
+Every developer needs a block explorer to take a look at information about blocks and transactions being submitted to the chain. You have two choices here: the [Hiro Explorer](https://explorer.hiro.so/) and [STXScan](https://stxscan.co/).
+
+#### API
+
+If you want to interact with or read data from the chain, there's a good chance the [Hiro API](https://docs.hiro.so/stacks-blockchain-api) has an endpoint for that.
+
+#### Stacks.js
+
+[Stacks.js](https://www.hiro.so/stacks-js) is the de-facto JavaScript library for the Stacks ecosystem. There are several packages here that will help you build robust frontends for your applications.
+
+#### Clarinet
+
+All good developer tooling needs a robust, easy-to-use development environment. Enter [Clarinet](https://www.hiro.so/clarinet). Clarinet provides everything you need to write, test, and deploy Clarity smart contracts, including a fully-featured local devnet blockchain.
+
+#### Chainhook
+
+One of the key use cases for Stacks is being able to directly interact with the Bitcoin chain. Hiro's [Chainhook](https://docs.hiro.so/chainhook) makes this easier by providing an IFTTT system for responding and reacting to events on both the Bitcoin and Stacks chains.
+
+#### Stacking Tools
+
+The Degen Lab team has created a [suite of tools](https://stacking.tools/) to make stacking significantly easier including a signer signature generator, a solo stacking dapp to stack without needing to run a signer, and a TypeScript library for mocking stacking functions.
+
+#### Oracles and Price Feeds
+
+DIA and Pyth provide oracle services for the Stacks layer. Find [documentation for DIA here](https://docs.diadata.org/use-nexus-product/nexus/data-delivery-usage/integrated-blockchains/stacks-price-oracles) and learn more about the [developer release of Pyth here](https://www.pyth.network/blog/developer-release-pyth-on-stacks).
+
+### Educational Resources
+
+#### Docs
+
+These docs you are currently looking at are a great place to get a comprehensive view of all things in the Stacks ecosystem, as well as providing some links out to additional resources you'll find helpful.
+
+#### Hiro Docs
+
+Hiro is a key player in the Stacks ecosystem, providing several developer tools to make your life easier. They also publish excellent [guides and docs](https://docs.hiro.so/) to make using these tools a breeze.
+
+#### Clarity Book
+
+The [Clarity Book](https://book.clarity-lang.org/) is the go-to resource for learning how to be a Clarity developer. In it you'll not only get the basics of Clarity but go through several practice projects and learn best practices.
+
+#### LearnWeb3
+
+LearnWeb3 is one of the best education providers in the game. They have recently begun publishing courses as part of their [Stacks Developer Degree](https://learnweb3.io/degrees/stacks-developer-degree/). LearnWeb3 courses will teach you everything you need to know about building Stacks Dapps.
+
+#### EasyA
+
+[EasyA](https://www.easya.io/) is a mobile app with a Stacks course built in. The EasyA app allows you to learn on the go and is a great way to learn the basics of Stacks and Clarity development all directly in their app.
+
+#### Bitcoin Primer
+
+If you're new to Bitcoin, interested in how it works, and how you can build Stacks dapps that interact with it, the [Bitcoin Primer](https://start.bitcoinprimer.dev/) is a great place to start.
diff --git a/docs/reference/SUMMARY.md b/docs/reference/SUMMARY.md
new file mode 100644
index 0000000000..8645b501b6
--- /dev/null
+++ b/docs/reference/SUMMARY.md
@@ -0,0 +1,53 @@
+# Table of contents
+
+* [Developer Stack](README.md)
+
+## Node Operations
+
+* [Stacks Node Configuration](node-operations/stacks-node-configuration.md)
+* [Signer Configuration](node-operations/signer-configuration.md)
+* [RPC API](node-operations/rpc-api.md)
+
+## Clarity
+
+* [Functions](clarity/functions.md)
+* [Keywords](clarity/keywords.md)
+* [Types](clarity/types.md)
+* [Example Contracts](clarity/example-contracts/README.md)
+ * [multi send](clarity/example-contracts/multi-send.md)
+ * [audited starter contracts](clarity/example-contracts/audited-starter-contracts.md)
+ * [stacking](clarity/example-contracts/stacking.md)
+ * [bns](clarity/example-contracts/bns.md)
+
+## Clarinet
+
+* [CLI Reference](clarinet/cli-reference.md)
+
+## Clarinet JS SDK
+
+* [SDK Reference](clarinet-js-sdk/sdk-reference.md)
+* [Browser SDK Reference](clarinet-js-sdk/browser-sdk-reference.md)
+
+## Rendezvous
+
+* [Rendezvous Reference](rendezvous/reference.md)
+
+## Stacks.js
+
+* [@stacks/network](stacks.js/stacks-network.md)
+* [@stacks/connect](stacks.js/stacks-connect.md)
+* [@stacks/transactions](stacks.js/stacks-transactions.md)
+* [sbtc](stacks.js/sbtc.md)
+
+## Nakamoto Upgrade
+
+* [Nakamoto Upgrade Start Here](nakamoto-upgrade/nakamoto-upgrade-start-here.md)
+* [What is the Nakamoto Release?](nakamoto-upgrade/what-is-the-nakamoto-release.md)
+* [Nakamoto in 10 Minutes](nakamoto-upgrade/nakamoto-in-10-minutes.md)
+* [Nakamoto Rollout Plan](nakamoto-upgrade/nakamoto-rollout-plan/README.md)
+ * [Nakamoto for Stackers](nakamoto-upgrade/nakamoto-rollout-plan/nakamoto-for-stackers.md)
+ * [Nakamoto for Exchanges](nakamoto-upgrade/nakamoto-rollout-plan/nakamoto-for-exchanges.md)
+ * [Nakamoto for Stacking Providers](nakamoto-upgrade/nakamoto-rollout-plan/nakamoto-for-stacking-providers.md)
+ * [Nakamoto for App Developers](nakamoto-upgrade/nakamoto-rollout-plan/nakamoto-for-app-developers.md)
+* [Nakamoto Activation Guide for Signers](nakamoto-upgrade/nakamoto-activation-guide-for-signers.md)
+* [Setting Up a Primary Post Nakamoto Testnet Node](nakamoto-upgrade/setting-up-a-primary-post-nakamoto-testnet-node.md)
diff --git a/docs/reference/clarinet-js-sdk/browser-sdk-reference.md b/docs/reference/clarinet-js-sdk/browser-sdk-reference.md
new file mode 100644
index 0000000000..d65ed456eb
--- /dev/null
+++ b/docs/reference/clarinet-js-sdk/browser-sdk-reference.md
@@ -0,0 +1,122 @@
+# Browser SDK Reference
+
+The browser build of the Clarinet SDK lets you interact with simnet directly from web experiences, so you can run Clarity tests without standing up a Node.js server.
+
+## Installation
+
+{% code title="Install" %}
+```bash
+npm install @stacks/clarinet-sdk-browser
+```
+{% endcode %}
+
+## Usage
+
+The browser SDK implements the same API as the Node.js Clarinet SDK. All methods, properties, and custom matchers work identically.
+
+### Empty session
+
+{% code title="Empty session (TypeScript)" %}
+```ts
+import { initSimnet } from '@stacks/clarinet-sdk-browser';
+
+const simnet = await initSimnet();
+await simnet.initEmptySession();
+
+// Execute Clarity code directly
+const result = simnet.runSnippet("(+ 1 2)");
+console.log(result); // 3
+```
+{% endcode %}
+
+### With a Clarinet project
+
+For testing with an existing Clarinet project using a virtual file system:
+
+{% code title="Using a Clarinet project (TypeScript)" %}
+```ts
+import { initSimnet } from '@stacks/clarinet-sdk-browser';
+
+const simnet = await initSimnet();
+await simnet.initSession("/project", "Clarinet.toml");
+
+// Your contracts are now available
+const count = simnet.getDataVar('counter', 'count');
+```
+{% endcode %}
+
+{% hint style="info" %}
+Virtual file system
+
+Using a Clarinet project in the browser requires setting up a virtual file system. Documentation and examples for this advanced use case are coming soon.
+{% endhint %}
+
+## Common use cases
+
+### Interactive contract playground
+
+{% code title="Playground example (TypeScript)" %}
+```ts
+import { initSimnet } from '@stacks/clarinet-sdk-browser';
+import { Cl } from '@stacks/transactions';
+
+// Initialize simnet
+const simnet = await initSimnet();
+await simnet.initEmptySession();
+
+// Deploy a simple contract
+const sourceCode = `
+(define-data-var counter uint u0)
+
+(define-public (increment)
+ (ok (var-set counter (+ (var-get counter) u1))))
+
+(define-read-only (get-counter)
+ (ok (var-get counter)))
+`;
+
+simnet.deployContract('counter', sourceCode, null, simnet.deployer);
+
+// Interact with the contract
+simnet.callPublicFn('counter', 'increment', [], simnet.deployer);
+const count = simnet.callReadOnlyFn('counter', 'get-counter', [], simnet.deployer);
+console.log(count.result); // (ok u1)
+```
+{% endcode %}
+
+### Testing in browser-based IDEs
+
+{% code title="Browser test example (TypeScript + Vitest)" %}
+```ts
+import { initSimnet } from '@stacks/clarinet-sdk-browser';
+import { expect } from 'vitest';
+
+const simnet = await initSimnet();
+await simnet.initEmptySession();
+
+// Run tests directly in the browser
+test('counter increments correctly', () => {
+ simnet.deployContract('counter', counterCode, null, simnet.deployer);
+
+ const result = simnet.callPublicFn('counter', 'increment', [], simnet.deployer);
+ expect(result.result).toBeOk(Cl.uint(1));
+
+ const count = simnet.getDataVar('counter', 'counter');
+ expect(count).toBeUint(1);
+});
+```
+{% endcode %}
+
+## Browser compatibility
+
+The browser SDK works in all modern browsers that support:
+
+* ES2020+ JavaScript features
+* WebAssembly
+* Dynamic imports
+
+Tested browsers include:
+
+* Chrome/Edge 90+
+* Firefox 89+
+* Safari 15+
diff --git a/docs/reference/clarinet-js-sdk/sdk-reference.md b/docs/reference/clarinet-js-sdk/sdk-reference.md
new file mode 100644
index 0000000000..e72ff3c653
--- /dev/null
+++ b/docs/reference/clarinet-js-sdk/sdk-reference.md
@@ -0,0 +1,614 @@
+# SDK Reference
+
+The Clarinet JS SDK provides a comprehensive suite of helpers for testing and interacting with Clarity smart contracts. From simnet initialization to contract deployment, the SDK streamlines your entire testing workflow.
+
+* Initialize a simulated network: `initSimnet`
+* Manage contract state: `getDataVar`, `getMapEntry`
+* Call contract functions: `callReadOnlyFn`, `callPublicFn`
+* Transfer STX: `transferSTX`
+* Deploy contracts: `deployContract`
+* Mine blocks: `mineBlock`, `mineEmptyBlock`
+* Custom assertions: `toBeOk`, `toBeErr`
+
+## Installation
+
+```bash
+npm install @stacks/clarinet-sdk
+```
+
+## Initialize simulated network
+
+### initSimnet
+
+`initSimnet` initializes a simulated network for testing your smart contracts.
+
+Usage:
+
+```
+initSimnet(manifestPath?: string): Promise
+```
+
+```ts
+import { initSimnet } from '@stacks/clarinet-sdk';
+
+const simnet = await initSimnet();
+```
+
+| Parameter | Type | Description |
+| -------------- | -------- | -------------------------------------------- |
+| `manifestPath` | `string` | Optional path to Clarinet.toml manifest file |
+
+## Simnet properties
+
+### blockHeight
+
+Returns the current block height of simnet.
+
+```ts
+const currentBlockHeight = simnet.blockHeight;
+// Returns: 1
+```
+
+### deployer
+
+Returns the default deployer address as defined in the project file.
+
+```ts
+const deployerAddress = simnet.deployer;
+// Returns: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
+```
+
+You can also update the deployer:
+
+```ts
+simnet.deployer = 'ST1SJ3DTE5DN7X54YDH5D64R3BCB6A2AG2ZQ8YPD5';
+```
+
+### currentEpoch
+
+Returns the current epoch of simnet (e.g., 2.5 for Stacks 2.5).
+
+```ts
+const epoch = simnet.currentEpoch;
+// Returns: 2.5
+```
+
+## Account management
+
+### getAccounts
+
+`getAccounts` retrieves all configured Stacks addresses including wallets, deployers, and faucets.
+
+Usage:
+
+```
+getAccounts(): Map
+```
+
+```ts
+const accounts = simnet.getAccounts();
+const wallet1 = accounts.get('wallet_1')!;
+// Returns: ST1SJ3DTE5DN7X54YDH5D64R3BCB6A2AG2ZQ8YPD5
+```
+
+## Asset balances
+
+### getAssetsMap
+
+`getAssetsMap` retrieves asset balances for all addresses, including STX, fungible, and non-fungible tokens.
+
+Usage:
+
+```
+getAssetsMap(): Map>
+```
+
+```ts
+const assets = simnet.getAssetsMap();
+const stxBalances = assets.get('STX')!;
+const deployerBalance = stxBalances.get(simnet.deployer)!;
+// Returns: 100000000000000n
+```
+
+## Read contract state
+
+### getDataVar
+
+`getDataVar` retrieves the value of a data variable from a contract.
+
+Usage:
+
+```
+getDataVar(contract: string, dataVar: string): ClarityValue
+```
+
+```ts
+const count = simnet.getDataVar('counter', 'count');
+// Returns: { type: 1, value: 1n }
+```
+
+| Parameter | Type | Description |
+| ---------- | -------- | ------------------------- |
+| `contract` | `string` | Contract identifier |
+| `dataVar` | `string` | Name of the data variable |
+
+### getMapEntry
+
+`getMapEntry` retrieves a value from a contract map by its key.
+
+Usage:
+
+```
+getMapEntry(contract: string, mapName: string, mapKey: ClarityValue): ClarityValue
+```
+
+```ts
+import { Cl } from '@stacks/transactions';
+
+const hasParticipated = simnet.getMapEntry(
+ "pool",
+ "Participants",
+ Cl.standardPrincipal(wallet)
+);
+// Returns: { type: 10, value: { type: 3 } }
+```
+
+| Parameter | Type | Description |
+| ---------- | -------------- | ------------------- |
+| `contract` | `string` | Contract identifier |
+| `mapName` | `string` | Name of the map |
+| `mapKey` | `ClarityValue` | Key to look up |
+
+## Call contract functions
+
+### callReadOnlyFn
+
+`callReadOnlyFn` calls read-only functions without mining a block.
+
+Usage:
+
+```
+callReadOnlyFn(
+ contract: string,
+ method: string,
+ args: ClarityValue[],
+ sender: string
+): ParsedTransactionResult
+```
+
+```ts
+import { Cl } from '@stacks/transactions';
+
+const result = simnet.callReadOnlyFn(
+ 'pool',
+ 'get-contribution-amount',
+ [Cl.standardPrincipal(wallet)],
+ wallet
+);
+// Returns: { result: { type: 1, value: 42000000n }, events: [] }
+```
+
+| Parameter | Type | Description |
+| ---------- | ---------------- | ------------------- |
+| `contract` | `string` | Contract identifier |
+| `method` | `string` | Function name |
+| `args` | `ClarityValue[]` | Function arguments |
+| `sender` | `string` | Sender address |
+
+### callPublicFn
+
+`callPublicFn` calls public functions and mines a block.
+
+Usage:
+
+```
+callPublicFn(
+ contract: string,
+ method: string,
+ args: ClarityValue[],
+ sender: string
+): ParsedTransactionResult
+```
+
+```ts
+import { Cl } from '@stacks/transactions';
+
+const result = simnet.callPublicFn(
+ 'pool',
+ 'register-participant',
+ [Cl.standardPrincipal(wallet)],
+ wallet
+);
+// Mines block and returns result
+```
+
+### callPrivateFn
+
+`callPrivateFn` calls private functions (testing only) and mines a block.
+
+Usage:
+
+```
+callPrivateFn(
+ contract: string,
+ method: string,
+ args: ClarityValue[],
+ sender: string
+): ParsedTransactionResult
+```
+
+```ts
+const result = simnet.callPrivateFn(
+ "pool",
+ "reward-participant-points",
+ [Cl.standardPrincipal(address1)],
+ wallet
+);
+```
+
+## Transfer STX
+
+`transferSTX` transfers STX between addresses and mines a block.
+
+Usage:
+
+```
+transferSTX(
+ amount: number | bigint,
+ recipient: string,
+ sender: string
+): ParsedTransactionResult
+```
+
+```ts
+const transfer = simnet.transferSTX(
+ 42000000, // 42 STX in microSTX
+ recipient,
+ simnet.deployer
+);
+// Returns transaction result with transfer event
+```
+
+| Parameter | Type | Description |
+| ----------- | ------------------ | ------------------ |
+| `amount` | `number \| bigint` | Amount in microSTX |
+| `recipient` | `string` | Recipient address |
+| `sender` | `string` | Sender address |
+
+## Deploy contracts
+
+`deployContract` deploys a new contract to simnet and mines a block.
+
+Usage:
+
+```
+deployContract(
+ name: string,
+ content: string,
+ options: DeployContractOptions | null,
+ sender: string
+): ParsedTransactionResult
+```
+
+```ts
+const sourceCode = '(define-read-only (say-hi) (ok "Hello World"))';
+
+const contract = simnet.deployContract(
+ 'hello-world',
+ sourceCode,
+ { clarityVersion: 2 },
+ simnet.deployer
+);
+```
+
+| Parameter | Type | Description |
+| --------- | ---------------- | ------------------- |
+| `name` | `string` | Contract name |
+| `content` | `string` | Clarity source code |
+| `options` | `object \| null` | Deployment options |
+| `sender` | `string` | Deployer address |
+
+## Block mining
+
+### mineBlock
+
+`mineBlock` mines a block with multiple transactions.
+
+Usage:
+
+```
+mineBlock(txs: Tx[]): ParsedTransactionResult[]
+```
+
+```ts
+import { tx } from '@stacks/clarinet-sdk';
+import { Cl } from '@stacks/transactions';
+
+const block = simnet.mineBlock([
+ tx.callPublicFn("counter", "increment", [], simnet.deployer),
+ tx.transferSTX(19000000, wallet, simnet.deployer),
+]);
+```
+
+### mineEmptyBlock
+
+`mineEmptyBlock` mines an empty block and increases block height.
+
+Usage:
+
+```
+mineEmptyBlock(): number
+```
+
+```ts
+simnet.mineEmptyBlock();
+const newHeight = simnet.blockHeight;
+// Returns: 2
+```
+
+### mineEmptyBlocks
+
+`mineEmptyBlocks` mines multiple empty blocks.
+
+Usage:
+
+```
+mineEmptyBlocks(count?: number): number
+```
+
+```ts
+simnet.mineEmptyBlocks(5);
+const newHeight = simnet.blockHeight;
+// Returns: 6
+```
+
+## Utility methods
+
+### runSnippet
+
+`runSnippet` executes arbitrary Clarity code without deploying.
+
+Usage:
+
+```
+runSnippet(snippet: string): string | ClarityValue
+```
+
+```ts
+const result = simnet.runSnippet('(stx-account tx-sender)');
+// Returns account balance information
+```
+
+### getContractsInterfaces
+
+`getContractsInterfaces` returns contract interfaces with function signatures and storage.
+
+Usage:
+
+```
+getContractsInterfaces(): Map
+```
+
+```ts
+const interfaces = simnet.getContractsInterfaces();
+const poolInterface = interfaces.get(`${simnet.deployer}.pool`);
+// Returns contract interface with functions, maps, variables
+```
+
+### getContractSource
+
+`getContractSource` retrieves the source code of a deployed contract.
+
+Usage:
+
+```
+getContractSource(contract: string): string | undefined
+```
+
+```ts
+const source = simnet.getContractSource('pool');
+// Returns Clarity source code as string
+```
+
+### getContractAST
+
+`getContractAST` returns the Abstract Syntax Tree of a contract.
+
+Usage:
+
+```
+getContractAST(contractId: string): ContractAST
+```
+
+```ts
+const ast = simnet.getContractAST('pool');
+// Returns parsed AST structure
+```
+
+## Custom matchers
+
+The SDK provides Vitest matchers for Clarity value assertions.
+
+### Response matchers
+
+#### toBeOk
+
+Asserts that a response is `(ok )`.
+
+```ts
+expect(result).toBeOk(Cl.uint(1));
+```
+
+#### toBeErr
+
+Asserts that a response is `(err )`.
+
+```ts
+expect(result).toBeErr(Cl.uint(500));
+```
+
+#### toBeSome
+
+Asserts that a response is `(some )`.
+
+```ts
+expect(result).toBeSome(Cl.bool(true));
+```
+
+#### toBeNone
+
+Asserts that a response is `(none)`.
+
+```ts
+expect(result).toBeNone();
+```
+
+### Value matchers
+
+#### toBeBool
+
+Asserts a boolean value.
+
+```ts
+expect(result).toBeBool(true);
+```
+
+#### toBeInt
+
+Asserts a signed integer value.
+
+```ts
+expect(result).toBeInt(1); // or 1n
+```
+
+#### toBeUint
+
+Asserts an unsigned integer value.
+
+```ts
+expect(result).toBeUint(1); // or 1n
+```
+
+#### toBeAscii
+
+Asserts a string-ascii value.
+
+```ts
+expect(result).toBeAscii('Hello World');
+```
+
+#### toBeUtf8
+
+Asserts a string-utf8 value.
+
+```ts
+expect(result).toBeUtf8('Hello World');
+```
+
+#### toBePrincipal
+
+Asserts a principal value.
+
+```ts
+expect(Cl.standardPrincipal(deployer)).toBePrincipal(deployer);
+```
+
+#### toBeBuff
+
+Asserts a buffer value.
+
+```ts
+const buffer = Uint8Array.from([1, 2, 3, 4]);
+expect(result).toBeBuff(buffer);
+```
+
+#### toBeList
+
+Asserts a list of Clarity values.
+
+```ts
+expect(result).toBeList([
+ Cl.standardPrincipal('ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM'),
+ Cl.standardPrincipal('ST1SJ3DTE5DN7X54YDH5D64R3BCB6A2AG2ZQ8YPD5')
+]);
+```
+
+#### toBeTuple
+
+Asserts a tuple value.
+
+```ts
+expect(result).toBeTuple({
+ enrollmentBlock: Cl.some(Cl.uint(1)),
+ contributionAmount: Cl.some(Cl.uint(19000000))
+});
+```
+
+### Type checking
+
+#### toHaveClarityType
+
+Checks that a value has the expected Clarity type.
+
+```ts
+expect(result).toHaveClarityType(ClarityType.ResponseOk);
+```
+
+### Event matchers
+
+#### toContainEqual
+
+Asserts that an events array contains a specific event. This is useful for checking transaction events.
+
+```ts
+// STX transfer event
+expect(events).toContainEqual({
+ event: "stx_transfer_event",
+ data: {
+ amount: "1000000",
+ memo: "",
+ recipient: "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM",
+ sender: "ST1SJ3DTE5DN7X54YDH5D64R3BCB6A2AG2ZQ8YPD5",
+ },
+});
+
+// Fungible token transfer event
+expect(events).toContainEqual({
+ event: "ft_transfer_event",
+ data: {
+ amount: "1000",
+ asset_identifier: "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.token::my-token",
+ recipient: recipientAddress,
+ sender: senderAddress,
+ },
+});
+
+// NFT transfer event
+expect(events).toContainEqual({
+ event: "nft_transfer_event",
+ data: {
+ asset_identifier: "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.nft::my-nft",
+ value: Cl.serialize(Cl.uint(1)),
+ recipient: newOwner,
+ sender: previousOwner,
+ },
+});
+
+// Print event
+expect(events).toContainEqual({
+ event: "print_event",
+ data: {
+ contract_id: `${deployer}.my-contract`,
+ value: Cl.serialize(Cl.tuple({ message: Cl.stringAscii("Hello") })),
+ },
+});
+
+// Check only specific properties with objectContaining
+expect(events).toContainEqual({
+ event: "stx_transfer_event",
+ data: expect.objectContaining({
+ sender: senderAddress,
+ recipient: recipientAddress,
+ }),
+});
+```
diff --git a/docs/reference/clarinet/cli-reference.md b/docs/reference/clarinet/cli-reference.md
new file mode 100644
index 0000000000..60850f5aa7
--- /dev/null
+++ b/docs/reference/clarinet/cli-reference.md
@@ -0,0 +1,411 @@
+# CLI Reference
+
+The Clarinet CLI provides a comprehensive suite of tools for Clarity smart contract development. From project initialization to deployment, Clarinet streamlines your entire development workflow.
+
+* Create a new project: `clarinet new`
+* Generate a new smart contract: `clarinet contracts new`
+* Validate contract syntax and types: `clarinet check`
+* Interactive REPL for testing contracts: `clarinet console`
+* Launch a local development network: `clarinet devnet start`
+* Manage deployments: `clarinet deployments`
+
+## Initialize a new project
+
+### clarinet new
+
+`clarinet new` creates a new project with all necessary configuration files and directory structure.
+
+Usage
+
+```
+clarinet new [OPTIONS]
+```
+
+```bash
+$ clarinet new my-defi-protocol
+Create directory my-defi-protocol
+Create directory contracts
+Create directory settings
+Create directory tests
+Create file Clarinet.toml
+Create file settings/Mainnet.toml
+Create file settings/Testnet.toml
+Create file settings/Devnet.toml
+Create directory .vscode
+Create file .vscode/settings.json
+Create file .vscode/tasks.json
+Create file .gitignore
+Create file .gitattributes
+Create file package.json
+Create file tsconfig.json
+Create file vitest.config.js
+```
+
+| Option | Description |
+| --------------------- | --------------------------------------------------------- |
+| `--disable-telemetry` | Do not provide developer usage telemetry for this project |
+
+## Manage your contracts
+
+### clarinet contracts
+
+`clarinet contracts` is a subcommand for working with contracts. It has two subcommands:
+
+| Command | Description |
+| ------- | ---------------------------------------------- |
+| `new` | Generate files and settings for a new contract |
+| `rm` | Remove files and settings for a contract |
+
+Usage with `new`
+
+```
+clarinet contracts new
+```
+
+```bash
+$ clarinet contracts new fungible-token
+Created file contracts/fungible-token.clar
+Created file tests/fungible-token.test.ts
+Updated Clarinet.toml
+```
+
+Usage with `rm`
+
+```
+clarinet contracts rm
+```
+
+```bash
+$ clarinet contracts rm old-token
+Removed file contracts/old-token.clar
+Removed file tests/old-token.test.ts
+Updated Clarinet.toml
+```
+
+| Option | Description |
+| ------------------------ | --------------------- |
+| `--manifest-path ` | Path to Clarinet.toml |
+
+## Validate your contracts
+
+### clarinet check
+
+`clarinet check` checks contracts syntax and performs type checking.
+
+Usage
+
+```
+clarinet check [FILE] [OPTIONS]
+```
+
+```bash
+clarinet check
+✔ 3 contracts checked
+clarinet check contracts/token.clar
+✔ contracts/token.clar syntax checks passed
+```
+
+| Option | Short | Description |
+| -------------------------------- | ----- | ------------------------------------------------------------------------------------- |
+| `--manifest-path ` | `-m` | Path to Clarinet.toml |
+| `--deployment-plan-path ` | `-p` | If specified, use this deployment file |
+| `--use-on-disk-deployment-plan` | `-d` | Use on disk deployment plan (prevent updates computing) |
+| `--use-computed-deployment-plan` | `-c` | Use computed deployment plan (will overwrite on disk version if any update) |
+| `--enable-clarity-wasm` | | Allow the Clarity Wasm preview to run in parallel with the Clarity interpreter (beta) |
+
+## Interact with your contracts in a local REPL
+
+### clarinet console
+
+`clarinet console` loads contracts in a REPL for an interactive session.
+
+Usage
+
+```
+clarinet console [OPTIONS]
+```
+
+```bash
+$ clarinet console
+clarity-repl v1.0.0
+Enter ".help" for usage hints.
+Connected to a transient in-memory database.
+```
+
+The Clarinet console offers a variety of commands for contract interaction:
+
+* `::help`: Lists all console commands
+* `::functions`: Display all the native functions available in Clarity
+* `::keywords`: Display all the native keywords available in Clarity
+* `::describe | `: Display documentation for a given native function or keyword
+* `::toggle_costs`: Display cost analysis after every expression
+* `::toggle_timings`: Display the execution duration
+* `::mint_stx `: Mint STX balance for a given principal
+* `::set_tx_sender `: Set tx-sender variable to principal
+* `::get_assets_maps`: Get assets maps for active accounts
+* `::get_contracts`: Get contracts
+* `::get_block_height`: Get current block height
+* `::advance_chain_tip `: Simulate mining of `` blocks
+* `::advance_stacks_chain_tip `: Simulate mining of `` stacks blocks
+* `::advance_burn_chain_tip `: Simulate mining of `` burnchain blocks
+* `::set_epoch `: Update the current epoch
+* `::get_epoch`: Get current epoch
+* `::debug `: Start an interactive debug session executing ``
+* `::trace `: Generate an execution trace for ``
+* `::get_costs `: Display the cost analysis
+* `::reload`: Reload the existing contract(s) in the session
+* `::read `: Read expressions from a file
+* `::encode `: Encode an expression to a Clarity Value bytes representation
+* `::decode `: Decode a Clarity Value bytes representation
+
+| Option | Short | Description |
+| --------------------------------------- | ----- | ------------------------------------------------------------------------------------- |
+| `--manifest-path ` | `-m` | Path to Clarinet.toml |
+| `--deployment-plan-path ` | `-p` | If specified, use this deployment file |
+| `--use-on-disk-deployment-plan` | `-d` | Use on disk deployment plan (prevent updates computing) |
+| `--use-computed-deployment-plan` | `-c` | Use computed deployment plan (will overwrite on disk version if any update) |
+| `--enable-remote-data` | `-r` | Enable remote data fetching from mainnet or a testnet |
+| `--remote-data-api-url ` | `-a` | Set a custom Stacks Blockchain API URL for remote data fetching |
+| `--remote-data-initial-height ` | `-b` | Initial remote Stacks block height |
+| `--enable-clarity-wasm` | | Allow the Clarity Wasm preview to run in parallel with the Clarity interpreter (beta) |
+
+## Start a local development network
+
+### clarinet devnet
+
+`clarinet devnet` is a subcommand for working with Devnet. It has two subcommands:
+
+| Command | Description |
+| --------- | ---------------------------------------------------------------- |
+| `start` | Start a local Devnet network for interacting with your contracts |
+| `package` | Generate package of all required devnet artifacts |
+
+Usage with `start`
+
+```
+clarinet devnet start [OPTIONS]
+```
+
+```bash
+clarinet devnet start
+```
+
+| Option | Short | Description |
+| -------------------------------- | ----- | --------------------------------------------------------------------------- |
+| `--manifest-path ` | `-m` | Path to Clarinet.toml |
+| `--no-dashboard` | | Display streams of logs instead of terminal UI dashboard |
+| `--deployment-plan-path ` | `-p` | If specified, use this deployment file |
+| `--use-on-disk-deployment-plan` | `-d` | Use on disk deployment plan (prevent updates computing) |
+| `--use-computed-deployment-plan` | `-c` | Use computed deployment plan (will overwrite on disk version if any update) |
+| `--package ` | | Path to Package.json produced by 'clarinet devnet package' |
+
+Usage with `package`
+
+```
+clarinet devnet package [OPTIONS]
+```
+
+```bash
+$ clarinet devnet package --name my-devnet
+Packaging devnet artifacts...
+Created file my-devnet.json
+```
+
+| Option | Short | Description |
+| ------------------------ | ----- | --------------------- |
+| `--name ` | `-n` | Output json file name |
+| `--manifest-path ` | `-m` | Path to Clarinet.toml |
+
+## Manage your deployments
+
+### clarinet deployments
+
+`clarinet deployments` is a subcommand for managing deployments on Devnet/Testnet/Mainnet.
+
+| Command | Description |
+| ---------- | ------------------------ |
+| `check` | Check deployments format |
+| `generate` | Generate new deployment |
+| `apply` | Apply deployment |
+
+Usage with `check`
+
+```
+clarinet deployments check [OPTIONS]
+```
+
+```bash
+$ clarinet deployments check
+✔ Deployment files are valid
+```
+
+| Option | Description |
+| ------------------------ | --------------------- |
+| `--manifest-path ` | Path to Clarinet.toml |
+
+Usage with `generate`
+
+```
+clarinet deployments generate [OPTIONS]
+```
+
+```bash
+$ clarinet deployments generate --testnet
+Generated deployment plan
+Created file deployments/default.testnet-plan.yaml
+```
+
+| Option | Description |
+| ------------------------ | ----------------------------------------------------------------------------- |
+| `--simnet` | Generate a deployment file for simnet environments (console, tests) |
+| `--devnet` | Generate a deployment file for devnet, using settings/Devnet.toml |
+| `--testnet` | Generate a deployment file for testnet, using settings/Testnet.toml |
+| `--mainnet` | Generate a deployment file for mainnet, using settings/Mainnet.toml |
+| `--manifest-path ` | Path to Clarinet.toml |
+| `--no-batch` | Generate a deployment file without trying to batch transactions (simnet only) |
+| `--low-cost` | Compute and set cost, using low priority (network connection required) |
+| `--medium-cost` | Compute and set cost, using medium priority (network connection required) |
+| `--high-cost` | Compute and set cost, using high priority (network connection required) |
+| `--manual-cost` | Leave cost estimation manual |
+
+Usage with `apply`
+
+```
+clarinet deployments apply [OPTIONS]
+```
+
+```bash
+$ clarinet deployments apply --testnet
+Applying deployment to testnet
+✔ Broadcasting transaction for token.clar
+ Transaction ID: 0x3d4f5...
+ Contract: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.token
+✔ All contracts deployed successfully
+```
+
+| Option | Short | Description |
+| -------------------------------- | ----- | --------------------------------------------------------------------------- |
+| `--devnet` | | Apply default deployment settings/default.devnet-plan.toml |
+| `--testnet` | | Apply default deployment settings/default.testnet-plan.toml |
+| `--mainnet` | | Apply default deployment settings/default.mainnet-plan.toml |
+| `--manifest-path ` | `-m` | Path to Clarinet.toml |
+| `--deployment-plan-path ` | `-p` | Apply deployment plan specified |
+| `--no-dashboard` | | Display streams of logs instead of terminal UI dashboard |
+| `--use-on-disk-deployment-plan` | `-d` | Use on disk deployment plan (prevent updates computing) |
+| `--use-computed-deployment-plan` | `-c` | Use computed deployment plan (will overwrite on disk version if any update) |
+
+## Interact with Mainnet contracts
+
+### clarinet requirements
+
+`clarinet requirements` is a subcommand for interacting with Mainnet contracts.
+
+| Command | Description |
+| ------- | ------------------------------------------------------ |
+| `add` | Add a mainnet contract as a dependency to your project |
+
+Usage
+
+```
+clarinet requirements
+```
+
+```bash
+$ clarinet requirements add SP2PABAF9FTAJYNFZH93XENAJ8FVY99RRM50D2JG9.nft-trait
+Added requirement SP2PABAF9FTAJYNFZH93XENAJ8FVY99RRM50D2JG9.nft-trait
+Updated Clarinet.toml
+```
+
+| Option | Description |
+| ------------------------ | --------------------- |
+| `--manifest-path ` | Path to Clarinet.toml |
+
+## Editor Integrations
+
+### clarinet lsp
+
+`clarinet lsp` starts the Language Server Protocol service for Clarity, enabling intelligent code completion, error highlighting, and other IDE features in supported editors.
+
+Usage
+
+```
+clarinet lsp
+```
+
+## Debugging
+
+### clarinet dap
+
+`clarinet dap` starts the Debug Adapter Protocol service, enabling debugging features like breakpoints, step-through execution, and variable inspection in supported editors.
+
+Usage
+
+```
+clarinet dap
+```
+
+## Format your code
+
+### clarinet format
+
+`clarinet format` formats Clarity code files according to standard conventions.
+
+Usage
+
+```
+clarinet format [OPTIONS]
+```
+
+```bash
+clarinet format --check
+clarinet format --dry-run
+clarinet format --file contracts/token.clar --in-place
+```
+
+| Option | Short | Description | Required |
+| ---------------------------- | ----- | ------------------------------------------------------ | -------- |
+| `--check` | | Check if code is formatted without modifying files | No |
+| `--dry-run` | | Only echo the result of formatting | No |
+| `--in-place` | | Replace the contents of a file with the formatted code | No |
+| `--manifest-path ` | `-m` | Path to Clarinet.toml | No |
+| `--file ` | `-f` | If specified, format only this file | No |
+| `--max-line-length ` | `-l` | Maximum line length | No |
+| `--indent ` | `-i` | Indentation size, e.g. 2 | No |
+| `--tabs` | `-t` | Use tabs instead of spaces | No |
+
+## Utilities
+
+### clarinet completions
+
+`clarinet completions` generates shell completion scripts for your shell.
+
+Usage
+
+```
+clarinet completions
+```
+
+```bash
+clarinet completions zsh > ~/.zsh/completions/_clarinet
+source ~/.zshrc
+```
+
+Supported Shells
+
+* `bash`
+* `zsh`
+* `fish`
+* `powershell`
+* `elvish`
+
+| Option | Short | Description |
+| ----------------- | ----- | -------------------------------------------------------- |
+| `--shell ` | `-s` | Specify which shell to generation completions script for |
+
+## Environment Variables
+
+Clarinet supports environment variables for configuration. All environment variables are prefixed with `CLARINET_`:
+
+```bash
+export CLARINET_MANIFEST_PATH=/path/to/project
+```
diff --git a/docs/reference/clarity/example-contracts/README.md b/docs/reference/clarity/example-contracts/README.md
new file mode 100644
index 0000000000..8bfe0241ca
--- /dev/null
+++ b/docs/reference/clarity/example-contracts/README.md
@@ -0,0 +1,2 @@
+# Example Contracts
+
diff --git a/docs/reference/clarity/example-contracts/audited-starter-contracts.md b/docs/reference/clarity/example-contracts/audited-starter-contracts.md
new file mode 100644
index 0000000000..aed648cfe3
--- /dev/null
+++ b/docs/reference/clarity/example-contracts/audited-starter-contracts.md
@@ -0,0 +1,10 @@
+# audited starter contracts
+
+Here's a list of sample contracts to learn Clarity or to serve as a starting point for your next project. All contracts come from the [Clarity book](https://book.clarity-lang.org/) and have been audited by [Coinfabrik](https://www.coinfabrik.com/).
+
+* [Counter](https://github.com/clarity-lang/book/tree/main/projects/counter)
+* [Multisig Vault](https://github.com/clarity-lang/book/tree/main/projects/multisig-vault)
+* [Sip-009 NFT](https://github.com/clarity-lang/book/tree/main/projects/sip009-nft)
+* [SIP-010 FT](https://github.com/clarity-lang/book/tree/main/projects/sip010-ft)
+* [Timelocked Wallet](https://github.com/clarity-lang/book/tree/main/projects/timelocked-wallet)
+* [Tiny Market (NFT marketplace)](https://github.com/clarity-lang/book/tree/main/projects/tiny-market)
diff --git a/docs/reference/clarity/example-contracts/bns.md b/docs/reference/clarity/example-contracts/bns.md
new file mode 100644
index 0000000000..c5498c7099
--- /dev/null
+++ b/docs/reference/clarity/example-contracts/bns.md
@@ -0,0 +1,423 @@
+# bns
+
+The Bitcoin Name System (BNS) is implemented as a smart contract using Clarity.
+
+Below is a list of public and read-only functions as well as error codes that can be returned by those methods.
+
+***
+
+## Public functions
+
+### name-import
+
+Signature:
+
+{% code title="Signature" %}
+```clojure
+(name-import namespace name beneficiary zonefile-hash)
+```
+{% endcode %}
+
+Input: `(buff 20), (buff 48), principal, (buff 20)`\
+Output: `(response bool int)`
+
+Description:\
+Imports name to a revealed namespace. Each imported name is given both an owner and some off-chain state.
+
+***
+
+### name-preorder
+
+Signature:
+
+{% code title="Signature" %}
+```clojure
+(name-preorder hashed-salted-fqn stx-to-burn)
+```
+{% endcode %}
+
+Input: `(buff 20), uint`\
+Output: `(response uint int)`
+
+Description:\
+Preorders a name by telling all BNS nodes the salted hash of the BNS name. It pays the registration fee to the namespace owner's designated address.
+
+***
+
+### name-register
+
+Signature:
+
+{% code title="Signature" %}
+```clojure
+(name-register namespace name salt zonefile-hash)
+```
+{% endcode %}
+
+Input: `(buff 20), (buff 48), (buff 20), (buff 20)`\
+Output: `(response bool int)`
+
+Description:\
+Reveals the salt and the name to all BNS nodes, and assigns the name an initial public key hash and zone file hash.
+
+***
+
+### name-renewal
+
+Signature:
+
+{% code title="Signature" %}
+```clojure
+(name-renewal namespace name stx-to-burn new-owner zonefile-hash)
+```
+{% endcode %}
+
+Input: `(buff 20), (buff 48), uint, (optional principal), (optional (buff 20))`\
+Output: `(response bool int)`
+
+Description:\
+Depending on the namespace rules, a name can expire. For example, names in the .id namespace expire after 2 years. You need to send a name renewal every so often to keep your name.
+
+You will pay the registration cost of your name to the namespace's designated burn address when you renew it. When a name expires, it enters a "grace period". The period is set to 5000 blocks (a month) but can be configured for each namespace.
+
+It will stop resolving in the grace period, and all of the above operations will cease to be honored by the BNS consensus rules. You may, however, send a NAME\_RENEWAL during this grace period to preserve your name. After the grace period, everybody can register that name again. If your name is in a namespace where names do not expire, then you never need to use this transaction.
+
+***
+
+### name-revoke
+
+Signature:
+
+{% code title="Signature" %}
+```clojure
+(name-revoke namespace name)
+```
+{% endcode %}
+
+Input: `(buff 20), (buff 48)`\
+Output: `(response bool int)`
+
+Description:\
+Makes a name unresolvable. The BNS consensus rules stipulate that once a name is revoked, no one can change its public key hash or its zone file hash. The name's zone file hash is set to null to prevent it from resolving. You should only do this if your private key is compromised, or if you want to render your name unusable for whatever reason.
+
+***
+
+### name-transfer
+
+Signature:
+
+{% code title="Signature" %}
+```clojure
+(name-transfer namespace name new-owner zonefile-hash)
+```
+{% endcode %}
+
+Input: `(buff 20), (buff 48), principal, (optional (buff 20))`\
+Output: `(response bool int)`
+
+Description:\
+Changes the name's public key hash. You would send a name transfer transaction if you wanted to:
+
+* Change your private key
+* Send the name to someone else
+* Update your zone file
+
+When transferring a name, you have the option to also clear the name's zone file hash (i.e. set it to null). This is useful for when you send the name to someone else, so the recipient's name does not resolve to your zone file.
+
+***
+
+### name-update
+
+Signature:
+
+{% code title="Signature" %}
+```clojure
+(name-update namespace name zonefile-hash)
+```
+{% endcode %}
+
+Input: `(buff 20), (buff 48), (buff 20)`\
+Output: `(response bool int)`
+
+Description:\
+Changes the name's zone file hash. You would send a name update transaction if you wanted to change the name's zone file contents. For example, you would do this if you want to deploy your own Gaia hub and want other people to read from it.
+
+***
+
+### namespace-preorder
+
+Signature:
+
+{% code title="Signature" %}
+```clojure
+(namespace-preorder hashed-salted-namespace stx-to-burn)
+```
+{% endcode %}
+
+Input: `(buff 20), uint`\
+Output: `(response uint int)`
+
+Description:\
+Registers the salted hash of the namespace with BNS nodes, and burns the requisite amount of cryptocurrency. Additionally, this step proves to the BNS nodes that user has honored the BNS consensus rules by including a recent consensus hash in the transaction. Returns pre-order's expiration date (in blocks).
+
+***
+
+### namespace-ready
+
+Signature:
+
+{% code title="Signature" %}
+```clojure
+(namespace-ready namespace)
+```
+{% endcode %}
+
+Input: `(buff 20)`\
+Output: `(response bool int)`
+
+Description:\
+Launches the namespace and makes it available to the public. Once a namespace is launched, anyone can register a name in it if they pay the appropriate amount of cryptocurrency.
+
+***
+
+### namespace-reveal
+
+Signature:
+
+{% code title="Signature" %}
+```clojure
+(namespace-reveal namespace namespace-salt p-func-base p-func-coeff p-func-b1 p-func-b2 p-func-b3 p-func-b4 p-func-b5 p-func-b6 p-func-b7 p-func-b8 p-func-b9 p-func-b10 p-func-b11 p-func-b12 p-func-b13 p-func-b14 p-func-b15 p-func-b16 p-func-non-alpha-discount p-func-no-vowel-discount lifetime namespace-import)
+```
+{% endcode %}
+
+Input: `(buff 20), (buff 20), uint, uint, uint, uint, uint, uint, uint, uint, uint, uint, uint, uint, uint, uint, uint, uint, uint, uint, uint, uint, uint, principal`\
+Output: `(response bool int)`
+
+Description:\
+Reveals the salt and the namespace ID (after a namespace preorder). It reveals how long names last in this namespace before they expire or must be renewed, and it sets a price function for the namespace that determines how cheap or expensive names will be. All of the parameters prefixed by `p` make up the price function. These parameters govern the pricing and lifetime of names in the namespace.
+
+Rules for a namespace:
+
+* A name can fall into one of 16 buckets, measured by length. Bucket 16 incorporates all names at least 16 characters long.
+* The pricing structure applies a multiplicative penalty for having numeric characters, or punctuation characters.
+* The price of a name in a bucket is: ((coeff) \* (base) ^ (bucket exponent)) / ((numeric discount multiplier) \* (punctuation discount multiplier))
+
+Example parameters:
+
+* base = 10
+* coeff = 2
+* nonalpha discount: 10
+* no-vowel discount: 10
+* buckets 1, 2: 9
+* buckets 3, 4, 5, 6: 8
+* buckets 7–14: 7
+* buckets 15, 16+: (not specified in source)
+
+***
+
+## Read-only functions
+
+### can-name-be-registered
+
+Signature:
+
+{% code title="Signature" %}
+```clojure
+(can-name-be-registered namespace name)
+```
+{% endcode %}
+
+Input: `(buff 20), (buff 48)`\
+Output: `(response bool int)`
+
+Description:\
+Returns true if the provided name can be registered.
+
+***
+
+### can-namespace-be-registered
+
+Signature:
+
+{% code title="Signature" %}
+```clojure
+(can-namespace-be-registered namespace)
+```
+{% endcode %}
+
+Input: `(buff 20)`\
+Output: `(response bool UnknownType)`
+
+Description:\
+Returns true if the provided namespace is available.
+
+***
+
+### can-receive-name
+
+Signature:
+
+{% code title="Signature" %}
+```clojure
+(can-receive-name owner)
+```
+{% endcode %}
+
+Input: `principal`\
+Output: `(response bool int)`
+
+Description:\
+Returns true if the provided name can be received. That is, if it is not currently owned, a previous lease is expired, and the name wasn't revoked.
+
+***
+
+### get-name-price
+
+Signature:
+
+{% code title="Signature" %}
+```clojure
+(get-name-price namespace name)
+```
+{% endcode %}
+
+Input: `(buff 20), (buff 48)`\
+Output: `(response uint int)`
+
+Description:\
+Gets the price for a name.
+
+***
+
+### get-namespace-price
+
+Signature:
+
+{% code title="Signature" %}
+```clojure
+(get-namespace-price namespace)
+```
+{% endcode %}
+
+Input: `(buff 20)`\
+Output: `(response uint int)`
+
+Description:\
+Gets the price for a namespace.
+
+***
+
+### get-namespace-properties
+
+Signature:
+
+{% code title="Signature" %}
+```clojure
+(get-namespace-properties namespace)
+```
+{% endcode %}
+
+Input: `(buff 20)`\
+Output: `(response (tuple (namespace (buff 20)) (properties (tuple (can-update-price-function bool) (launched-at (optional uint)) (lifetime uint) (namespace-import principal) (price-function (tuple (base uint) (buckets (list 16 uint)) (coeff uint) (no-vowel-discount uint) (nonalpha-discount uint))) (revealed-at uint)))) int)`
+
+Description:\
+Get namespace properties.
+
+***
+
+### is-name-lease-expired
+
+Signature:
+
+{% code title="Signature" %}
+```clojure
+(is-name-lease-expired namespace name)
+```
+{% endcode %}
+
+Input: `(buff 20), (buff 48)`\
+Output: `(response bool int)`
+
+Description:\
+Return true if the provided name lease is expired.
+
+***
+
+### name-resolve
+
+Signature:
+
+{% code title="Signature" %}
+```clojure
+(name-resolve namespace name)
+```
+{% endcode %}
+
+Input: `(buff 20), (buff 48)`\
+Output: `(response (tuple (lease-ending-at (optional uint)) (lease-started-at uint) (owner principal) (zonefile-hash (buff 20))) int)`
+
+Description:\
+Get name registration details.
+
+***
+
+### resolve-principal
+
+Signature:
+
+{% code title="Signature" %}
+```clojure
+(resolve-principal owner)
+```
+{% endcode %}
+
+Input: `principal`\
+Output: `(response (tuple (name (buff 48)) (namespace (buff 20))) (tuple (code int) (name (optional (tuple (name (buff 48)) (namespace (buff 20)))))))`
+
+Description:\
+Returns the registered name that a principal owns if there is one. A principal can only own one name at a time.
+
+***
+
+## Error codes
+
+* ERR\_INSUFFICIENT\_FUNDS — type: int, value: 4001
+* ERR\_NAMESPACE\_ALREADY\_EXISTS — type: int, value: 1006
+* ERR\_NAMESPACE\_ALREADY\_LAUNCHED — type: int, value: 1014
+* ERR\_NAMESPACE\_BLANK — type: int, value: 1013
+* ERR\_NAMESPACE\_CHARSET\_INVALID — type: int, value: 1016
+* ERR\_NAMESPACE\_HASH\_MALFORMED — type: int, value: 1015
+* ERR\_NAMESPACE\_NOT\_FOUND — type: int, value: 1005
+* ERR\_NAMESPACE\_NOT\_LAUNCHED — type: int, value: 1007
+* ERR\_NAMESPACE\_OPERATION\_UNAUTHORIZED — type: int, value: 1011
+* ERR\_NAMESPACE\_PREORDER\_ALREADY\_EXISTS — type: int, value: 1003
+* ERR\_NAMESPACE\_PREORDER\_CLAIMABILITY\_EXPIRED — type: int, value: 1009
+* ERR\_NAMESPACE\_PREORDER\_EXPIRED — type: int, value: 1002
+* ERR\_NAMESPACE\_PREORDER\_LAUNCHABILITY\_EXPIRED — type: int, value: 1010
+* ERR\_NAMESPACE\_PREORDER\_NOT\_FOUND — type: int, value: 1001
+* ERR\_NAMESPACE\_PRICE\_FUNCTION\_INVALID — type: int, value: 1008
+* ERR\_NAMESPACE\_STX\_BURNT\_INSUFFICIENT — type: int, value: 1012
+* ERR\_NAMESPACE\_UNAVAILABLE — type: int, value: 1004
+* ERR\_NAME\_ALREADY\_CLAIMED — type: int, value: 2011
+* ERR\_NAME\_BLANK — type: int, value: 2010
+* ERR\_NAME\_CHARSET\_INVALID — type: int, value: 2022
+* ERR\_NAME\_CLAIMABILITY\_EXPIRED — type: int, value: 2012
+* ERR\_NAME\_COULD\_NOT\_BE\_MINTED — type: int, value: 2020
+* ERR\_NAME\_COULD\_NOT\_BE\_TRANSFERRED — type: int, value: 2021
+* ERR\_NAME\_EXPIRED — type: int, value: 2008
+* ERR\_NAME\_GRACE\_PERIOD — type: int, value: 2009
+* ERR\_NAME\_HASH\_MALFORMED — type: int, value: 2017
+* ERR\_NAME\_NOT\_FOUND — type: int, value: 2013
+* ERR\_NAME\_NOT\_RESOLVABLE — type: int, value: 2019
+* ERR\_NAME\_OPERATION\_UNAUTHORIZED — type: int, value: 2006
+* ERR\_NAME\_PREORDERED\_BEFORE\_NAMESPACE\_LAUNCH — type: int, value: 2018
+* ERR\_NAME\_PREORDER\_ALREADY\_EXISTS — type: int, value: 2016
+* ERR\_NAME\_PREORDER\_EXPIRED — type: int, value: 2002
+* ERR\_NAME\_PREORDER\_FUNDS\_INSUFFICIENT — type: int, value: 2003
+* ERR\_NAME\_PREORDER\_NOT\_FOUND — type: int, value: 2001
+* ERR\_NAME\_REVOKED — type: int, value: 2014
+* ERR\_NAME\_STX\_BURNT\_INSUFFICIENT — type: int, value: 2007
+* ERR\_NAME\_TRANSFER\_FAILED — type: int, value: 2015
+* ERR\_NAME\_UNAVAILABLE — type: int, value: 2004
+* ERR\_PANIC — type: int, value: 0
+* ERR\_PRINCIPAL\_ALREADY\_ASSOCIATED — type: int, value: 3001
diff --git a/docs/reference/clarity/example-contracts/multi-send.md b/docs/reference/clarity/example-contracts/multi-send.md
new file mode 100644
index 0000000000..a0d2408322
--- /dev/null
+++ b/docs/reference/clarity/example-contracts/multi-send.md
@@ -0,0 +1,23 @@
+# multi send
+
+Multi send is a very simple but highly useful utility contract for executing multiple STX transfers in a single transaction.
+
+It takes in a list of addresses and amounts and folds through them to execute a STX transfer for each one.
+
+Mainnet contract: https://explorer.hiro.so/txid/0x59665b756dc0fa9efb3fca9e05a28f572c9b14ca894c115fd3e7d81a563e14f8?chain=mainnet
+
+{% code title="multi-send.clar" %}
+```clojure
+;; send-many
+(define-private (send-stx (recipient { to: principal, ustx: uint }))
+ (stx-transfer? (get ustx recipient) tx-sender (get to recipient)))
+(define-private (check-err (result (response bool uint))
+ (prior (response bool uint)))
+ (match prior ok-value result
+ err-value (err err-value)))
+(define-public (send-many (recipients (list 200 { to: principal, ustx: uint })))
+ (fold check-err
+ (map send-stx recipients)
+ (ok true)))
+```
+{% endcode %}
diff --git a/docs/reference/clarity/example-contracts/stacking.md b/docs/reference/clarity/example-contracts/stacking.md
new file mode 100644
index 0000000000..dc00d17aa2
--- /dev/null
+++ b/docs/reference/clarity/example-contracts/stacking.md
@@ -0,0 +1,428 @@
+# stacking
+
+Stacking is implemented as a smart contract using Clarity. You can always find the Stacking contract identifier using the Stacks Blockchain API [`v2/pox` endpoint](https://docs.hiro.so/api#operation/get_pox_info).
+
+Currently, stacking uses the pox-4 contract. The deployed pox-4 contract and included comments can be [viewed in the explorer](https://explorer.hiro.so/txid/SP000000000000000000002Q6VF78.pox-4?chain=mainnet).
+
+In this walkthrough, we'll cover the entire stacking contract from start to finish, including descriptions of the various functions and errors, and when you might use/encounter them.
+
+Rather than walking through the contract line by line, which you can do by simply reading the contract code and the comments, we'll instead explore it from the perspective of conducting stacking operations, including solo stacking, delegating, and running a pool.
+
+At the bottom you will find a list of some errors you may run into and their explanations.
+
+There are a few utilities that make interacting with this contract easier including [Leather Earn](https://earn.leather.io/) as an UI and the [@stacks/stacking package](https://www.npmjs.com/package/@stacks/stacking) for a JS library.
+
+Hiro has a [detailed guide](https://docs.hiro.so/stacks.js/guides/how-to-integrate-stacking) available for stacking using this library as well as a [Nakamoto guide](https://docs.hiro.so/nakamoto/stacks-js) specifically for the additions made to work with `pox-4`.
+
+### Prerequisites
+
+If you are not familiar with stacking as a concept, it will be useful to [familiarize yourself with that first](/broken/pages/3df1d5b76fd4f047544069a38895455776fc228f) before diving into the contract.
+
+***
+
+## Solo Stacking
+
+Solo stacking is the simplest option, and begins by calling the `stack-stx` function.
+
+### stack-stx
+
+This function locks up the given amount of STX for the given lock period (number of reward cycles) for the `tx-sender`.
+
+Here's the full code for that function, then we'll dive into how it works below that.
+
+{% code title="pox-4: stack-stx" %}
+```clojure
+(define-public (stack-stx (amount-ustx uint)
+ (pox-addr (tuple (version (buff 1)) (hashbytes (buff 32))))
+ (start-burn-ht uint)
+ (lock-period uint)
+ (signer-sig (optional (buff 65)))
+ (signer-key (buff 33))
+ (max-amount uint)
+ (auth-id uint))
+ ;; this stacker's first reward cycle is the _next_ reward cycle
+ (let ((first-reward-cycle (+ u1 (current-pox-reward-cycle)))
+ (specified-reward-cycle (+ u1 (burn-height-to-reward-cycle start-burn-ht))))
+ ;; the start-burn-ht must result in the next reward cycle, do not allow stackers
+ ;; to "post-date" their `stack-stx` transaction
+ (asserts! (is-eq first-reward-cycle specified-reward-cycle)
+ (err ERR_INVALID_START_BURN_HEIGHT))
+
+ ;; must be called directly by the tx-sender or by an allowed contract-caller
+ (asserts! (check-caller-allowed)
+ (err ERR_STACKING_PERMISSION_DENIED))
+
+ ;; tx-sender principal must not be stacking
+ (asserts! (is-none (get-stacker-info tx-sender))
+ (err ERR_STACKING_ALREADY_STACKED))
+
+ ;; tx-sender must not be delegating
+ (asserts! (is-none (get-check-delegation tx-sender))
+ (err ERR_STACKING_ALREADY_DELEGATED))
+
+ ;; the Stacker must have sufficient unlocked funds
+ (asserts! (>= (stx-get-balance tx-sender) amount-ustx)
+ (err ERR_STACKING_INSUFFICIENT_FUNDS))
+
+ ;; Validate ownership of the given signer key
+ (try! (consume-signer-key-authorization pox-addr (- first-reward-cycle u1) "stack-stx" lock-period signer-sig signer-key amount-ustx max-amount auth-id))
+
+ ;; ensure that stacking can be performed
+ (try! (can-stack-stx pox-addr amount-ustx first-reward-cycle lock-period))
+
+ ;; register the PoX address with the amount stacked
+ (let ((reward-set-indexes (try! (add-pox-addr-to-reward-cycles pox-addr first-reward-cycle lock-period amount-ustx tx-sender signer-key))))
+ ;; add stacker record
+ (map-set stacking-state
+ { stacker: tx-sender }
+ { pox-addr: pox-addr,
+ reward-set-indexes: reward-set-indexes,
+ first-reward-cycle: first-reward-cycle,
+ lock-period: lock-period,
+ delegated-to: none })
+
+ ;; return the lock-up information, so the node can actually carry out the lock.
+ (ok { stacker: tx-sender, lock-amount: amount-ustx, signer-key: signer-key, unlock-burn-height: (reward-cycle-to-burn-height (+ first-reward-cycle lock-period)) }))))
+```
+{% endcode %}
+
+First let's cover the needed parameters.
+
+* `amount-ustx` is the amount of STX you would like to lock, denoted in micro-STX, or uSTX (1 STX = 1,000,000 uSTX).
+* `pox-addr` is a tuple that encodes the Bitcoin address to be used for the PoX rewards, details below.
+* `start-burn-ht` is the Bitcoin block height you would like to begin stacking. You will receive rewards in the reward cycle following `start-burn-ht`. Importantly, `start-burn-ht` may not be further into the future than the current reward cycle, and in most cases should be set to the current burn block height.
+* `lock-period` sets the number of reward cycles you would like you lock your STX for, this can be between 1 and 12.
+* `signer-sig` is a unique generated signature that proves ownership of this signer. Further details for its role and how to generate it can be found in the [How to Stack](/broken/pages/930b16324611cdbf3451ca2b306ada93a1be367e) document.
+* `signer-key` is the public key of your signer, more details in the [How to Run a Signer](/broken/pages/5baf2f4c67696dbef7258f50d4cbf103b3e014d1) document.
+* `max-amount` sets the maximum amount allowed to be stacked during the provided stacking period.
+* `auth-id` is a unique string to prevent re-use of this stacking transaction.
+
+{% hint style="warning" %}
+It's important to make sure that these fields match what you pass in to the signer signature generation. If they don't, you will likely get error 35 (`ERR_INVALID_SIGNATURE_PUBKEY`) when trying to submit this transaction as the signer signature will not be valid.
+{% endhint %}
+
+### Supported Reward Address Types
+
+{% hint style="info" %}
+For the `pox-addr` field, the `version` buffer must represent what kind of bitcoin address is being submitted. These are all the possible values you can pass here depending on your address type:
+
+```clojure
+(define-constant ADDRESS_VERSION_P2PKH 0x00)
+(define-constant ADDRESS_VERSION_P2SH 0x01)
+(define-constant ADDRESS_VERSION_P2WPKH 0x02)
+(define-constant ADDRESS_VERSION_P2WSH 0x03)
+(define-constant ADDRESS_VERSION_NATIVE_P2WPKH 0x04)
+(define-constant ADDRESS_VERSION_NATIVE_P2WSH 0x05)
+(define-constant ADDRESS_VERSION_NATIVE_P2TR 0x06)
+```
+
+The `hashbytes` are the 20 hash bytes of the bitcoin address. You can obtain that from a bitcoin library, for instance using [`bitcoinjs-lib`](https://github.com/bitcoinjs/bitcoinjs-lib):
+
+```javascript
+const btc = require("bitcoinjs-lib");
+console.log(
+ "0x" +
+ btc.address
+ .fromBase58Check("1C56LYirKa3PFXFsvhSESgDy2acEHVAEt6")
+ .hash.toString("hex")
+);
+```
+{% endhint %}
+
+The `stack-stx` function performs several checks including:
+
+* The `start-burn-ht` results in the next reward cycle
+* The function is being called by the `tx-sender` or an allowed contract caller
+* The `tx-sender` is not currently stacking or delegating
+* The `tx-sender` has enough funds
+* The given `signer-key` is valid, proving ownership
+* Stacking can be performed (amount meets minimum threshold, lock period and bitcoin address are valid)
+
+Next the function registers the provided PoX address for the next reward cycle, assigns its specific reward slot, and adds it to the `stacking-state` map, which keeps track of all current stackers per reward cycle.
+
+Finally it returns the lock-up information so the node can carry out the lock. This step is what actually locks the STX and prevents the stacker from using them on-chain.
+
+From here, the locked STX tokens will be unlocked automatically at the end of the lock period. The stacker can also call `stack-increase` or `stack-extend` to increase the amount locked or extend the time.
+
+***
+
+## Delegated Stacking
+
+Delegated stacking is essentially a multi-step process where delegators give pool operators permission to lock STX on their behalf. The typical flow:
+
+{% stepper %}
+{% step %}
+### Step: Delegator delegates their STX to a pool operator
+
+The delegator calls `delegate-stx` to record that they delegate a given amount to a specific pool operator. This does not lock the STX — it only records the delegation permission.
+{% endstep %}
+
+{% step %}
+### Step: Pool operator stacks delegated STX (partial)
+
+The pool operator calls `delegate-stack-stx` for each delegator they will lock on behalf of. This marks those STX as partially stacked (not yet in the official reward set).
+{% endstep %}
+
+{% step %}
+### Step: Pool operator commits aggregated locks
+
+When the pool operator has aggregated enough delegated STX, they call `stack-aggregation-commit-indexed` (wraps `inner-stack-aggregation-commit`) to commit the aggregated stake into the reward set for the reward cycle.
+{% endstep %}
+{% endstepper %}
+
+There are also alternative actions like revoking delegation (see contract functions).
+
+***
+
+### delegate-stx
+
+This function is called by the individual stacker delegating their STX to a pool operator. An individual stacker choosing to delegate does not need to run their own signer.
+
+This function does not actually lock the STX, but just allows the pool operator to issue the lock.
+
+{% code title="pox-4: delegate-stx" %}
+```clojure
+(define-public (delegate-stx (amount-ustx uint)
+ (delegate-to principal)
+ (until-burn-ht (optional uint))
+ (pox-addr (optional { version: (buff 1), hashbytes: (buff 32) })))
+
+ (begin
+ ;; must be called directly by the tx-sender or by an allowed contract-caller
+ (asserts! (check-caller-allowed)
+ (err ERR_STACKING_PERMISSION_DENIED))
+
+ ;; delegate-stx no longer requires the delegator to not currently
+ ;; be stacking.
+ ;; delegate-stack-* functions assert that
+ ;; 1. users can't swim in two pools at the same time.
+ ;; 2. users can't switch pools without cool down cycle.
+ ;; Other pool admins can't increase or extend.
+ ;; 3. users can't join a pool while already directly stacking.
+
+ ;; pox-addr, if given, must be valid
+ (match pox-addr
+ address
+ (asserts! (check-pox-addr-version (get version address))
+ (err ERR_STACKING_INVALID_POX_ADDRESS))
+ true)
+
+ ;; tx-sender must not be delegating
+ (asserts! (is-none (get-check-delegation tx-sender))
+ (err ERR_STACKING_ALREADY_DELEGATED))
+
+ ;; add delegation record
+ (map-set delegation-state
+ { stacker: tx-sender }
+ { amount-ustx: amount-ustx,
+ delegated-to: delegate-to,
+ until-burn-ht: until-burn-ht,
+ pox-addr: pox-addr })
+
+ (ok true)))
+```
+{% endcode %}
+
+Parameters:
+
+* `amount-ustx`: amount delegating (uSTX)
+* `delegate-to`: Stacks address of the pool operator
+* `until-burn-ht`: optional expiry burn height for the delegation
+* `pox-addr`: optional Bitcoin address where this delegator wants rewards sent (if supplied, pool operator must send rewards to this address)
+
+Checks: caller allowed, `pox-addr` version valid if provided, delegator not already delegating. Updates `delegation-state`. No STX are locked yet — the pool operator must call `delegate-stack-stx`.
+
+***
+
+### delegate-stack-stx
+
+Called by the pool operator to partially stack a delegator's STX.
+
+{% code title="pox-4: delegate-stack-stx" %}
+```clojure
+(define-public (delegate-stack-stx (stacker principal)
+ (amount-ustx uint)
+ (pox-addr { version: (buff 1), hashbytes: (buff 32) })
+ (start-burn-ht uint)
+ (lock-period uint))
+ ;; this stacker's first reward cycle is the _next_ reward cycle
+ (let ((first-reward-cycle (+ u1 (current-pox-reward-cycle)))
+ (specified-reward-cycle (+ u1 (burn-height-to-reward-cycle start-burn-ht)))
+ (unlock-burn-height (reward-cycle-to-burn-height (+ (current-pox-reward-cycle) u1 lock-period))))
+ ;; the start-burn-ht must result in the next reward cycle, do not allow stackers
+ ;; to "post-date" their `stack-stx` transaction
+ (asserts! (is-eq first-reward-cycle specified-reward-cycle)
+ (err ERR_INVALID_START_BURN_HEIGHT))
+
+ ;; must be called directly by the tx-sender or by an allowed contract-caller
+ (asserts! (check-caller-allowed)
+ (err ERR_STACKING_PERMISSION_DENIED))
+
+ ;; stacker must have delegated to the caller
+ (let ((delegation-info (unwrap! (get-check-delegation stacker) (err ERR_STACKING_PERMISSION_DENIED))))
+ ;; must have delegated to tx-sender
+ (asserts! (is-eq (get delegated-to delegation-info) tx-sender)
+ (err ERR_STACKING_PERMISSION_DENIED))
+ ;; must have delegated enough stx
+ (asserts! (>= (get amount-ustx delegation-info) amount-ustx)
+ (err ERR_DELEGATION_TOO_MUCH_LOCKED))
+ ;; if pox-addr is set, must be equal to pox-addr
+ (asserts! (match (get pox-addr delegation-info)
+ specified-pox-addr (is-eq pox-addr specified-pox-addr)
+ true)
+ (err ERR_DELEGATION_POX_ADDR_REQUIRED))
+ ;; delegation must not expire before lock period
+ (asserts! (match (get until-burn-ht delegation-info)
+ until-burn-ht (>= until-burn-ht
+ unlock-burn-height)
+ true)
+ (err ERR_DELEGATION_EXPIRES_DURING_LOCK))
+ )
+
+ ;; stacker principal must not be stacking
+ (asserts! (is-none (get-stacker-info stacker))
+ (err ERR_STACKING_ALREADY_STACKED))
+
+ ;; the Stacker must have sufficient unlocked funds
+ (asserts! (>= (stx-get-balance stacker) amount-ustx)
+ (err ERR_STACKING_INSUFFICIENT_FUNDS))
+
+ ;; ensure that stacking can be performed
+ (try! (minimal-can-stack-stx pox-addr amount-ustx first-reward-cycle lock-period))
+
+ ;; register the PoX address with the amount stacked via partial stacking
+ ;; before it can be included in the reward set, this must be committed!
+ (add-pox-partial-stacked pox-addr first-reward-cycle lock-period amount-ustx)
+
+ ;; add stacker record
+ (map-set stacking-state
+ { stacker: stacker }
+ { pox-addr: pox-addr,
+ first-reward-cycle: first-reward-cycle,
+ reward-set-indexes: (list),
+ lock-period: lock-period,
+ delegated-to: (some tx-sender) })
+
+ ;; return the lock-up information, so the node can actually carry out the lock.
+ (ok { stacker: stacker,
+ lock-amount: amount-ustx,
+ unlock-burn-height: unlock-burn-height })))
+```
+{% endcode %}
+
+This function validates the delegation record, ensures the delegator has the funds and is not already stacking, runs lightweight stacking checks, registers the partial stacked amount, and updates `stacking-state`. The STX remain partially stacked until the operator commits.
+
+***
+
+### stack-aggregation-commit-indexed / inner-stack-aggregation-commit
+
+The `stack-aggregation-commit-indexed` function wraps the private `inner-stack-aggregation-commit`. The private function commits partially stacked amounts into the reward set so each pox-addr obtains a reward-slot index.
+
+{% code title="pox-4: inner-stack-aggregation-commit" %}
+```clojure
+(define-private (inner-stack-aggregation-commit (pox-addr { version: (buff 1), hashbytes: (buff 32) })
+ (reward-cycle uint)
+ (signer-sig (optional (buff 65)))
+ (signer-key (buff 33))
+ (max-amount uint)
+ (auth-id uint))
+ (let ((partial-stacked
+ ;; fetch the partial commitments
+ (unwrap! (map-get? partial-stacked-by-cycle { pox-addr: pox-addr, sender: tx-sender, reward-cycle: reward-cycle })
+ (err ERR_STACKING_NO_SUCH_PRINCIPAL))))
+ ;; must be called directly by the tx-sender or by an allowed contract-caller
+ (asserts! (check-caller-allowed)
+ (err ERR_STACKING_PERMISSION_DENIED))
+ (let ((amount-ustx (get stacked-amount partial-stacked)))
+ (try! (consume-signer-key-authorization pox-addr reward-cycle "agg-commit" u1 signer-sig signer-key amount-ustx max-amount auth-id))
+ (try! (can-stack-stx pox-addr amount-ustx reward-cycle u1))
+ ;; Add the pox addr to the reward cycle, and extract the index of the PoX address
+ ;; so the delegator can later use it to call stack-aggregation-increase.
+ (let ((add-pox-addr-info
+ (add-pox-addr-to-ith-reward-cycle
+ u0
+ { pox-addr: pox-addr,
+ first-reward-cycle: reward-cycle,
+ num-cycles: u1,
+ reward-set-indexes: (list),
+ stacker: none,
+ signer: signer-key,
+ amount-ustx: amount-ustx,
+ i: u0 }))
+ (pox-addr-index (unwrap-panic
+ (element-at (get reward-set-indexes add-pox-addr-info) u0))))
+
+ ;; don't update the stacking-state map,
+ ;; because it _already has_ this stacker's state
+ ;; don't lock the STX, because the STX is already locked
+ ;;
+ ;; clear the partial-stacked state, and log it
+ (map-delete partial-stacked-by-cycle { pox-addr: pox-addr, sender: tx-sender, reward-cycle: reward-cycle })
+ (map-set logged-partial-stacked-by-cycle { pox-addr: pox-addr, sender: tx-sender, reward-cycle: reward-cycle } partial-stacked)
+ (ok pox-addr-index)))))
+```
+{% endcode %}
+
+Key points:
+
+* Validates caller and signer signature.
+* Validates stacking conditions.
+* Adds the aggregated pox-addr to the reward cycle and returns its reward-set index.
+* Deletes the partial-stacked entry and logs it.
+
+***
+
+## How Stacking Reward Distribution Works
+
+All of the above stacking functions take a `pox-addr` field that corresponds to a Bitcoin address where BTC rewards will be sent. It's important to understand how these addresses are used and how reward distribution is handled.
+
+How Bitcoin rewards are distributed is primarily up to the discretion of the pool operator. Since PoX reward distributions are handled using Bitcoin transactions, there is currently not an effective way to automate their distribution to individual delegated stackers.
+
+Role of `pox-addr` by function:
+
+* stack-stx: Bitcoin address for the solo stacker to receive rewards.
+* delegate-stx: Optional. If omitted, the pool operator decides where to send this delegator's rewards. If provided, the pool operator must send rewards to that address. Note: if provided, the delegator must have enough STX to meet the minimum stacking amount (each unique `pox-addr` consumes a reward slot).
+* delegate-stack-stx and stack-aggregation-commit-indexed: `pox-addr` is where the pool operator will receive BTC rewards for that aggregated stake. Pool operators typically use wrapper contracts or off-chain accounting to distribute BTC to delegators.
+
+***
+
+## Errors
+
+You may encounter several errors when trying to perform stacking operations. Below are some of the more common errors with explanations and how to resolve them.
+
+
+
+Error 35 - ERR_INVALID_SIGNATURE_PUBKEY
+
+This is likely the most common error you will encounter, and you'll usually see it in a failed `stack-stx` or `stack-aggregation-commit` transaction.
+
+This error occurs in `consume-signer-key-authorization` which is called any time a signer signature is provided.
+
+Possible causes:
+
+* The public key you used to generate the signer signature is not the same as the one you are passing in to the `signer-key` field.
+* One of the fields you passed in to generate your signer signature does not match the field you passed in to either the `stack-stx` or `stack-aggregation-commit` function.
+
+How to fix: verify that the signer signature was generated using the exact same signer public key and parameters (amount, pox-addr/reward-cycle, lock period, max-amount, auth-id, etc.) as what you are passing into the contract call.
+
+
+
+
+
+Error 4 - ERR_STACKING_NO_SUCH_PRINCIPAL
+
+This error means the contract lookup for a partially stacked entry failed. The stacking contract looks up partially stacked STX (after `delegate-stack-stx`) by the key `(pox-addr, stx-address, reward-cycle)`. If any of those parameters are wrong when generating the signature or calling `stack-aggregation-commit`, the lookup will fail.
+
+How to fix: check that the `pox-addr`, `stacker` principal (stx address), and `reward-cycle` values match exactly what was used in `delegate-stack-stx` / the signature generation. See the [stacking guide](/broken/pages/930b16324611cdbf3451ca2b306ada93a1be367e#delegator-initiates-delegation) for delegation flow details.
+
+
+
+
+
+Error 24 - ERR_INVALID_START_BURN_HEIGHT
+
+This means the `start-burn-height` parameter parsed was invalid (it corresponded to a past or future cycle rather than the current next reward cycle). You will mostly see this in `stack-stx` or `delegate-stack-stx` failed transactions.
+
+How to fix: set `start-burn-ht` to the current burn block height corresponding to the next reward cycle (or compute it using node APIs / libraries that map burn height to reward cycles).
+
+
diff --git a/docs/reference/clarity/functions.md b/docs/reference/clarity/functions.md
new file mode 100644
index 0000000000..ab981afe2b
--- /dev/null
+++ b/docs/reference/clarity/functions.md
@@ -0,0 +1,2394 @@
+---
+description: The complete reference guide to all Clarity functions.
+---
+
+# Functions
+
+## \* (multiply)
+
+Introduced in: **Clarity 1**
+
+**input:** `int, ... | uint, ...`\
+**output:** `int | uint`\
+**signature:** `(* i1 i2...)`
+
+**description:**\
+Multiplies a variable number of integer inputs and returns the result. In the event of an _overflow_, throws a runtime error.
+
+**example:**
+
+```clojure
+(* 2 3) ;; Returns 6
+(* 5 2) ;; Returns 10
+(* 2 2 2) ;; Returns 8
+```
+
+***
+
+## + (add)
+
+Introduced in: **Clarity 1**
+
+**input:** `int, ... | uint, ...`\
+**output:** `int | uint`\
+**signature:** `(+ i1 i2...)`
+
+**description:**\
+Adds a variable number of integer inputs and returns the result. In the event of an _overflow_, throws a runtime error.
+
+**example:**
+
+```clojure
+(+ 1 2 3) ;; Returns 6
+```
+
+***
+
+## - (subtract)
+
+Introduced in: **Clarity 1**
+
+**input:** `int, ... | uint, ...`\
+**output:** `int | uint`\
+**signature:** `(- i1 i2...)`
+
+**description:**\
+Subtracts a variable number of integer inputs and returns the result. In the event of an _underflow_, throws a runtime error.
+
+**example:**
+
+```clojure
+(- 2 1 1) ;; Returns 0
+(- 0 3) ;; Returns -3
+```
+
+***
+
+## / (divide)
+
+Introduced in: **Clarity 1**
+
+**input:** `int, ... | uint, ...`\
+**output:** `int | uint`\
+**signature:** `(/ i1 i2...)`
+
+**description:**\
+Integer divides a variable number of integer inputs and returns the result. In the event of division by zero, throws a runtime error.
+
+**example:**
+
+```clojure
+(/ 2 3) ;; Returns 0
+(/ 5 2) ;; Returns 2
+(/ 4 2 2) ;; Returns 1
+```
+
+***
+
+## < (less than)
+
+Introduced in: **Clarity 1**
+
+**input:** `int, int | uint, uint | string-ascii, string-ascii | string-utf8, string-utf8 | buff, buff`\
+**output:** `bool`\
+**signature:** `(< i1 i2)`
+
+**description:**\
+Compares two integers (or other comparable types), returning `true` if `i1` is less than `i2` and `false` otherwise. i1 and i2 must be of the same type.
+
+* Starting with Stacks 1.0: comparable types are `int` and `uint`.
+* Starting with Stacks 2.1: comparable types also include `string-ascii`, `string-utf8` and `buff`.
+
+**example:**
+
+```clojure
+(< 1 2) ;; Returns true
+(< 5 2) ;; Returns false
+(< "aaa" "baa") ;; Returns true
+(< "aa" "aaa") ;; Returns true
+(< 0x01 0x02) ;; Returns true
+(< 5 u2) ;; Throws type error
+```
+
+***
+
+## <= (less than or equal)
+
+Introduced in: **Clarity 1**
+
+**input:** `int, int | uint, uint | string-ascii, string-ascii | string-utf8, string-utf8 | buff, buff`\
+**output:** `bool`\
+**signature:** `(<= i1 i2)`
+
+**description:**\
+Compares two values, returning `true` if `i1` is less than or equal to `i2`. Types must match. Same type support notes as `<`.
+
+**example:**
+
+```clojure
+(<= 1 1) ;; Returns true
+(<= 5 2) ;; Returns false
+(<= "aaa" "baa") ;; Returns true
+(<= "aa" "aaa") ;; Returns true
+(<= 0x01 0x02) ;; Returns true
+(<= 5 u2) ;; Throws type error
+```
+
+***
+
+## > (greater than)
+
+Introduced in: **Clarity 1**
+
+**input:** `int, int | uint, uint | string-ascii, string-ascii | string-utf8, string-utf8 | buff, buff`\
+**output:** `bool`\
+**signature:** `(> i1 i2)`
+
+**description:**\
+Compares two values, returning `true` if `i1` is greater than `i2`. Types must match. Same type support notes as `<`.
+
+**example:**
+
+```clojure
+(> 1 2) ;; Returns false
+(> 5 2) ;; Returns true
+(> "baa" "aaa") ;; Returns true
+(> "aaa" "aa") ;; Returns true
+(> 0x02 0x01) ;; Returns true
+(> 5 u2) ;; Throws type error
+```
+
+***
+
+## >= (greater than or equal)
+
+Introduced in: **Clarity 1**
+
+**input:** `int, int | uint, uint | string-ascii, string-ascii | string-utf8, string-utf8 | buff, buff`\
+**output:** `bool`\
+**signature:** `(>= i1 i2)`
+
+**description:**\
+Compares two values, returning `true` if `i1` is greater than or equal to `i2`. Types must match. Same type support notes as `<`.
+
+**example:**
+
+```clojure
+(>= 1 1) ;; Returns true
+(>= 5 2) ;; Returns true
+(>= "baa" "aaa") ;; Returns true
+(>= "aaa" "aa") ;; Returns true
+(>= 0x02 0x01) ;; Returns true
+(>= 5 u2) ;; Throws type error
+```
+
+***
+
+## and
+
+Introduced in: **Clarity 1**
+
+**input:** `bool, ...`\
+**output:** `bool`\
+**signature:** `(and b1 b2 ...)`
+
+**description:**\
+Returns `true` if all boolean inputs are `true`. Arguments are evaluated in-order and lazily (short-circuits on `false`).
+
+**example:**
+
+```clojure
+(and true false) ;; Returns false
+(and (is-eq (+ 1 2) 1) (is-eq 4 4)) ;; Returns false
+(and (is-eq (+ 1 2) 3) (is-eq 4 4)) ;; Returns true
+```
+
+***
+
+## append
+
+Introduced in: **Clarity 1**
+
+**input:** `list A, A`\
+**output:** `list`\
+**signature:** `(append (list 1 2 3 4) 5)`
+
+**description:**\
+Takes a list and a value of the same entry type, and returns a new list with max\_len += 1 (effectively appending the value).
+
+**example:**
+
+```clojure
+(append (list 1 2 3 4) 5) ;; Returns (1 2 3 4 5)
+```
+
+***
+
+## as-contract?
+
+Introduced in: **Clarity 4**
+
+{% hint style="info" %}
+The previous version of `as-contract`, introduced in Clarity 1, has changed to `as-contract?` in Clarity 4, with several new security enhancements. If you are using Clarity 1-3, the previous signature and description for `as-contract` can be found in the dropdown below.
+{% endhint %}
+
+
+
+Previous as-contract
+
+**input:** `A` **output:** `A` **signature:** `(as-contract expr)`
+
+**description:** Executes `expr` with the tx-sender switched to the contract's principal and returns the result.
+
+**example:**
+
+Copy
+
+```
+(as-contract tx-sender) ;; Returns S1G2081040G2081040G2081040G208105NK8PE5.docs-test
+```
+
+
+
+**Input**:
+
+* `((with-stx|with-ft|with-nft|with-stacking)*|with-all-assets-unsafe)`: The set of allowances (at most 128) to grant during the evaluation of the body expressions. Note that `with-all-assets-unsafe` is mutually exclusive with other allowances.
+* `AnyType* A`: The Clarity expressions to be executed within the context, with the final expression returning type `A`, where `A` is not a `response`
+
+**Output**: `(response A uint)`
+
+**Signature**: `(as-contract? ((with-stx|with-ft|with-nft|with-stacking)*|with-all-assets-unsafe) expr-body1 expr-body2 ... expr-body-last)`
+
+**Description**: Switches the current context's `tx-sender` and `contract-caller` values to the contract's principal and executes the body expressions within that context, then checks the asset outflows from the contract against the granted allowances, in declaration order. If any allowance is violated, the body expressions are reverted and an error is returned. Note that the allowance setup expressions are evaluated before executing the body expressions. The final body expression cannot return a `response` value in order to avoid returning a nested `response` value from `as-contract?` (nested responses are error-prone). Returns:
+
+* `(ok x)` if the outflows are within the allowances, where `x` is the result of the final body expression and has type `A`.
+* `(err index)` if an allowance was violated, where `index` is the 0-based index of the first violated allowance in the list of granted allowances, or `u128` if an asset with no allowance caused the violation.
+
+**Example**:
+
+```
+(define-public (foo)
+ (as-contract? ()
+ (try! (stx-transfer? u1000000 tx-sender recipient))
+ )
+) ;; Returns (err u128)
+(define-public (bar)
+ (as-contract? ((with-stx u1000000))
+ (try! (stx-transfer? u1000000 tx-sender recipient))
+ )
+) ;; Returns (ok true)
+```
+
+***
+
+## as-max-len?
+
+Introduced in: **Clarity 1**
+
+**input:** `sequence_A, uint`\
+**output:** `(optional sequence_A)`\
+**signature:** `(as-max-len? sequence max_length)`
+
+**description:**\
+If the sequence length ≤ max\_length, returns `(some sequence)`, otherwise `none`. Applies to `(list A)`, `buff`, `string-ascii`, `string-utf8`.
+
+**example:**
+
+```clojure
+(as-max-len? (list 2 2 2) u3) ;; Returns (some (2 2 2))
+(as-max-len? (list 1 2 3) u2) ;; Returns none
+(as-max-len? "hello" u10) ;; Returns (some "hello")
+(as-max-len? 0x010203 u10) ;; Returns (some 0x010203)
+```
+
+***
+
+## asserts!
+
+Introduced in: **Clarity 1**
+
+**input:** `bool, C`\
+**output:** `bool`\
+**signature:** `(asserts! bool-expr thrown-value)`
+
+**description:**\
+If `bool-expr` is `true`, returns `true` and continues. If `false`, returns `thrown-value` and exits current control-flow.
+
+**example:**
+
+```clojure
+(asserts! (is-eq 1 1) (err 1)) ;; Returns true
+```
+
+***
+
+## at-block
+
+Introduced in: **Clarity 1**
+
+**input:** `(buff 32), A`\
+**output:** `A`\
+**signature:** `(at-block id-block-hash expr)`
+
+**description:**\
+Evaluates `expr` as if evaluated at the end of the block identified by `id-block-hash`. `expr` must be read-only. The block hash must be from `id-header-hash`.
+
+**example:**
+
+```clojure
+(define-data-var data int 1)
+(at-block 0x0000000000000000000000000000000000000000000000000000000000000000 block-height) ;; Returns u0
+(at-block (get-block-info? id-header-hash 0) (var-get data)) ;; Throws NoSuchDataVariable because `data` wasn't initialized at block height 0
+```
+
+***
+
+## begin
+
+Introduced in: **Clarity 1**
+
+**input:** `AnyType, ... A`\
+**output:** `A`\
+**signature:** `(begin expr1 expr2 expr3 ... expr-last)`
+
+**description:**\
+Evaluates each expression in order and returns the value of the last expression. Note: intermediary statements returning a response type must be checked.
+
+**example:**
+
+```clojure
+(begin (+ 1 2) 4 5) ;; Returns 5
+```
+
+***
+
+## bit-and
+
+Introduced in: **Clarity 2**
+
+**input:** `int, ... | uint, ...`\
+**output:** `int | uint`\
+**signature:** `(bit-and i1 i2...)`
+
+**description:**\
+Bitwise AND across a variable number of integer inputs.
+
+**example:**
+
+```clojure
+(bit-and 24 16) ;; Returns 16
+(bit-and 28 24 -1) ;; Returns 24
+(bit-and u24 u16) ;; Returns u16
+(bit-and -128 -64) ;; Returns -128
+```
+
+***
+
+## bit-not
+
+Introduced in: **Clarity 2**
+
+**input:** `int | uint`\
+**output:** `int | uint`\
+**signature:** `(bit-not i1)`
+
+**description:**\
+Returns the one's complement (bitwise NOT) of `i1`.
+
+**example:**
+
+```clojure
+(bit-not 3) ;; Returns -4
+(bit-not u128) ;; Returns u340282366920938463463374607431768211327
+(bit-not 128) ;; Returns -129
+(bit-not -128) ;; Returns 127
+```
+
+***
+
+## bit-or
+
+Introduced in: **Clarity 2**
+
+**input:** `int, ... | uint, ...`\
+**output:** `int | uint`\
+**signature:** `(bit-or i1 i2...)`
+
+**description:**\
+Bitwise inclusive OR across a variable number of integer inputs.
+
+**example:**
+
+```clojure
+(bit-or 4 8) ;; Returns 12
+(bit-or 1 2 4) ;; Returns 7
+(bit-or 64 -32 -16) ;; Returns -16
+(bit-or u2 u4 u32) ;; Returns u38
+```
+
+***
+
+## bit-shift-left
+
+Introduced in: **Clarity 2**
+
+**input:** `int, uint | uint, uint`\
+**output:** `int | uint`\
+**signature:** `(bit-shift-left i1 shamt)`
+
+**description:**\
+Shifts bits of `i1` left by `shamt` modulo 128. Does not check for arithmetic overflow — use `*`, `/`, `pow` if overflow detection is needed.
+
+**example:**
+
+```clojure
+(bit-shift-left 2 u1) ;; Returns 4
+(bit-shift-left 16 u2) ;; Returns 64
+(bit-shift-left -64 u1) ;; Returns -128
+(bit-shift-left u4 u2) ;; Returns u16
+(bit-shift-left 123 u9999999999) ;; Returns -170141183460469231731687303715884105728
+(bit-shift-left -1 u7) ;; Returns -128
+(bit-shift-left -1 u128) ;; Returns -1
+```
+
+***
+
+## bit-shift-right
+
+Introduced in: **Clarity 2**
+
+**input:** `int, uint | uint, uint`\
+**output:** `int | uint`\
+**signature:** `(bit-shift-right i1 shamt)`
+
+**description:**\
+Shifts bits of `i1` right by `shamt` modulo 128. For `uint` fills with zeros; for `int` preserves sign bit. Does not check for arithmetic overflow.
+
+**example:**
+
+```clojure
+(bit-shift-right 2 u1) ;; Returns 1
+(bit-shift-right 128 u2) ;; Returns 32
+(bit-shift-right -64 u1) ;; Returns -32
+(bit-shift-right u128 u2) ;; Returns u32
+(bit-shift-right 123 u9999999999) ;; Returns 0
+(bit-shift-right -128 u7) ;; Returns -1
+```
+
+***
+
+## bit-xor
+
+Introduced in: **Clarity 2**
+
+**input:** `int, ... | uint, ...`\
+**output:** `int | uint`\
+**signature:** `(bit-xor i1 i2...)`
+
+**description:**\
+Bitwise exclusive OR across a variable number of integer inputs.
+
+**example:**
+
+```clojure
+(bit-xor 1 2) ;; Returns 3
+(bit-xor 120 280) ;; Returns 352
+(bit-xor -128 64) ;; Returns -64
+(bit-xor u24 u4) ;; Returns u28
+(bit-xor 1 2 4 -1) ;; Returns -8
+```
+
+***
+
+## buff-to-int-be
+
+Introduced in: **Clarity 2**
+
+**input:** `(buff 16)`\
+**output:** `int`\
+**signature:** `(buff-to-int-be (buff 16))`
+
+**description:**\
+Converts a buffer to a signed integer using big-endian encoding. Buffer up to 16 bytes; if fewer, it behaves as if left-zero-padded. Available starting Stacks 2.1.
+
+**example:**
+
+```clojure
+(buff-to-int-be 0x01) ;; Returns 1
+(buff-to-int-be 0x00000000000000000000000000000001) ;; Returns 1
+(buff-to-int-be 0xffffffffffffffffffffffffffffffff) ;; Returns -1
+(buff-to-int-be 0x) ;; Returns 0
+```
+
+***
+
+## buff-to-int-le
+
+Introduced in: **Clarity 2**
+
+**input:** `(buff 16)`\
+**output:** `int`\
+**signature:** `(buff-to-int-le (buff 16))`
+
+**description:**\
+Converts a buffer to a signed integer using little-endian encoding. Up to 16 bytes; fewer bytes behave as right-zero-padded. Available starting Stacks 2.1.
+
+**example:**
+
+```clojure
+(buff-to-int-le 0x01) ;; Returns 1
+(buff-to-int-le 0x01000000000000000000000000000000) ;; Returns 1
+(buff-to-int-le 0xffffffffffffffffffffffffffffffff) ;; Returns -1
+(buff-to-int-le 0x) ;; Returns 0
+```
+
+***
+
+## buff-to-uint-be
+
+Introduced in: **Clarity 2**
+
+**input:** `(buff 16)`\
+**output:** `uint`\
+**signature:** `(buff-to-uint-be (buff 16))`
+
+**description:**\
+Converts a buffer to an unsigned integer using big-endian encoding. Up to 16 bytes; fewer bytes behave as left-zero-padded. Available starting Stacks 2.1.
+
+**example:**
+
+```clojure
+(buff-to-uint-be 0x01) ;; Returns u1
+(buff-to-uint-be 0x00000000000000000000000000000001) ;; Returns u1
+(buff-to-uint-be 0xffffffffffffffffffffffffffffffff) ;; Returns u340282366920938463463374607431768211455
+(buff-to-uint-be 0x) ;; Returns u0
+```
+
+***
+
+## buff-to-uint-le
+
+Introduced in: **Clarity 2**
+
+**input:** `(buff 16)`\
+**output:** `uint`\
+**signature:** `(buff-to-uint-le (buff 16))`
+
+**description:**\
+Converts a buffer to an unsigned integer using little-endian encoding. Up to 16 bytes; fewer bytes behave as right-zero-padded. Available starting Stacks 2.1.
+
+**example:**
+
+```clojure
+(buff-to-uint-le 0x01) ;; Returns u1
+(buff-to-uint-le 0x01000000000000000000000000000000) ;; Returns u1
+(buff-to-uint-le 0xffffffffffffffffffffffffffffffff) ;; Returns u340282366920938463463374607431768211455
+(buff-to-uint-le 0x) ;; Returns u0
+```
+
+***
+
+## concat
+
+Introduced in: **Clarity 1**
+
+**input:** `sequence_A, sequence_A`\
+**output:** `sequence_A`\
+**signature:** `(concat sequence1 sequence2)`
+
+**description:**\
+Concatenates two sequences of the same type. Applicable to `(list A)`, `buff`, `string-ascii`, `string-utf8`.
+
+**example:**
+
+```clojure
+(concat (list 1 2) (list 3 4)) ;; Returns (1 2 3 4)
+(concat "hello " "world") ;; Returns "hello world"
+(concat 0x0102 0x0304) ;; Returns 0x01020304
+```
+
+***
+
+## contract-call?
+
+Introduced in: **Clarity 1**
+
+**input:** `ContractName, PublicFunctionName, Arg0, ...`\
+**output:** `(response A B)`\
+**signature:** `(contract-call? .contract-name function-name arg0 arg1 ...)`
+
+**description:**\
+Executes a public function on another contract (not the current contract). If that function returns `err`, any DB changes resulting from the call are aborted; if `ok`, DB changes occurred.
+
+**example:**
+
+```clojure
+;; instantiate the sample-contracts/tokens.clar contract first
+(as-contract (contract-call? .tokens mint! u19)) ;; Returns (ok u19)
+```
+
+***
+
+## contract-hash?
+
+Introduced in: **Clarity 4**
+
+**Input**: `principal`
+
+**Output**: `(response (buff 32) uint)`
+
+**Signature**: `(contract-hash? contract-principal)`
+
+**Description**: Returns the SHA-512/256 hash of the code body of the contract principal specified as input, or an error if the principal is not a contract or the specified contract does not exist. Returns:
+
+* `(ok 0x)`, where `` is the SHA-512/256 hash of the code body, on success
+* `(err u1)` if the principal is not a contract principal
+* `(err u2)` if the specified contract does not exist
+
+**Example**:
+
+```
+(contract-hash? 'SP2QEZ06AGJ3RKJPBV14SY1V5BBFNAW33D96YPGZF.BNS-V2) ;; Returns (ok 0x9f8104ff869aba1205cd5e15f6404dd05675f4c3fe0817c623c425588d981c2f)
+```
+
+***
+
+## contract-of
+
+Introduced in: **Clarity 1**
+
+**input:** `Trait`\
+**output:** `principal`\
+**signature:** `(contract-of .contract-name)`
+
+**description:**\
+Returns the principal of the contract implementing the trait.
+
+**example:**
+
+```clojure
+(use-trait token-a-trait 'SPAXYA5XS51713FDTQ8H94EJ4V579CXMTRNBZKSF.token-a.token-trait)
+(define-public (forward-get-balance (user principal) (contract ))
+ (begin
+ (ok (contract-of contract)))) ;; returns the principal of the contract implementing
+```
+
+***
+
+## default-to
+
+Introduced in: **Clarity 1**
+
+**input:** `A, (optional A)`\
+**output:** `A`\
+**signature:** `(default-to default-value option-value)`
+
+**description:**\
+If the second argument is `(some v)`, returns `v`. If it is `none`, returns `default-value`.
+
+**example:**
+
+```clojure
+(define-map names-map { name: (string-ascii 12) } { id: int })
+(map-set names-map { name: "blockstack" } { id: 1337 })
+(default-to 0 (get id (map-get? names-map (tuple (name "blockstack"))))) ;; Returns 1337
+(default-to 0 (get id (map-get? names-map (tuple (name "non-existant"))))) ;; Returns 0
+```
+
+***
+
+## define-constant
+
+Introduced in: **Clarity 1**
+
+**input:** `MethodSignature, MethodBody`\
+**output:** `Not Applicable`\
+**signature:** `(define-constant name expression)`
+
+**description:**\
+Defines a private constant evaluated at contract launch. Must be top-level. Be mindful of definition order.
+
+**example:**
+
+```clojure
+(define-constant four (+ 2 2))
+(+ 4 four) ;; Returns 8
+```
+
+***
+
+## define-data-var
+
+Introduced in: **Clarity 1**
+
+**input:** `VarName, TypeDefinition, Value`\
+**output:** `Not Applicable`\
+**signature:** `(define-data-var var-name type value)`
+
+**description:**\
+Defines a new persisted variable for the contract. Only modifiable by the contract. Must be top-level.
+
+**example:**
+
+```clojure
+(define-data-var size int 0)
+(define-private (set-size (value int))
+ (var-set size value))
+(set-size 1)
+(set-size 2)
+```
+
+***
+
+## define-fungible-token
+
+Introduced in: **Clarity 1**
+
+**input:** `TokenName, `\
+**output:** `Not Applicable`\
+**signature:** `(define-fungible-token token-name )`
+
+**description:**\
+Defines a fungible token class in the contract. Optional total supply caps minting. Must be top-level.
+
+**example:**
+
+```clojure
+(define-fungible-token stacks)
+(define-fungible-token limited-supply-stacks u100)
+```
+
+***
+
+## define-map
+
+Introduced in: **Clarity 1**
+
+**input:** `MapName, TypeDefinition, TypeDefinition`\
+**output:** `Not Applicable`\
+**signature:** `(define-map map-name key-type value-type)`
+
+**description:**\
+Defines a data map stored by the contract. Must be top-level.
+
+**example:**
+
+```clojure
+(define-map squares { x: int } { square: int })
+(define-private (add-entry (x int))
+ (map-insert squares { x: 2 } { square: (* x x) }))
+(add-entry 1)
+(add-entry 2)
+```
+
+***
+
+## define-non-fungible-token
+
+Introduced in: **Clarity 1**
+
+**input:** `AssetName, TypeSignature`\
+**output:** `Not Applicable`\
+**signature:** `(define-non-fungible-token asset-name asset-identifier-type)`
+
+**description:**\
+Defines an NFT class in the contract. Asset identifiers must be unique. Must be top-level.
+
+**example:**
+
+```clojure
+(define-non-fungible-token names (buff 50))
+```
+
+***
+
+## define-private
+
+Introduced in: **Clarity 1**
+
+**input:** `MethodSignature, MethodBody`\
+**output:** `Not Applicable`\
+**signature:** `(define-private (function-name (arg-name-0 arg-type-0) ...) function-body)`
+
+**description:**\
+Defines a private function callable only within the contract. Must be top-level.
+
+**example:**
+
+```clojure
+(define-private (max-of (i1 int) (i2 int))
+ (if (> i1 i2)
+ i1
+ i2))
+(max-of 4 6) ;; Returns 6
+```
+
+***
+
+## define-public
+
+Introduced in: **Clarity 1**
+
+**input:** `MethodSignature, MethodBody`\
+**output:** `Not Applicable`\
+**signature:** `(define-public (function-name (arg-name-0 arg-type-0) ...) function-body)`
+
+**description:**\
+Defines a public transaction function. Must return a ResponseType (`ok` or `err`). DB changes are aborted if `err`. Must be top-level.
+
+**example:**
+
+```clojure
+(define-public (hello-world (input int))
+ (begin
+ (print (+ 2 input))
+ (ok input)))
+```
+
+***
+
+## define-read-only
+
+Introduced in: **Clarity 1**
+
+**input:** `MethodSignature, MethodBody`\
+**output:** `Not Applicable`\
+**signature:** `(define-read-only (function-name (arg-name-0 arg-type-0) ...) function-body)`
+
+**description:**\
+Defines a public read-only function. Cannot modify data maps or call mutating functions. May return any type. Must be top-level.
+
+**example:**
+
+```clojure
+(define-read-only (just-return-one-hundred)
+ (* 10 10))
+```
+
+***
+
+## define-trait
+
+Introduced in: **Clarity 1**
+
+**input:** `VarName, [MethodSignature]`\
+**output:** `Not Applicable`\
+**signature:** `(define-trait trait-name ((func1-name (arg1-type ...) (return-type))))`
+
+**description:**\
+Defines a trait (interface) other contracts can implement. Must be top-level. Notes about Clarity 1 vs Clarity 2 trait usage and implicit casting in Clarity 2 are included.
+
+**example:**
+
+```clojure
+(define-trait token-trait
+ ((transfer? (principal principal uint) (response uint uint))
+ (get-balance (principal) (response uint uint))))
+```
+
+***
+
+## element-at
+
+Introduced in: **Clarity 1**
+
+**input:** `sequence_A, uint`\
+**output:** `(optional A)`\
+**signature:** `(element-at? sequence index)`
+
+**description:**\
+Returns the element at `index` in the sequence as an optional. Applicable types: `(list A)`, `buff`, `string-ascii`, `string-utf8`. In Clarity 1 spelled `element-at` (alias).
+
+**example:**
+
+```clojure
+(element-at? "blockstack" u5) ;; Returns (some "s")
+(element-at? (list 1 2 3 4 5) u5) ;; Returns none
+(element-at? (list 1 2 3 4 5) (+ u1 u2)) ;; Returns (some 4)
+(element-at? "abcd" u1) ;; Returns (some "b")
+(element-at? 0xfb01 u1) ;; Returns (some 0x01)
+```
+
+***
+
+## element-at?
+
+Introduced in: **Clarity 2**
+
+(Same as element-at; retained as Clarity 2 preferred spelling)
+
+**example:** (see element-at above)
+
+***
+
+## err
+
+Introduced in: **Clarity 1**
+
+**input:** `A`\
+**output:** `(response A B)`\
+**signature:** `(err value)`
+
+**description:**\
+Constructs an `err` response. Use for returning errors from public functions; indicates DB changes should be rolled back.
+
+**example:**
+
+```clojure
+(err true) ;; Returns (err true)
+```
+
+***
+
+## filter
+
+Introduced in: **Clarity 1**
+
+**input:** `Function(A) -> bool, sequence_A`\
+**output:** `sequence_A`\
+**signature:** `(filter func sequence)`
+
+**description:**\
+Filters elements of a sequence by applying `func` to each element and keeping those where `func` returns `true`. `func` must be a literal function name. Applies to `(list A)`, `buff`, `string-ascii`, `string-utf8`.
+
+**example:**
+
+```clojure
+(filter not (list true false true false)) ;; Returns (false false)
+(define-private (is-a (char (string-utf8 1)))
+ (is-eq char u"a"))
+(filter is-a u"acabd") ;; Returns u"aa"
+```
+
+***
+
+## fold
+
+Introduced in: **Clarity 1**
+
+**input:** `Function(A, B) -> B, sequence_A, B`\
+**output:** `B`\
+**signature:** `(fold func sequence_A initial_B)`
+
+**description:**\
+Reduces a sequence to a single value by applying `func` cumulatively, starting with `initial_B`.
+
+**example:**
+
+```clojure
+(fold * (list 2 2 2) 1) ;; Returns 8
+(fold - (list 3 7 11) 2) ;; Returns 5
+```
+
+(Examples showing string/buffer concatenation omitted here; see original for fuller set.)
+
+***
+
+## from-consensus-buff?
+
+Introduced in: **Clarity 2**
+
+**input:** `type-signature(t), buff`\
+**output:** `(optional t)`\
+**signature:** `(from-consensus-buff? type-signature buffer)`
+
+**description:**\
+Deserializes a buffer into a Clarity value using SIP-005 consensus serialization. Returns `some` on success, `none` on failure.
+
+**example:**
+
+```clojure
+(from-consensus-buff? int 0x0000000000000000000000000000000001) ;; Returns (some 1)
+(from-consensus-buff? uint 0x0000000000000000000000000000000001) ;; Returns none
+(from-consensus-buff? bool 0x03) ;; Returns (some true)
+(from-consensus-buff? principal 0x051fa46ff88886c2ef9762d970b4d2c63678835bd39d) ;; Returns (some SZ2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKQ9H6DPR)
+```
+
+***
+
+## ft-burn?
+
+Introduced in: **Clarity 1**
+
+**input:** `TokenName, uint, principal`\
+**output:** `(response bool uint)`\
+**signature:** `(ft-burn? token-name amount sender)`
+
+**description:**\
+Burns (destroys) `amount` of `token-name` from `sender`'s balance. On success returns `(ok true)`. Error `(err u1)` - insufficient balance or non-positive amount.
+
+**example:**
+
+```clojure
+(define-fungible-token stackaroo)
+(ft-mint? stackaroo u100 'SPAXYA5XS51713FDTQ8H94EJ4V579CXMTRNBZKSF) ;; Returns (ok true)
+(ft-burn? stackaroo u50 'SPAXYA5XS51713FDTQ8H94EJ4V579CXMTRNBZKSF) ;; Returns (ok true)
+```
+
+***
+
+## ft-get-balance
+
+Introduced in: **Clarity 1**
+
+**input:** `TokenName, principal`\
+**output:** `uint`\
+**signature:** `(ft-get-balance token-name principal)`
+
+**description:**\
+Returns the `token-name` balance for `principal`. Token must be defined with `define-fungible-token`.
+
+**example:**
+
+```clojure
+(define-fungible-token stackaroo)
+(ft-mint? stackaroo u100 'SZ2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKQ9H6DPR)
+(ft-get-balance stackaroo 'SZ2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKQ9H6DPR) ;; Returns u100
+```
+
+***
+
+## ft-get-supply
+
+Introduced in: **Clarity 1**
+
+**input:** `TokenName`\
+**output:** `uint`\
+**signature:** `(ft-get-supply token-name)`
+
+**description:**\
+Returns circulating supply for the `token-name`. Token must be defined with `define-fungible-token`.
+
+**example:**
+
+```clojure
+(define-fungible-token stackaroo)
+(ft-mint? stackaroo u100 'SZ2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKQ9H6DPR)
+(ft-get-supply stackaroo) ;; Returns u100
+```
+
+***
+
+## ft-mint?
+
+Introduced in: **Clarity 1**
+
+**input:** `TokenName, uint, principal`\
+**output:** `(response bool uint)`\
+**signature:** `(ft-mint? token-name amount recipient)`
+
+**description:**\
+Mints `amount` of `token-name` to `recipient`. Non-positive amount returns `(err 1)`. On success returns `(ok true)`.
+
+**example:**
+
+```clojure
+(define-fungible-token stackaroo)
+(ft-mint? stackaroo u100 'SPAXYA5XS51713FDTQ8H94EJ4V579CXMTRNBZKSF) ;; Returns (ok true)
+```
+
+***
+
+## ft-transfer?
+
+Introduced in: **Clarity 1**
+
+**input:** `TokenName, uint, principal, principal`\
+**output:** `(response bool uint)`\
+**signature:** `(ft-transfer? token-name amount sender recipient)`
+
+**description:**\
+Transfers `amount` of `token-name` from `sender` to `recipient` (token must be defined in contract). Anyone can call; proper guards are expected. Returns `(ok true)` on success. Error codes: `(err u1)` insufficient balance, `(err u2)` sender==recipient, `(err u3)` non-positive amount.
+
+**example:**
+
+```clojure
+(define-fungible-token stackaroo)
+(ft-mint? stackaroo u100 'SZ2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKQ9H6DPR)
+(ft-transfer? stackaroo u50 'SZ2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKQ9H6DPR 'SPAXYA5XS51713FDTQ8H94EJ4V579CXMTRNBZKSF) ;; Returns (ok true)
+```
+
+***
+
+## get
+
+Introduced in: **Clarity 1**
+
+**input:** `KeyName, (tuple) | (optional (tuple))`\
+**output:** `A`\
+**signature:** `(get key-name tuple)`
+
+**description:**\
+Fetches value associated with `key-name` from a tuple. If an optional tuple is supplied and is `none`, returns `none`.
+
+**example:**
+
+```clojure
+(define-map names-map { name: (string-ascii 12) } { id: int })
+(map-insert names-map { name: "blockstack" } { id: 1337 })
+(get id (tuple (name "blockstack") (id 1337))) ;; Returns 1337
+(get id (map-get? names-map (tuple (name "blockstack")))) ;; Returns (some 1337)
+(get id (map-get? names-map (tuple (name "non-existent")))) ;; Returns none
+```
+
+***
+
+## get-block-info?
+
+Introduced in: **Clarity 1**
+
+**input:** `BlockInfoPropertyName, uint`\
+**output:** `(optional buff) | (optional uint)`\
+**signature:** `(get-block-info? prop-name block-height)`
+
+**description:**\
+Fetches data for a Stacks block at given block height. If the height doesn't exist prior to current block, returns `none`. Property names and returned types described; newer Clarity versions split this into `get-stacks-block-info?` and `get-tenure-info?`. See original for full list of properties and notes.
+
+**example:**
+
+```clojure
+(get-block-info? time u0) ;; Returns (some u1557860301)
+(get-block-info? header-hash u0) ;; Returns (some 0x3747...)
+```
+
+***
+
+## get-burn-block-info?
+
+Introduced in: **Clarity 2**
+
+**input:** `BurnBlockInfoPropertyName, uint`\
+**output:** `(optional buff) | (optional (tuple ...))`\
+**signature:** `(get-burn-block-info? prop-name block-height)`
+
+**description:**\
+Fetches burnchain block data for the given burnchain height. Valid properties include `header-hash` and `pox-addrs`. See original for full tuple shape of `pox-addrs`.
+
+**example:**
+
+```clojure
+(get-burn-block-info? header-hash u677050) ;; Returns (some 0xe671...)
+(get-burn-block-info? pox-addrs u677050) ;; Returns (some (tuple (addrs (...)) (payout u123)))
+```
+
+***
+
+## get-stacks-block-info?
+
+Introduced in: **Clarity 3**
+
+**input:** `StacksBlockInfoPropertyName, uint`\
+**output:** `(optional buff), (optional uint)`\
+**signature:** `(get-stacks-block-info? prop-name stacks-block-height)`
+
+**description:**\
+Replacement for `get-block-info?` in Clarity 3; fetches Stacks block data for a given height. See original for property list and behavior differences before/after epoch 3.0.
+
+**example:**
+
+```clojure
+(get-stacks-block-info? time u0) ;; Returns (some u1557860301)
+(get-stacks-block-info? header-hash u0) ;; Returns (some 0x3747...)
+```
+
+***
+
+## get-tenure-info?
+
+Introduced in: **Clarity 3**
+
+**input:** `TenureInfoPropertyName, uint`\
+**output:** `(optional buff) | (optional uint)`\
+**signature:** `(get-tenure-info? prop-name stacks-block-height)`
+
+**description:**\
+Fetches tenure-related info at the given block height (burnchain header for tenure, miner address, time, vrf-seed, block reward, miner spend totals). Returns `none` if height is not prior to current block. See original for full notes.
+
+**example:**
+
+```clojure
+(get-tenure-info? time u0) ;; Returns (some u1557860301)
+(get-tenure-info? vrf-seed u0) ;; Returns (some 0xf490...)
+```
+
+***
+
+## hash160
+
+Introduced in: **Clarity 1**
+
+**input:** `buff|uint|int`\
+**output:** `(buff 20)`\
+**signature:** `(hash160 value)`
+
+**description:**\
+Computes RIPEMD160(SHA256(x)). If input is an integer, it is hashed over its little-endian representation.
+
+**example:**
+
+```clojure
+(hash160 0) ;; Returns 0xe4352f72...
+```
+
+***
+
+## if
+
+Introduced in: **Clarity 1**
+
+**input:** `bool, A, A`\
+**output:** `A`\
+**signature:** `(if bool1 expr1 expr2)`
+
+**description:**\
+Conditional expression: evaluates and returns `expr1` if `bool1` is true, otherwise `expr2`. Both exprs must return the same type.
+
+**example:**
+
+```clojure
+(if true 1 2) ;; Returns 1
+(if (> 1 2) 1 2) ;; Returns 2
+```
+
+***
+
+## impl-trait
+
+Introduced in: **Clarity 1**
+
+**input:** `TraitIdentifier`\
+**output:** `Not Applicable`\
+**signature:** `(impl-trait trait-identifier)`
+
+**description:**\
+Asserts that the contract implements the given trait. Checked at publish time. Must be top-level.
+
+**example:**
+
+```clojure
+(impl-trait 'SPAXYA5XS51713FDTQ8H94EJ4V579CXMTRNBZKSF.token-a.token-trait)
+(define-public (get-balance (account principal))
+ (ok u0))
+```
+
+***
+
+## index-of
+
+Introduced in: **Clarity 1**
+
+**input:** `sequence_A, A`\
+**output:** `(optional uint)`\
+**signature:** `(index-of? sequence item)`
+
+**description:**\
+Returns first index of `item` in sequence using `is-eq`. Returns `none` if not found or if empty string/buffer. Clarity 1 spelling: `index-of` (alias).
+
+**example:**
+
+```clojure
+(index-of? "blockstack" "b") ;; Returns (some u0)
+(index-of? (list 1 2 3 4 5) 6) ;; Returns none
+```
+
+***
+
+## index-of?
+
+Introduced in: **Clarity 2**
+
+(Same as index-of; retained for Clarity 2)
+
+***
+
+## int-to-ascii
+
+Introduced in: **Clarity 2**
+
+**input:** `int | uint`\
+**output:** `(string-ascii 40)`\
+**signature:** `(int-to-ascii (int|uint))`
+
+**description:**\
+Converts an integer to its ASCII string representation. Available starting Stacks 2.1.
+
+**example:**
+
+```clojure
+(int-to-ascii 1) ;; Returns "1"
+(int-to-ascii -1) ;; Returns "-1"
+```
+
+***
+
+## int-to-utf8
+
+Introduced in: **Clarity 2**
+
+**input:** `int | uint`\
+**output:** `(string-utf8 40)`\
+**signature:** `(int-to-utf8 (int|uint))`
+
+**description:**\
+Converts an integer to its UTF-8 string representation. Available starting Stacks 2.1.
+
+**example:**
+
+```clojure
+(int-to-utf8 1) ;; Returns u"1"
+(int-to-utf8 -1) ;; Returns u"-1"
+```
+
+***
+
+## is-eq
+
+Introduced in: **Clarity 1**
+
+**input:** `A, A, ...`\
+**output:** `bool`\
+**signature:** `(is-eq v1 v2...)`
+
+**description:**\
+Returns `true` if all inputs are equal. Unlike `and`, does not short-circuit. All arguments must be the same type.
+
+**example:**
+
+```clojure
+(is-eq 1 1) ;; Returns true
+(is-eq true false) ;; Returns false
+(is-eq "abc" "abc") ;; Returns true
+```
+
+***
+
+## is-err / is-ok / is-none / is-some
+
+Introduced in: **Clarity 1**
+
+* `(is-err value)` returns `true` if `value` is `(err ...)`.
+* `(is-ok value)` returns `true` if `value` is `(ok ...)`.
+* `(is-none value)` returns `true` if `value` is `none`.
+* `(is-some value)` returns `true` if `value` is `(some ...)`.
+
+**examples:**
+
+```clojure
+(is-err (err 1)) ;; Returns true
+(is-ok (ok 1)) ;; Returns true
+(is-none none) ;; Returns true
+(is-some (some 1)) ;; Returns true
+```
+
+***
+
+## is-standard
+
+Introduced in: **Clarity 2**
+
+**input:** `principal`\
+**output:** `bool`\
+**signature:** `(is-standard standard-or-contract-principal)`
+
+**description:**\
+Tests whether a principal matches the current network type (mainnet vs testnet) and therefore can spend tokens on that network. Available starting Stacks 2.1.
+
+**example:**
+
+```clojure
+(is-standard 'STB44HYPYAT2BB2QE513NSP81HTMYWBJP02HPGK6) ;; true on testnet; false on mainnet
+```
+
+***
+
+## keccak256
+
+Introduced in: **Clarity 1**
+
+**input:** `buff|uint|int`\
+**output:** `(buff 32)`\
+**signature:** `(keccak256 value)`
+
+**description:**\
+Computes KECCAK256(value). If input is an integer, it is hashed over its little-endian representation.
+
+**example:**
+
+```clojure
+(keccak256 0) ;; Returns 0xf490de29...
+```
+
+***
+
+## len
+
+Introduced in: **Clarity 1**
+
+**input:** `sequence_A`\
+**output:** `uint`\
+**signature:** `(len sequence)`
+
+**description:**\
+Returns length of a sequence. Applies to `(list A)`, `buff`, `string-ascii`, `string-utf8`.
+
+**example:**
+
+```clojure
+(len "blockstack") ;; Returns u10
+(len (list 1 2 3 4 5)) ;; Returns u5
+(len 0x010203) ;; Returns u3
+```
+
+***
+
+## let
+
+Introduced in: **Clarity 1**
+
+**input:** `((name1 AnyType) ...), AnyType, ... A`\
+**output:** `A`\
+**signature:** `(let ((name1 expr1) ...) expr-body1 ... expr-body-last)`
+
+**description:**\
+Binds sequential variables then evaluates the body expressions in that context. Returns last body expression's value.
+
+**example:**
+
+```clojure
+(let ((a 2) (b (+ 5 6 7)))
+ (print a)
+ (print b)
+ (+ a b)) ;; Returns 20
+```
+
+***
+
+## list
+
+Introduced in: **Clarity 1**
+
+**input:** `A, ...`\
+**output:** `(list A)`\
+**signature:** `(list expr1 expr2 expr3 ...)`
+
+**description:**\
+Constructs a list from supplied values (must be same type).
+
+**example:**
+
+```clojure
+(list (+ 1 2) 4 5) ;; Returns (3 4 5)
+```
+
+***
+
+## log2
+
+Introduced in: **Clarity 1**
+
+**input:** `int | uint`\
+**output:** `int | uint`\
+**signature:** `(log2 n)`
+
+**description:**\
+Returns floor(log2(n)). Fails on negative numbers.
+
+**example:**
+
+```clojure
+(log2 u8) ;; Returns u3
+(log2 8) ;; Returns 3
+```
+
+***
+
+## map
+
+Introduced in: **Clarity 1**
+
+**input:** `Function(A, B, ..., N) -> X, sequence_A, sequence_B, ...`\
+**output:** `(list X)`\
+**signature:** `(map func sequence_A sequence_B ...)`
+
+**description:**\
+Applies `func` to each corresponding element of input sequences and returns a list of results. `func` must be a literal function name. Output is always a list.
+
+**example:**
+
+```clojure
+(map + (list 1 2 3) (list 1 2 3) (list 1 2 3)) ;; Returns (3 6 9)
+```
+
+***
+
+## map-delete / map-get? / map-insert / map-set
+
+Introduced in: **Clarity 1**
+
+Operations for manipulating contract data maps:
+
+* `(map-delete map-name key-tuple)` — removes entry; returns `true` if removed, `false` if none existed.
+* `(map-get? map-name key-tuple)` — returns `(some value)` or `none`.
+* `(map-insert map-name key-tuple value-tuple)` — inserts only if key absent; returns `true` if inserted, `false` if existed.
+* `(map-set map-name key-tuple value-tuple)` — blind overwrite; returns `true`.
+
+Examples exist in the original content (omitted here for brevity).
+
+***
+
+## match
+
+Introduced in: **Clarity 1**
+
+**input:** `(optional A) name expression expression | (response A B) name expression name expression`\
+**output:** `C`\
+**signature:** `(match opt-input some-binding-name some-branch none-branch) | (match-resp input ok-binding-name ok-branch err-binding-name err-branch)`
+
+**description:**\
+Destructures `optional` and `response` types and evaluates only the matching branch. See original for type-checking caveats.
+
+**example:**
+
+```clojure
+(define-private (add-10 (x (optional int)))
+ (match x
+ value (+ 10 value)
+ 10))
+(add-10 (some 5)) ;; Returns 15
+(add-10 none) ;; Returns 10
+```
+
+***
+
+## merge
+
+Introduced in: **Clarity 1**
+
+**input:** `tuple, tuple`\
+**output:** `tuple`\
+**signature:** `(merge tuple { key1: val1 })`
+
+**description:**\
+Returns a new tuple combining fields (non-mutating).
+
+**example:**
+
+```clojure
+(merge user { address: (some 'SPAXYA5X...) }) ;; Returns merged tuple
+```
+
+***
+
+## mod
+
+Introduced in: **Clarity 1**
+
+**input:** `int, int | uint, uint | string-ascii, string-ascii | string-utf8, string-utf8 | buff, buff`\
+**output:** `int | uint`\
+**signature:** `(mod i1 i2)`
+
+**description:**\
+Returns remainder of integer division; division by zero throws runtime error.
+
+**example:**
+
+```clojure
+(mod 5 2) ;; Returns 1
+```
+
+***
+
+## nft-burn? / nft-get-owner? / nft-mint? / nft-transfer?
+
+Introduced in: **Clarity 1**
+
+NFT operations for assets defined with `define-non-fungible-token`:
+
+* `(nft-mint? asset-class asset-identifier recipient)` — mint; returns `(ok true)` or `(err u1)` if exists.
+* `(nft-get-owner? asset-class asset-identifier)` — returns `(some owner)` or `none`.
+* `(nft-transfer? asset-class asset-identifier sender recipient)` — transfer; returns `(ok true)` or errors.
+* `(nft-burn? asset-class asset-identifier sender)` — burn; returns `(ok true)` or errors.
+
+Examples present in original content.
+
+***
+
+## not
+
+Introduced in: **Clarity 1**
+
+**input:** `bool`\
+**output:** `bool`\
+**signature:** `(not b1)`
+
+**description:**\
+Boolean negation.
+
+**example:**
+
+```clojure
+(not true) ;; Returns false
+```
+
+***
+
+## ok
+
+Introduced in: **Clarity 1**
+
+**input:** `A`\
+**output:** `(response A B)`\
+**signature:** `(ok value)`
+
+**description:**\
+Constructs an `ok` response. Use for successful public function returns.
+
+**example:**
+
+```clojure
+(ok 1) ;; Returns (ok 1)
+```
+
+***
+
+## or
+
+Introduced in: **Clarity 1**
+
+**input:** `bool, ...`\
+**output:** `bool`\
+**signature:** `(or b1 b2 ...)`
+
+**description:**\
+Returns `true` if any input is `true`. Evaluated in-order and lazily (short-circuits on `true`).
+
+**example:**
+
+```clojure
+(or true false) ;; Returns true
+```
+
+***
+
+## pow
+
+Introduced in: **Clarity 1**
+
+**input:** `int, int | uint, uint | string-ascii, string-ascii | string-utf8, string-utf8 | buff, buff`\
+**output:** `int | uint`\
+**signature:** `(pow i1 i2)`
+
+**description:**\
+Returns i1^i2. Throws runtime error on overflow. Special-case rules for 0^0, i1==1, etc. Throws runtime error if exponent negative or > u32::MAX.
+
+**example:**
+
+```clojure
+(pow 2 3) ;; Returns 8
+```
+
+***
+
+## principal-construct?
+
+Introduced in: **Clarity 2**
+
+**input:** `(buff 1), (buff 20), [(string-ascii 40)]`\
+**output:** `(response principal { error_code: uint, principal: (option principal) })`\
+**signature:** `(principal-construct? (buff 1) (buff 20) [(string-ascii 40)])`
+
+**description:**\
+Constructs a standard or contract principal from version byte and hash bytes, optionally with contract name. Returns `ok` with principal or `err` tuple with error code and optional principal. Available starting Stacks 2.1.
+
+**example:** (see original for many examples)
+
+***
+
+## principal-destruct?
+
+Introduced in: **Clarity 2**
+
+**input:** `principal`\
+**output:** `(response (tuple ...) (tuple ...))`\
+**signature:** `(principal-destruct? principal-address)`
+
+**description:**\
+Decomposes a principal into `{version, hash-bytes, name}` tuple. Returns `ok` if version matches network, otherwise `err`. Available starting Stacks 2.1.
+
+**example:** (see original)
+
+***
+
+## principal-of?
+
+Introduced in: **Clarity 1**
+
+**input:** `(buff 33)`\
+**output:** `(response principal uint)`\
+**signature:** `(principal-of? public-key)`
+
+**description:**\
+Derives the principal from a compressed public key. Returns `(err u1)` if invalid. Note: pre-2.1 bug returned testnet principals irrespective of network; fixed in 2.1.
+
+**example:**
+
+```clojure
+(principal-of? 0x03adb8de4b...) ;; Returns (ok ST1AW6E...)
+```
+
+***
+
+## print
+
+Introduced in: **Clarity 1**
+
+**input:** `A`\
+**output:** `A`\
+**signature:** `(print expr)`
+
+**description:**\
+Evaluates and returns its argument. On dev nodes prints to STDOUT.
+
+**example:**
+
+```clojure
+(print (+ 1 2 3)) ;; Returns 6
+```
+
+***
+
+## replace-at?
+
+Introduced in: **Clarity 2**
+
+**input:** `sequence_A, uint, A`\
+**output:** `(optional sequence_A)`\
+**signature:** `(replace-at? sequence index element)`
+
+**description:**\
+Returns a new sequence with element at `index` replaced. Returns `none` if index out of bounds.
+
+**example:**
+
+```clojure
+(replace-at? u"ab" u1 u"c") ;; Returns (some u"ac")
+(replace-at? (list 1 2) u3 4) ;; Returns none
+```
+
+***
+
+## restrict-assets?
+
+Introduced in: **Clarity 4**
+
+**Input**:
+
+* `asset-owner`: `principal`: The principal whose assets are being protected.
+* `((with-stx|with-ft|with-nft|with-stacking)*)`: The set of allowances (at most 128) to grant during the evaluation of the body expressions .
+* `AnyType* A`: The Clarity expressions to be executed within the context, with the final expression returning type `A`, where `A` is not a `response`
+
+**Output**: `(response A uint)`
+
+**Signature**: `(restrict-assets? asset-owner ((with-stx|with-ft|with-nft|with-stacking)*) expr-body1 expr-body2 ... expr-body-last)`
+
+**Description**: Executes the body expressions, then checks the asset outflows against the granted allowances, in declaration order. If any allowance is violated, the body expressions are reverted and an error is returned. Note that the `asset-owner` and allowance setup expressions are evaluated before executing the body expressions. The final body expression cannot return a `response` value in order to avoid returning a nested `response` value from `restrict-assets?` (nested responses are error-prone). Returns:
+
+* `(ok x)` if the outflows are within the allowances, where `x` is the result of the final body expression and has type `A`.
+* `(err index)` if an allowance was violated, where `index` is the 0-based index of the first violated allowance in the list of granted allowances, or `u128` if an asset with no allowance caused the violation.
+
+**Example**:
+
+```
+(define-public (foo)
+ (restrict-assets? tx-sender ()
+ (try! (stx-transfer? u1000000 tx-sender 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM))
+ )
+) ;; Returns (err u128)
+(define-public (bar)
+ (restrict-assets? tx-sender ()
+ (+ u1 u2)
+ )
+) ;; Returns (ok u3)
+```
+
+***
+
+## secp256k1-recover?
+
+Introduced in: **Clarity 1**
+
+**input:** `(buff 32), (buff 65)`\
+**output:** `(response (buff 33) uint)`\
+**signature:** `(secp256k1-recover? message-hash signature)`
+
+**description:**\
+Recovers the public key from a signature over message-hash. Returns `(err u1)` if signature doesn't match, `(err u2)` if signature invalid.
+
+**example:** (see original)
+
+***
+
+## secp256k1-verify
+
+Introduced in: **Clarity 1**
+
+**input:** `(buff 32), (buff 64) | (buff 65), (buff 33)`\
+**output:** `bool`\
+**signature:** `(secp256k1-verify message-hash signature public-key)`
+
+**description:**\
+Verifies that `signature` of `message-hash` was produced by `public-key`. Signature is 64 or 65 bytes.
+
+**example:** (see original)
+
+***
+
+## secp256r1-verify
+
+**Input**: `(buff 32), (buff 64), (buff 33)`
+
+**Output**: `bool`
+
+**Signature**: `(secp256r1-verify message-hash signature public-key)`
+
+**Description**: The `secp256r1-verify` function verifies that the provided `signature` of the `message-hash` was produced by the private key corresponding to `public-key`. The `message-hash` is the SHA-256 hash of the message. The `signature` must be 64 bytes (compact signature). Returns `true` if the signature is valid for the given `public-key` and message hash, otherwise returns `false`.
+
+**Example**:
+
+```clojure
+(secp256r1-verify 0x033510403a646d23ee4f005061c2ca6af5da7c32c83758e8e9b6ac4cc1c2153c
+ 0x9608dc164b76d2e19365ffa67b48981e441d323c3109718aee245d6ac8ccd21ddadadb94303c922c0d79d131ea59a0b6ba83e1157695db01189bb4b7e9f14b72 0x037a6b62e3c8b14f1b5933f5d5ab0509a8e7d95a111b8d3b264d95bfa753b00296) ;; Returns true
+(secp256r1-verify 0x0000000000000000000000000000000000000000000000000000000000000000
+ 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 0x037a6b62e3c8b14f1b5933f5d5ab0509a8e7d95a111b8d3b264d95bfa753b00296) ;; Returns false
+```
+
+***
+
+## sha256 / sha512 / sha512/256
+
+Introduced in: **Clarity 1**
+
+Hash functions:
+
+* `(sha256 value)` → `(buff 32)`
+* `(sha512 value)` → `(buff 64)`
+* `(sha512/256 value)` → `(buff 32)`
+
+If integer supplied, hashed over little-endian representation.
+
+**examples:**
+
+```clojure
+(sha256 0) ;; Returns 0x374708ff...
+(sha512 1) ;; Returns 0x6fcee9a7...
+(sha512/256 1) ;; Returns 0x515a7e92...
+```
+
+***
+
+## slice?
+
+Introduced in: **Clarity 2**
+
+**input:** `sequence_A, uint, uint`\
+**output:** `(optional sequence_A)`\
+**signature:** `(slice? sequence left-position right-position)`
+
+**description:**\
+Returns subsequence \[left, right). If left==right returns empty sequence. Returns `none` if out of bounds or right < left.
+
+**example:**
+
+```clojure
+(slice? "blockstack" u5 u10) ;; Returns (some "stack")
+(slice? "abcd" u2 u2) ;; Returns (some "")
+(slice? "abcd" u3 u1) ;; Returns none
+```
+
+***
+
+## some
+
+Introduced in: **Clarity 1**
+
+**input:** `A`\
+**output:** `(optional A)`\
+**signature:** `(some value)`
+
+**description:**\
+Constructs `(some value)`.
+
+**example:**
+
+```clojure
+(some 1) ;; Returns (some 1)
+```
+
+***
+
+## sqrti
+
+Introduced in: **Clarity 1**
+
+**input:** `int | uint`\
+**output:** `int | uint`\
+**signature:** `(sqrti n)`
+
+**description:**\
+Returns floor(sqrt(n)). Fails on negative numbers.
+
+**example:**
+
+```clojure
+(sqrti u11) ;; Returns u3
+```
+
+***
+
+## string-to-int? / string-to-uint?
+
+Introduced in: **Clarity 2**
+
+**input:** `(string-ascii 1048576) | (string-utf8 262144)`\
+**output:** `(optional int)` / `(optional uint)`\
+**signature:** `(string-to-int? str)` / `(string-to-uint? str)`
+
+**description:**\
+Parse string to int/uint. Returns `(some value)` on success, `none` on failure. Available starting Stacks 2.1.
+
+**example:**
+
+```clojure
+(string-to-int? "1") ;; Returns (some 1)
+(string-to-uint? "1") ;; Returns (some u1)
+(string-to-int? "a") ;; Returns none
+```
+
+***
+
+## stx-account
+
+Introduced in: **Clarity 2**
+
+**input:** `principal`\
+**output:** `(tuple (locked uint) (unlock-height uint) (unlocked uint))`\
+**signature:** `(stx-account owner)`
+
+**description:**\
+Query the STX account for `owner`. Returns locked, unlock-height, and unlocked amounts (microstacks). Available starting Clarity 2.
+
+**example:**
+
+```clojure
+(stx-account 'SZ2J6ZY48G...) ;; Returns (tuple (locked u0) (unlock-height u0) (unlocked u0))
+```
+
+***
+
+## stx-burn?
+
+Introduced in: **Clarity 1**
+
+**input:** `uint, principal`\
+**output:** `(response bool uint)`\
+**signature:** `(stx-burn? amount sender)`
+
+**description:**\
+Destroys `amount` of STX from `sender` (microstacks). `sender` must be current `tx-sender`. Returns `(ok true)` on success. Error codes: `(err u1)` insufficient balance, `(err u3)` non-positive amount, `(err u4)` sender not tx-sender.
+
+**example:**
+
+```clojure
+(as-contract (stx-burn? u60 tx-sender)) ;; Returns (ok true)
+```
+
+***
+
+## stx-get-balance
+
+Introduced in: **Clarity 1**
+
+**input:** `principal`\
+**output:** `uint`\
+**signature:** `(stx-get-balance owner)`
+
+**description:**\
+Returns STX balance (microstacks) of `owner`. If owner not materialized returns 0.
+
+**example:**
+
+```clojure
+(stx-get-balance (as-contract tx-sender)) ;; Returns u1000
+```
+
+***
+
+## stx-transfer-memo?
+
+Introduced in: **Clarity 2**
+
+**input:** `uint, principal, principal, buff`\
+**output:** `(response bool uint)`\
+**signature:** `(stx-transfer-memo? amount sender recipient memo)`
+
+**description:**\
+Same as `stx-transfer?` but includes a `memo` buffer. Returns same error codes as `stx-transfer?`.
+
+**example:**
+
+```clojure
+(as-contract (stx-transfer-memo? u60 tx-sender 'SZ2J6Z... 0x010203)) ;; Returns (ok true)
+```
+
+***
+
+## stx-transfer?
+
+Introduced in: **Clarity 1**
+
+**input:** `uint, principal, principal`\
+**output:** `(response bool uint)`\
+**signature:** `(stx-transfer? amount sender recipient)`
+
+**description:**\
+Transfers STX (microstacks) from `sender` to `recipient`. `sender` must be current `tx-sender`. Returns `(ok true)` or errors: `(err u1)` insufficient funds, `(err u2)` same principal, `(err u3)` non-positive amount, `(err u4)` sender not tx-sender.
+
+**example:**
+
+```clojure
+(as-contract (stx-transfer? u60 tx-sender 'SZ2J6Z...)) ;; Returns (ok true)
+```
+
+***
+
+## to-ascii?
+
+Introduced in: **Clarity 4**
+
+**Input**: `int` | `uint` | `bool` | `principal` | `(buff 524284)` | `(string-utf8 262144)`
+
+**Output**: `(response (string-ascii 1048571) uint)`
+
+**Signature**: `(to-ascii? value)`
+
+**Description**: Returns the `string-ascii` representation of the input value in an `ok` response on success. The only error condition is if the input type is `string-utf8` and the value contains non-ASCII characters, in which case, `(err u1)` is returned. Note that the limitation on the maximum sizes of `buff` and `string-utf8` inputs is due to the Clarity value size limit of 1MB. The `(string-utf8 262144)` is the maximum allowed size of a `string-utf8` value, and the `(buff 524284)` limit is chosen because the ASCII representation of a `buff` is `0x` followed by two ASCII characters per byte in the `buff`. This means that the ASCII representation of a `(buff 524284)` is `2 + 2 * 524284 = 1048570` characters at 1 byte each, and the remainder is required for the `response` value wrapping the `string-ascii`.
+
+**Example**:
+
+```clojure
+(to-ascii? true) ;; Returns (ok "true")
+(to-ascii? 42) ;; Returns (ok "42")
+(to-ascii? 'SP2QEZ06AGJ3RKJPBV14SY1V5BBFNAW33D96YPGZF) ;; Returns (ok "SP2QEZ06AGJ3RKJPBV14SY1V5BBFNAW33D96YPGZF")
+(to-ascii? 0x12345678) ;; Returns (ok "0x12345678")
+```
+
+***
+
+## to-consensus-buff?
+
+Introduced in: **Clarity 2**
+
+**input:** `any`\
+**output:** `(optional buff)`\
+**signature:** `(to-consensus-buff? value)`
+
+**description:**\
+Serializes a Clarity value using SIP-005 consensus serialization. If serialized size fits into a buffer, returns `(some buff)`, else `none`. During type checking the maximal possible buffer length is inferred. Available starting Clarity 2.
+
+**example:**
+
+```clojure
+(to-consensus-buff? 1) ;; Returns (some 0x0000...01)
+(to-consensus-buff? true) ;; Returns (some 0x03)
+```
+
+***
+
+## to-int
+
+Introduced in: **Clarity 1**
+
+**input:** `uint`\
+**output:** `int`\
+**signature:** `(to-int u)`
+
+**description:**\
+Converts `uint` to `int`. Runtime error if argument >= 2^127.
+
+**example:**
+
+```clojure
+(to-int u238) ;; Returns 238
+```
+
+***
+
+## to-uint
+
+Introduced in: **Clarity 1**
+
+**input:** `int`\
+**output:** `uint`\
+**signature:** `(to-uint i)`
+
+**description:**\
+Converts `int` to `uint`. Runtime error if argument is negative.
+
+**example:**
+
+```clojure
+(to-uint 238) ;; Returns u238
+```
+
+***
+
+## try!
+
+Introduced in: **Clarity 1**
+
+**input:** `(optional A) | (response A B)`\
+**output:** `A`\
+**signature:** `(try! option-input)`
+
+**description:**\
+Unpacks `(some v)` or `(ok v)` returning `v`. If input is `none` or `(err ...)`, `try!` returns the current function's `none` or `(err ...)` and exits control-flow.
+
+**example:** (see original for longer usage)
+
+***
+
+## tuple
+
+Introduced in: **Clarity 1**
+
+**input:** `(key-name A), ...`\
+**output:** `(tuple (key-name A) ...)`\
+**signature:** `(tuple (key0 expr0) (key1 expr1) ...)`
+
+**description:**\
+Constructs a typed tuple. Shorthand using curly braces `{ key: val, ... }` is available.
+
+**example:**
+
+```clojure
+(tuple (name "blockstack") (id 1337))
+{name: "blockstack", id: 1337}
+```
+
+***
+
+## unwrap! / unwrap-err! / unwrap-err-panic / unwrap-panic
+
+Introduced in: **Clarity 1**
+
+Utilities for unpacking optionals and responses with different failure behaviors:
+
+* `(unwrap! option-or-response thrown-value)` — returns inner value or returns `thrown-value` from current function.
+* `(unwrap-err! response-input thrown-value)` — returns err value or returns `thrown-value` if ok.
+* `(unwrap-err-panic response-input)` — returns err inner value or throws runtime error if ok.
+* `(unwrap-panic option-or-response)` — returns inner value or throws runtime error if none/err.
+
+**example:** (see original for usage)
+
+***
+
+## use-trait
+
+Introduced in: **Clarity 1**
+
+**input:** `VarName, TraitIdentifier`\
+**output:** `Not Applicable`\
+**signature:** `(use-trait trait-alias trait-identifier)`
+
+**description:**\
+Imports an external trait under an alias for use in the contract (must be top-level).
+
+**example:**
+
+```clojure
+(use-trait token-a-trait 'SPAXYA5X....token-a.token-trait)
+```
+
+***
+
+## var-get / var-set
+
+Introduced in: **Clarity 1**
+
+* `(var-get var-name)` — returns the value of a data var.
+* `(var-set var-name expr)` — sets the data var; returns `true`.
+
+**example:**
+
+```clojure
+(define-data-var cursor int 6)
+(var-get cursor) ;; Returns 6
+(var-set cursor (+ (var-get cursor) 1)) ;; Returns true
+```
+
+***
+
+{% hint style="info" %}
+The following 5 `with-*` functions are meant to be used inside the new `restrict-assets?` function. See the tutorial on Restricting Assets in Clarity for more info on how to use this function.
+{% endhint %}
+
+## with-all-assets-unsafe
+
+Introduced in: **Clarity 4**
+
+**Input**: None
+
+**Output**: Not applicable
+
+**Signature**: `(with-all-assets-unsafe)`
+
+**Description**: Grants unrestricted access to all assets of the contract to the enclosing `as-contract?` expression. Note that this is not allowed in `restrict-assets?` and will trigger an analysis error, since usage there does not make sense (i.e. just remove the `restrict-assets?` instead). **Security Warning:** This should be used with extreme caution, as it effectively disables all asset protection for the contract. This dangerous allowance should only be used when the code executing within the `as-contract?` body is verified to be trusted through other means (e.g. checking traits against an allow list, passed in from a trusted caller), and even then the more restrictive allowances should be preferred when possible.
+
+**Example**:
+
+```clojure
+(define-public (execute-trait (trusted-trait ))
+ (begin
+ (asserts! (is-eq contract-caller TRUSTED_CALLER) ERR_UNTRUSTED_CALLER)
+ (as-contract? ((with-all-assets-unsafe))
+ (contract-call? trusted-trait execute)
+ )
+ )
+)
+```
+
+***
+
+## with-ft
+
+**Input**:
+
+* `contract-id`: `principal`: The contract defining the FT asset.
+* `token-name`: `(string-ascii 128)`: The name of the FT or `"*"` for any FT defined in `contract-id`.
+* `amount`: `uint`: The amount of FT to grant access to.
+
+**Output**: Not applicable
+
+**Signature**: `(with-ft contract-id token-name amount)`
+
+**Description**: Adds an outflow allowance for `amount` of the fungible token defined in `contract-id` with name `token-name` from the `asset-owner` of the enclosing `restrict-assets?` or `as-contract?` expression. Note that `token-name` should match the name used in the `define-fungible-token` call in the contract. When `"*"` is used for the token name, the allowance applies to **all** FTs defined in `contract-id`.
+
+**Example**:
+
+```clojure
+(restrict-assets? tx-sender
+ ((with-ft (contract-of token-trait) "stackaroo" u50))
+ (try! (contract-call? token-trait transfer u100 tx-sender 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM none))
+) ;; Returns (err u0)
+(restrict-assets? tx-sender
+ ((with-ft (contract-of token-trait) "stackaroo" u50))
+ (try! (contract-call? token-trait transfer u20 tx-sender 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM none))
+) ;; Returns (ok true)
+```
+
+***
+
+## with-nft
+
+**Input**:
+
+* `contract-id`: `principal`: The contract defining the NFT asset.
+* `token-name`: `(string-ascii 128)`: The name of the NFT or `"*"` for any NFT defined in `contract-id`.
+* `identifiers`: `(list 128 T)`: The identifiers of the token to grant access to.
+
+**Output**: Not applicable
+
+**Signature**: `(with-nft contract-id token-name identifiers)`
+
+**Description**: Adds an outflow allowance for the non-fungible token(s) identified by `identifiers` defined in `contract-id` with name `token-name` from the `asset-owner` of the enclosing `restrict-assets?` or `as-contract?` expression. Note that `token-name` should match the name used in the `define-non-fungible-token` call in the contract. When `"*"` is used for the token name, the allowance applies to **all** NFTs defined in `contract-id`.
+
+**Example**:
+
+```clojure
+(restrict-assets? tx-sender
+ ((with-nft (contract-of nft-trait) "stackaroo" (list u123)))
+ (try! (contract-call? nft-trait transfer u4 tx-sender 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM))
+) ;; Returns (err u0)
+(restrict-assets? tx-sender
+ ((with-nft (contract-of nft-trait) "stackaroo" (list u123)))
+ (try! (contract-call? nft-trait transfer u123 tx-sender 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM))
+) ;; Returns (ok true)
+```
+
+***
+
+## with-stacking
+
+**Input**:
+
+* `amount`: `uint`: The amount of uSTX that can be locked.
+
+**Output**: Not applicable
+
+**Signature**: `(with-stacking amount)`
+
+**Description**: Adds a stacking allowance for `amount` uSTX from the `asset-owner` of the enclosing `restrict-assets?` or `as-contract?` expression. This restricts calls to the active PoX contract that either delegate funds for stacking or stack directly, ensuring that the locked amount is limited by the amount of uSTX specified.
+
+**Example**:
+
+```clojure
+(restrict-assets? tx-sender
+ ((with-stacking u1000000000000))
+ (try! (contract-call? 'SP000000000000000000002Q6VF78.pox-4 delegate-stx
+ u1100000000000 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM none none
+ ))
+) ;; Returns (err u0)
+(restrict-assets? tx-sender
+ ((with-stacking u1000000000000))
+ (try! (contract-call? 'SP000000000000000000002Q6VF78.pox-4 delegate-stx
+ u900000000000 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM none none
+ ))
+) ;; Returns (ok true)
+```
+
+***
+
+## with-stx
+
+**Input**:
+
+* `amount`: `uint`: The amount of uSTX to grant access to.
+
+**Output**: Not applicable
+
+**Signature**: `(with-stx amount)`
+
+**Description**: Adds an outflow allowance for `amount` uSTX from the `asset-owner` of the enclosing `restrict-assets?` or `as-contract?` expression.
+
+**Example**:
+
+```
+(restrict-assets? tx-sender
+ ((with-stx u1000000))
+ (try! (stx-transfer? u2000000 tx-sender 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM))
+) ;; Returns (err u0)
+(restrict-assets? tx-sender
+ ((with-stx u1000000))
+ (try! (stx-transfer? u1000000 tx-sender 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM))
+) ;; Returns (ok true)
+```
+
+***
+
+## xor
+
+Introduced in: **Clarity 1**
+
+**input:** `int, int | uint, uint | string-ascii, string-ascii | string-utf8, string-utf8 | buff, buff`\
+**output:** `int | uint`\
+**signature:** `(xor i1 i2)`
+
+**description:**\
+Bitwise exclusive OR of `i1` and `i2`.
+
+**example:**
+
+```clojure
+(xor 1 2) ;; Returns 3
+```
diff --git a/docs/reference/clarity/keywords.md b/docs/reference/clarity/keywords.md
new file mode 100644
index 0000000000..c503930cf6
--- /dev/null
+++ b/docs/reference/clarity/keywords.md
@@ -0,0 +1,320 @@
+---
+description: The complete reference guide to all Clarity keywords.
+---
+
+# Keywords
+
+{% hint style="info" %}
+The Nakamoto hard fork will introduce a few new Clarity keywords. It's important to note that even with the new block production mechanism, the `block-height` keyword behavior will not change. It will simply correspond to the current tenure height. This means any Clarity contracts using this keyword will be backwards compatible after the Nakamoto Upgrade.
+{% endhint %}
+
+### block-height
+
+Introduced in: Clarity 1
+
+output: `uint`
+
+description:
+
+Returns the current block height of the Stacks blockchain in Clarity 1 and 2. Upon activation of epoch 3.0, `block-height` will return the same value as `tenure-height`. In Clarity 3, `block-height` is removed and has been replaced with `stacks-block-height`.
+
+example:
+
+```clarity
+(> block-height u1000) ;; returns true if the current block-height has passed 1000 blocks.
+```
+
+***
+
+### burn-block-height
+
+{% hint style="warning" %}
+There is a bug in Clarity 3 when `burn-block-height` is used within an `at-block` expression. Normally, keywords executed within an `at-block` expression will return the data for that specified block. This bug causes `burn-block-height` always to return the burn block at the current chain tip, even within an `at-block` expression. This behavior affects any Clarity 3 contracts and will be fixed in a future hard fork.
+{% endhint %}
+
+Introduced in: Clarity 1
+
+output: `uint`
+
+description:
+
+Returns the current block height of the underlying burn blockchain as a uint
+
+example:
+
+```clarity
+(> burn-block-height 1000) ;; returns true if the current height of the underlying burn blockchain has passed 1000 blocks.
+```
+
+***
+
+### chain-id
+
+Introduced in: Clarity 2
+
+output: `uint`
+
+description:
+
+Returns the 32-bit chain ID of the blockchain running this transaction
+
+example:
+
+```clarity
+(print chain-id) ;; Will print 'u1' if the code is running on mainnet, and 'u2147483648' on testnet, and other values on different chains.
+```
+
+***
+
+### contract-caller
+
+Introduced in: Clarity 1
+
+output: `principal`
+
+description:
+
+Returns the caller of the current contract context. If this contract is the first one called by a signed transaction, the caller will be equal to the signing principal. If `contract-call?` was used to invoke a function from a new contract, `contract-caller` changes to the _calling_ contract's principal. If `as-contract` is used to change the `tx-sender` context, `contract-caller` _also_ changes to the same contract principal.
+
+example:
+
+```clarity
+(print contract-caller) ;; Will print out a Stacks address of the transaction sender
+```
+
+{% hint style="warning" %}
+Use caution when leveraging all contract calls, particularly tx-sender and contract-caller as based on the design, you can unintentionally introduce attack surface area. [Read more](https://www.setzeus.com/community-blog-posts/clarity-carefully-tx-sender).
+{% endhint %}
+
+***
+
+### current-contract
+
+Introduced in: Clarity 4
+
+output: `principal`
+
+description: Returns the principal of the current contract.
+
+example:
+
+```
+(stx-transfer? u1000000 tx-sender current-contract)
+```
+
+***
+
+### false
+
+Introduced in: Clarity 1
+
+output: `bool`
+
+description:
+
+Boolean false constant.
+
+example:
+
+```clarity
+(and true false) ;; Evaluates to false
+(or false true) ;; Evaluates to true
+```
+
+***
+
+### is-in-mainnet
+
+Introduced in: Clarity 2
+
+output: `bool`
+
+description:
+
+Returns a boolean indicating whether or not the code is running on the mainnet
+
+example:
+
+```clarity
+(print is-in-mainnet) ;; Will print 'true' if the code is running on the mainnet
+```
+
+***
+
+### is-in-regtest
+
+Introduced in: Clarity 1
+
+output: `bool`
+
+description:
+
+Returns whether or not the code is running in a regression test
+
+example:
+
+```clarity
+(print is-in-regtest) ;; Will print 'true' if the code is running in a regression test
+```
+
+***
+
+### none
+
+Introduced in: Clarity 1
+
+output: `(optional ?)`
+
+description:
+
+Represents the _none_ option indicating no value for a given optional (analogous to a null value).
+
+example:
+
+```clarity
+(define-public (only-if-positive (a int))
+ (if (> a 0)
+ (some a)
+ none))
+(only-if-positive 4) ;; Returns (some 4)
+(only-if-positive (- 3)) ;; Returns none
+```
+
+```clarity
+(print stx-liquid-supply) ;; Will print out the total number of liqui
+```
+
+***
+
+### stacks-block-height
+
+Introduced in: Clarity 3
+
+output: `uint`
+
+description:
+
+Returns the current Stacks block height.
+
+example:
+
+```clarity
+(print stacks-block-height) ;; Will print out the current Stacks block height
+```
+
+***
+
+### stacks-block-time
+
+Introduced in: Clarity 4
+
+output: `uint`
+
+description: Returns the timestamp of the current block in seconds since the Unix epoch
+
+{% hint style="info" %}
+This same timestamp can also be retrieved for previous blocks using `(get-stacks-block-info? time height)`, which exists since Clarity 3, but cannot be used for the current block.
+
+Note that `stacks-block-time` will properly account for the context of an `at-block` expression. If the `at-block` sets the context to a block that is from before Clarity 4 has activated, attempting to use `stacks-block-time` in that context will result in a runtime error.
+{% endhint %}
+
+```
+(if (> stacks-block-time 1755820800)
+ (print "after 2025-07-22")
+ (print "before 2025-07-22"))
+```
+
+***
+
+### stx-liquid-supply
+
+Introduced in: Clarity 1
+
+output: `uint`
+
+description:
+
+Returns the total number of micro-STX (uSTX) that are liquid in the system as of this block.
+
+example:
+
+```clarity
+(print stx-liquid-supply) ;; Will print out the total number of liquid uSTX
+```
+
+***
+
+### tenure-height
+
+Introduced in: Clarity 3
+
+output: `uint`
+
+description:
+
+Returns the number of tenures that have passed. When the Nakamoto block-processing starts, this will be equal to the chain length.
+
+example:
+
+```clarity
+(print tenure-height) ;; Will print out the current tenure height
+```
+
+***
+
+### true
+
+Introduced in: Clarity 1
+
+output: `bool`
+
+description:
+
+Boolean true constant.
+
+example:
+
+```clarity
+(and true false) ;; Evaluates to false
+(or false true) ;; Evaluates to true
+```
+
+***
+
+### tx-sender
+
+Introduced in: Clarity 1
+
+output: `principal`
+
+description:
+
+Returns the original sender of the current transaction, or if `as-contract` was called to modify the sending context, it returns that contract principal.
+
+example:
+
+```clarity
+(print tx-sender) ;; Will print out a Stacks address of the transaction sender
+```
+
+{% hint style="warning" %}
+Use caution when leveraging all contract calls, particularly tx-sender and contract-caller as based on the design, you can unintentionally introduce attack surface area. [Read more](https://www.setzeus.com/community-blog-posts/clarity-carefully-tx-sender).
+{% endhint %}
+
+***
+
+### tx-sponsor?
+
+Introduced in: Clarity 2
+
+output: `optional principal`
+
+description:
+
+Returns the sponsor of the current transaction if there is a sponsor, otherwise returns None.
+
+example:
+
+```clarity
+(print tx-sponsor?) ;; Will print out an optional value containing the Stacks address of the transaction sponsor
+```
diff --git a/docs/reference/clarity/types.md b/docs/reference/clarity/types.md
new file mode 100644
index 0000000000..ecf04eca23
--- /dev/null
+++ b/docs/reference/clarity/types.md
@@ -0,0 +1,23 @@
+---
+description: The complete reference guide to all Clarity types.
+---
+
+# Types
+
+### Clarity Type System
+
+The type system contains the following types:
+
+| Types | Notes |
+| ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| `int` | signed 128-bit integer |
+| `uint` | unsigned 128-bit integer |
+| `bool` | boolean value (`true` or `false`) |
+| `principal` | object representing a principal (whether a contract principal or standard principal) |
+| `(buff max-len)` | byte buffer of maximum length `max-len`. |
+| `(string-ascii max-len)` | ASCII string of maximum length `max-len` |
+| `(string-utf8 max-len)` | UTF-8 string of maximum length `max-len` (u"A smiley face emoji \u{1F600} as a utf8 string") |
+| `(list max-len entry-type)` | list of maximum length `max-len`, with entries of type `entry-type` |
+| `{label-0: value-type-0, label-1: value-type-1, ...}` | tuple, group of data values with named fields |
+| `(optional some-type)` | an option type for objects that can either be `(some value)` or `none` |
+| `(response ok-type err-type)` | object used by public functions to commit their changes or abort. May be returned or used by other functions as well, however, only public functions have the commit/abort behavior. |
diff --git a/docs/reference/nakamoto-upgrade/nakamoto-activation-guide-for-signers.md b/docs/reference/nakamoto-upgrade/nakamoto-activation-guide-for-signers.md
new file mode 100644
index 0000000000..a127b91308
--- /dev/null
+++ b/docs/reference/nakamoto-upgrade/nakamoto-activation-guide-for-signers.md
@@ -0,0 +1,83 @@
+# Nakamoto Activation Guide for Signers
+
+{% hint style="info" %}
+The block for Nakamoto activation has been chosen as Bitcoin block 867,867, which is currently expected on October 28th. This block is subject to change should core developers need additional time for testing or unexpected issues.
+
+Binaries will be provided roughly a week in advance and your normal upgrade procedure should apply here, you’ll want to be running the latest node and Signer software. Note that if you do not upgrade ahead of the hard fork, your nodes will be dropped from the network.
+{% endhint %}
+
+#### Testnet Activation Window (August 19)
+
+This initial phase focuses on testing Signer 3.0 readiness in a testnet environment (Primary Testnet).
+
+{% stepper %}
+{% step %}
+### Update stacks-node
+
+Update stacks-node to version 3.1.0.0.5.
+
+Release link: https://github.com/stacks-network/stacks-core/releases/latest
+{% endstep %}
+
+{% step %}
+### Update signer
+
+Update signer to version 3.1.0.0.5.0.
+
+Release link: https://github.com/stacks-network/stacks-core/releases/tag/signer-3.1.0.0.5.0
+{% endstep %}
+
+{% step %}
+### Run a Primary Testnet node
+
+Run a Primary Testnet node alongside your Signer.
+{% endstep %}
+
+{% step %}
+### Create a testnet wallet address
+
+Create a testnet wallet address to be used for delegated testing.
+{% endstep %}
+
+{% step %}
+### Submit the provided form
+
+Complete the provided form to register for testnet delegation:
+
+https://blocksurvey.io/signer-nakamoto-activation-upgrade-GrOV5aivQ2.z2fh3bqEyLQ?v=o
+{% endstep %}
+
+{% step %}
+### Await testnet STX delegation
+
+Await testnet STX delegation from the team and participate in testing.
+
+Goals: monitor for issues, implement fixes, and test Signing and Signer hand-off for multiple Epoch 2.5 cycles.
+
+Moving forward, please report any Signer-related bugs, issues or feature requests using the issue template in the stacks-core repo (here)
+{% endstep %}
+{% endstepper %}
+
+#### Mainnet Activation Window (Starting August 28)
+
+Pending successful testnet phases, we will initiate the mainnet activation window.
+
+**Action Required:**
+
+* ALL Mainnet Signers must update to the latest Stacks-Core and Signer binary versions (specifics to be confirmed)
+
+We will test for at least 1.5 Stacking Cycles to ensure stability.
+
+#### Key Points
+
+* Your participation in all phases is crucial
+* Report any issues or unexpected behavior immediately
+* Stay alert for further communications
+
+#### Conclusion
+
+Your dedication to the Stacks network's security and efficiency is invaluable. We appreciate your prompt attention to these critical steps and your ongoing support.
+
+For any questions or concerns, please don't hesitate to reach out.
+
+Thank you for your commitment to the Stacks ecosystem.
diff --git a/docs/reference/nakamoto-upgrade/nakamoto-in-10-minutes.md b/docs/reference/nakamoto-upgrade/nakamoto-in-10-minutes.md
new file mode 100644
index 0000000000..928856dca8
--- /dev/null
+++ b/docs/reference/nakamoto-upgrade/nakamoto-in-10-minutes.md
@@ -0,0 +1,57 @@
+# Nakamoto in 10 Minutes
+
+On the previous page, we outlined three primary changes to the way Stacks works that Nakamoto introduces:
+
+* **Fast blocks:** The time taken for a user-submitted transaction to be mined within a block (and thus confirmed) will now take on the order of seconds, instead of tens of minutes. This is achieved by separating block production from cryptographic sortitions -- a winning miner may produce many blocks between two subsequent sortitions.
+* **Bitcoin finality:** Once a transaction is confirmed, reversing it is at least as hard as reversing a Bitcoin transaction. The Stacks blockchain no longer forks on its own.
+* **Bitcoin Miner MEV Resistance:** This proposal alters the sortition algorithm to ensure that Bitcoin miners do not have an advantage as Stacks miners. They must spend competitive amounts of Bitcoin currency to have a chance of earning STX.
+
+Here is a video that covers exactly what happens to a Stacks transaction under Nakamoto rules. In it we cover exactly how Nakamoto achieves Bitcoin finality.
+
+{% embed url="https://www.youtube.com/watch?v=DFBZTSsZUOs" %}
+
+In the rest of this doc, we'll cover some of the key components of Nakamoto in a bit more detail.
+
+### Fast Blocks
+
+One of the most significant changes coming in Nakamoto is how new blocks are produced. Historically, because Stacks blocks have been anchored 1:1 to Bitcoin blocks, slow block times and transaction times have been one of the biggest pain points for Stacks users and developers.
+
+Nakamoto brings significantly faster block times by decoupling Stacks block production from Bitcoin block production. In Nakamoto, new Stacks blocks are produced roughly every 5 seconds.
+
+#### Tenure-Based Block Production
+
+This is achieved via the use of tenure-based block production. Each Bitcoin block introduces a new tenure, in which a single miner cryptographically selected for that tenure is responsible for producing all Stacks blocks.
+
+Rather than single Stacks blocks being tied to a single Bitcoin block, Bitcoin blocks are now tied to a miner tenure, during which they mine several Stacks blocks which settle in around 5 seconds.
+
+But if a single miner is only cryptographically selected for their tenure, and not their produced blocks, what mechanisms exist to ensure the validity of their block production?
+
+#### Stackers
+
+This is where Stackers come in. In pre-Nakamoto Stacks, Stackers were responsible only for locking their STX tokens to contribute to the economic security of the network.
+
+In Nakamoto, Stackers are responsible for validating and approving each block produced during a miner's tenure.
+
+To ensure network consistency, the Stacks protocol commits to the state of the Stacks blockchain with each new Bitcoin block by referencing the first Stacks block produced in the previous tenure. Such a design reinforces the fidelity of transaction data and the synchronization between the two chains. It also links the Stacker’s actions with the actions of miners producing a partnership between the two to create both fast and secure blocks.
+
+As part of this tenure change, Stackers also agree on a last signed block and require the next miner to build off of this, which prevents new Stacks forks. Stacks does not fork on its own and automatically forks with Bitcoin.
+
+This symbiotic relationship between Stackers and miners is what creates the capability for both fast blocks and 100% Bitcoin finality.
+
+This elegant design creates a cooperative relationship between miners and stackers while achieving the best of both worlds with block production and transaction speed and security.
+
+Here is a diagram outlining miner and signer behavior.
+
+
+
+### Bitcoin MEV Mitigation
+
+Miner Extractable Value (MEV) has been a longstanding issue across many blockchains, including Stacks pre-Nakamoto.
+
+MEV refers to the potential profit miners can extract from the manipulation of transaction inclusion and ordering within the blocks they produce, which can lead to unfair practices and diminished trust in the network.
+
+Specifically in pre-Nakamoto releases of Stacks, Bitcoin miners with a significant percentage of Bitcoin’s hashrate had the ability to censor commitment transactions of other Stacks miners ensuring they were able to win the block rewards and fees of Stacks blocks where they were also the winner of the Bitcoin block as a Bitcoin miner.
+
+The Nakamoto system uses a variation of the Assumed Total Commitment with Carryforward (ATC-C) MEV mitigation strategy described in [this document](https://github.com/stacksgov/sips/blob/main/sips/sip-021/MEV-Report.pdf) to allocate block rewards to miners. The probability a miner will win the block and be granted the current tenure will be based on a function that accounts for the total block commit spend on the blocks leading up to the current block.
+
+The ATC solution leaves the option for a block to have no valid winner. The TenureChange-Extend transaction mitigates the majority of adverse effects caused by a missed block.
diff --git a/docs/reference/nakamoto-upgrade/nakamoto-rollout-plan/README.md b/docs/reference/nakamoto-upgrade/nakamoto-rollout-plan/README.md
new file mode 100644
index 0000000000..890ea6f567
--- /dev/null
+++ b/docs/reference/nakamoto-upgrade/nakamoto-rollout-plan/README.md
@@ -0,0 +1,45 @@
+# Nakamoto Rollout Plan
+
+{% hint style="info" %}
+Nakamoto has completed step 1 of the rollout (Instantiation). Next, a hard fork that follows an Activation sequence outlined below will make Nakamoto features available to the whole network.
+{% endhint %}
+
+#### Step 1, Step 2: Instantiation & Activation
+
+The rollout will follow this two-step process, each of which is implemented via hard fork.
+
+{% stepper %}
+{% step %}
+### Instantiation
+
+The pox-4 contract and the majority of the Nakamoto code are shipped, but Nakamoto rules are inactive. This is so other aspects of the contract can be tested before layering on the complexity that comes with the testnet (and later mainnet) being dependent on it. Importantly, this phase also allows time for Signers to register without the network being dependent on them to sign blocks.
+{% endstep %}
+
+{% step %}
+### Activation
+
+Once completely rolled out, the full set of Nakamoto features including Signer-based functions, fast blocks, and Bitcoin finality. In other words, ‘the switch is flipped’! This switch is scheduled to occur at Bitcoin Block #867867 (\~October 29th).
+{% endstep %}
+{% endstepper %}
+
+It’s important to note the heaviest lift of any hard fork is historically the sync from genesis. With the two Nakamoto forks, one goal is not to require this, making the upgrade more akin to a push-button software update and much simpler for all node operators.
+
+
+
+What are ‘Nakamoto Rules’?
+
+Nakamoto rules are the logic that makes Nakamoto different than the version before it called Stacks 2.4. The key difference is that under Nakamoto, block validation logic requires Signers to sign the blocks to be confirmed as anchor blocks. At Step 1 (Instantiation), this logic, or the ‘Nakamoto Rules’ remains inactive, meaning the network follows the block validation rules of Stacks 2.4. Once the testnet (and later mainnet) reaches Activation, the network switches to running these Nakamoto rules and all the features we’re excited about go live for everybody.
+
+
+
+#### Nakamoto Activation Sequence
+
+Step Overview Date/Period ✅ A, B A ctivation Window Opens & B inaries DeliveredPending no new bugs, final binaries are delivered - this is all the code Signers, Miners, and Node Operators need to run the network. Aug 28th ✅ C C ycle Handoff - SignersAt the end of Cycle 92, core developers will watch for a successful ‘handoff’, meaning a successful change of the Signer sets between Stacking cycles. Cycle 92 to Cycle 93 ✅ D First Testnet Hard Fork Core developers performed a successful testnet hardfork (on Nakamoto testnet). Sept 27 ✅ E Determine Hard Fork Block Core developers have selected Bitcoin block #867867. October 17 F Epoch 3.0 - Nakamoto Rules Start Fast blocks, full Bitcoin finality! Nakamoto rules go live on mainnet at hard fork block. ~October 29
+
+#### Factors that could affect timelines
+
+* **Testing & Audit Results:** A top-notch group of researchers, contractors, and testers, along with security auditors from Clarity Alliance and Quantstamp, continue to hammer away at Nakamoto as they have for the past several months. This testing is ongoing, so there is always the possibility they surface an issue that needs to be addressed before the final hard fork.
+* **Signer Needs:** The ecosystem is proud to have industry leaders comprising its leading Signer network. Signers are a critical new network player so if a clear issue or unexpected need arises during activation, additional time would be taken to address it.
+* **Miner adoption:** As always, miners must choose to adopt the new code. Should they be delayed or experience issues with their setups, it could cause a delay in Activation.
+
+As always, core developers are committed to a safe, secure launch. Several factors could warrant additional time added to the Nakamoto activation sequence outlined above and result in a new hard fork block being selected.
diff --git a/docs/reference/nakamoto-upgrade/nakamoto-rollout-plan/nakamoto-for-app-developers.md b/docs/reference/nakamoto-upgrade/nakamoto-rollout-plan/nakamoto-for-app-developers.md
new file mode 100644
index 0000000000..dc19f87c35
--- /dev/null
+++ b/docs/reference/nakamoto-upgrade/nakamoto-rollout-plan/nakamoto-for-app-developers.md
@@ -0,0 +1,49 @@
+# Nakamoto for App Developers
+
+### API Endpoints
+
+* API status
+ * Tesnet: https://api.testnet.hiro.so/extended/
+ * Mainnet: https://api.hiro.so/extended/
+* Burn Block endpoint. This will allow you to get the hashes of fast Stacks blocks as they are added to the chain and see their associated burn blocks.
+ * Testnet: https://api.testnet.hiro.so/extended/v2/burn-blocks
+ * Mainnet: https://api.hiro.so/extended/v2/burn-blocks
+* Pox endpoint. This allows you to get information about proof of transfer, including the currently deployed pox-4 contract. This will be helpful for anyone looking to incorporate stacking into their app.
+ * Testnet: https://api.testnet.hiro.so/v2/pox
+ * Mainnet: https://api.hiro.so/v2/pox
+
+#### PoX-4 Contract
+
+`pox-4.clar` is the stacking contract. If you are interested in experimenting with proof of transfer use cases including state changes, solo stacking, and pool stacking, all the functions you’ll need can be found at the deployed contract:
+
+* Testnet: https://explorer.hiro.so/txid/0xfba7f786fae1953fa56f4e56aeac053575fd48bf72360523366d739e96613da3?chain=testnet
+* Mainnet: https://explorer.hiro.so/txid/0xc6d6e6ec82cabb2d7a9f4b85fcc298778d01186cabaee01685537aca390cdb46?chain=mainnet
+
+#### Signers Voting Contract
+
+After a DKG (Distributed Key Generation) round, signer votes are submitted to this contract. For more on DKG, you can read the Stackers and Signing section of Nakamoto In-Depth:
+
+https://explorer.hiro.so/txid/0x69af1dbed501acdbc0d1c79e1ecbc17e1904edacc15cf4b39d6783e720e21c00?chain=testnet
+
+#### Block Explorer
+
+The explorer will allow you to view fast blocks as they come in. Be sure to turn on “Live updates” to see them coming in in real time.\
+https://explorer.hiro.so/?chain=testnet
+
+#### Local Development Environment
+
+Clarinet has been updated to work with Nakamoto as of version 2.4. That means you can use Clarinet to build locally using Nakamoto rules in your local development environment and use Clarinet and deployment plans to deploy to Nakamoto Testnet.
+
+Be sure to update Clarinet to the newest version: https://docs.hiro.so/clarinet/getting-started
+
+#### Running a signer
+
+If you are interested in running a signer, you can take a look at the How to Run a Signer doc which will get you up to speed on how to get the signer software set up using Nakamoto:
+
+../../guides-and-tutorials/running-a-signer/
+
+#### Office Hours
+
+If you need support or just want to ask questions while experimenting with the Nakamoto Testnet, you can join the weekly office hours with the Stacks' Foundation's Developer Advocate, Kenny Rogers:
+
+https://events.stacks.co/event/HD16484710
diff --git a/docs/reference/nakamoto-upgrade/nakamoto-rollout-plan/nakamoto-for-exchanges.md b/docs/reference/nakamoto-upgrade/nakamoto-rollout-plan/nakamoto-for-exchanges.md
new file mode 100644
index 0000000000..f413ee2125
--- /dev/null
+++ b/docs/reference/nakamoto-upgrade/nakamoto-rollout-plan/nakamoto-for-exchanges.md
@@ -0,0 +1,36 @@
+# Nakamoto for Exchanges
+
+
+
+What is the Nakamoto upgrade?
+
+The Nakamoto release brings many new capabilities and improvements to the Stacks blockchain by focusing on a set of core advancements: improving transaction speed, enhancing finality guarantees for transactions, mitigating Bitcoin miner MEV (miner extractable value) opportunities that affect PoX, and boosting robustness against chain reorganizations. This strategic upgrade aims to solidify trust in the Stacks network, offer greater alignment with Bitcoin's immutable nature, and foster an environment ripe for advanced Decentralized Finance (DeFi) applications. The expected outcome is a versatile, scalable, and secure platform that closely integrates with, yet distinctly enhances, the Bitcoin ecosystem.
+
+Learn more: [Broken link](/broken/pages/fac008cad2409afc8de86501f205ee51e148b5af "mention")
+
+
+
+### What does the Nakamoto upgrade mean for exchanges?
+
+The main thing exchanges will notice when the Nakamoto rollout is complete is the faster blocks! Gone are the days of waiting for Bitcoin blocks for confirmations. In addition to fast blocks, exchanges will benefit from:
+
+* Smoother block production
+* No forking at the Stacks layer — once a transaction is confirmed in an anchor block, it is as irreversible as a Bitcoin transaction (and therefore exchanges can update confirmation rules (number of confirmations) to match Bitcoin's)
+* For exchanges offering Stacking pools, likely increased BTC rewards thanks to MEV improvements
+
+### Other Recommendations
+
+* With just a bit of extra work, exchanges can support the [Stacks SIP-10 token standard](https://github.com/stacksgov/sips/blob/main/sips/sip-010/sip-010-fungible-token-standard.md). This allows an exchange to easily list any of a growing number of tokens built on Stacks as well as the upcoming sBTC asset.
+* Exchanges that already offer staking-type services to their users (programs often called Earn/Stake/etc.) should consider adding Stacking to their platform alongside other offerings. Users can earn BTC by participating in Stacks consensus through a simple pool.
+* The Stacks Foundation is seeking a handful of exchanges to pilot rapid BTC withdrawals via the upcoming sBTC asset, expected to closely follow the Nakamoto hard fork. Interested exchanges can reach out to their usual point of contact or complete [this form](https://stacks.org/exchanges).
+
+### Resources
+
+* [Testnet documentation](https://docs.stacks.co/nakamoto-upgrade/nakamoto)
+* [API documentation](https://docs.hiro.so/nakamoto/stacks-js)
+* [Stacks Core Binaries](https://github.com/stacks-network/stacks-core/releases/latest)
+* [Stacks Signer Binary](https://github.com/stacks-network/stacks-core/releases/tag/signer-3.1.0.0.5.0)
+* [Stacks Core Docker Images](https://hub.docker.com/r/blockstack/stacks-core/tags?page=1\&name=3.1.0.0.5)
+* [Stacks Signer Docker Image](https://hub.docker.com/r/blockstack/stacks-signer/tags?page=1\&name=3.1.0.0.5.0)
+* [Stacks Blockchain API](https://github.com/hirosystems/stacks-blockchain-api/releases/latest)
+* [Stacks Blockchain API Docker Images](https://hub.docker.com/r/hirosystems/stacks-blockchain-api/tags?page=1\&name=8.4.0)
diff --git a/docs/reference/nakamoto-upgrade/nakamoto-rollout-plan/nakamoto-for-stackers.md b/docs/reference/nakamoto-upgrade/nakamoto-rollout-plan/nakamoto-for-stackers.md
new file mode 100644
index 0000000000..c4e73c14a3
--- /dev/null
+++ b/docs/reference/nakamoto-upgrade/nakamoto-rollout-plan/nakamoto-for-stackers.md
@@ -0,0 +1,22 @@
+---
+description: >-
+ Learn how you can earn a BTC yield by locking your STX and supporting network
+ consensus
+---
+
+# Nakamoto for Stackers
+
+### Stacking Providers:
+
+Find the current list at [stacks.co](https://www.stacks.co/learn/stacking)
+
+### Stacking Tools
+
+Check out these valuable Stacking resources:
+
+* Stacking Calendar and more! [https://stacking.tools/](https://stacking.tools/)
+* Stacking Tracker: [https://www.stacking-tracker.com/](https://www.stacking-tracker.com/)
+* Lockstacks (access various pools): [https://lockstacks.com/](https://lockstacks.com/)
+* Find Stacking data:
+ * [https://app.signal21.io/](https://app.signal21.io/)
+ * [https://app.ortege.ai/superset/dashboard/stacks/](https://app.ortege.ai/superset/dashboard/stacks/)
diff --git a/docs/reference/nakamoto-upgrade/nakamoto-rollout-plan/nakamoto-for-stacking-providers.md b/docs/reference/nakamoto-upgrade/nakamoto-rollout-plan/nakamoto-for-stacking-providers.md
new file mode 100644
index 0000000000..a31597df6a
--- /dev/null
+++ b/docs/reference/nakamoto-upgrade/nakamoto-rollout-plan/nakamoto-for-stacking-providers.md
@@ -0,0 +1,42 @@
+# Nakamoto for Stacking Providers
+
+## Upgrading your Stacking pool or service
+
+There are a few basic steps you'll need to follow to get your Stacking pool set up to work with this first Nakamoto hard fork as this fork brings us the new pox-4 contract:
+
+{% stepper %}
+{% step %}
+### Setup a Stacks node and signer
+
+Set up a Stacks node and signer by following the How to Run a Signer doc.
+{% endstep %}
+
+{% step %}
+### Update user-facing products and contracts to use pox-4
+
+Update your user-facing products and contracts to point to the new pox-4 contract.
+
+* If you use a wrapper contract with pox-3 hardcoded, you'll need to deploy a new contract referencing pox-4.
+{% endstep %}
+
+{% step %}
+### Update internal infrastructure and automation
+
+Update any internal infrastructure or automation that you use to manage your pool.
+{% endstep %}
+
+{% step %}
+### Familiarize yourself with new stack-aggregation-commit arguments and signer signature generation
+
+Familiarize yourself with the new `stack-aggregation-commit` function arguments, along with how to generate a signer key signature.
+{% endstep %}
+{% endstepper %}
+
+{% hint style="info" %}
+Other notes:
+
+* Once you are running a signer as described in the How to Run a Signer doc, you'll initiate Stacking transactions as normal, but you'll need to pass an additional Signer signature field. This is covered extensively in the How to Stack doc.
+* For delegated stacking flows, the functions `delegate-stx` and `delegate-stack-stx` are unchanged. If your pool makes use of custom smart contracts for allowing Stackers to delegate to you, those contracts may need to be updated to point to the new `pox-4` address.
+* The function `stack-aggregation-commit` now requires pool operators to provide their Signer’s public key, along with other related information. Learn more about generating Signer key signatures using the stacks-signer CLI or with [Lockstacks](https://docs.stacks.co/nakamoto-upgrade/signing-and-stacking/stacking-flow#generating-your-signature-with-lockstacks). Again, this entire flow is covered extensively in the How to Stack doc.
+* Depending on your pool’s infrastructure, you may need to update any tools or automations that you use to finalize your pool’s delegations.
+{% endhint %}
diff --git a/docs/reference/nakamoto-upgrade/nakamoto-upgrade-start-here.md b/docs/reference/nakamoto-upgrade/nakamoto-upgrade-start-here.md
new file mode 100644
index 0000000000..439ddc9014
--- /dev/null
+++ b/docs/reference/nakamoto-upgrade/nakamoto-upgrade-start-here.md
@@ -0,0 +1,41 @@
+# Nakamoto Upgrade Start Here
+
+The Nakamoto Upgrade is a major upgrade to the Stacks blockchain that instantiated at Bitcoin block 840,360. This marked the start of the [Nakamoto mainnet rollout](https://app.gitbook.com/o/hoh4mQXTl8NvI3cETroY/s/GVj1Z9vMuEOMe7oH7Wnq/~/changes/8/nakamoto-upgrade/nakamoto-rollout-plan).
+
+There are several important things to be aware of regarding how the Nakamoto upgrade will be rolled out and different actions you may need to take depending on your role in the ecosystem.
+
+## The Basics
+
+If you aren't familiar with what Nakamoto is, first [get up to speed](https://app.gitbook.com/o/hoh4mQXTl8NvI3cETroY/s/GVj1Z9vMuEOMe7oH7Wnq/~/changes/8/nakamoto-upgrade/what-is-the-nakamoto-release).
+
+Next, make sure you understand the rollout plan. Nakamoto is a major change to the network, and there are several moving parts and a specific, intentional [rollout plan and timeline](https://app.gitbook.com/o/hoh4mQXTl8NvI3cETroY/s/GVj1Z9vMuEOMe7oH7Wnq/~/changes/8/nakamoto-upgrade/nakamoto-rollout-plan).
+
+After you familiarize yourself with what Nakamoto is and how it’s being rolled out, check the sections below to see what specific actions you may need to take depending on your role.
+
+## Users / STX Holders
+
+* For most users the upgrade is simple: you don't have to do anything. No token transfers are required. In many cases wallets will be upgraded automatically and you'll be on the upgraded network without noticing a change.
+* Exchanges may briefly suspend STX-related activities (deposits/withdrawals/trading) while they upgrade their nodes. These suspensions are typically communicated by the exchange and are often very brief or may not be necessary if their upgrade proceeds smoothly. If you experience issues with an exchange, contact that exchange directly.
+
+## Stackers
+
+After Nakamoto activation, stackers will need to either operate or work with a signer.
+
+* If you are stacking in a pool, your pool operator will be responsible for running the signer.
+* If you are solo stacking, you can either run your own signer or collaborate with an existing signer to stack your STX.
+
+## Stacking Pool Operators
+
+If you operate a pool, ensure you are ready to accept delegations and that you have an operational signer you can stack with. Details are in the How to Operate a Pool guide.
+
+## Signers
+
+If you operate a signer, familiarize yourself with both the stacking guide and the running a signer guide. These guides explain how to run a signer and how signing and stacking interact.
+
+## Application Developers
+
+The instantiation phase (current phase) focuses on activating the new stacking rules in PoX-4. Fast blocks won't be available until after Activation, projected \~October 29th. Most developers won't need to change anything immediately, but there are updates to some Hiro products and tools you should be aware of. See the [Nakamoto for App Developers](https://app.gitbook.com/o/hoh4mQXTl8NvI3cETroY/s/GVj1Z9vMuEOMe7oH7Wnq/~/changes/8/nakamoto-upgrade/nakamoto-rollout-plan/nakamoto) guide for details.
+
+## Exchanges
+
+For exchanges, the process is similar to past upgrades: upgrade your node to the newest version. Depending on your setup, review changes to the API and stacks.js. See the [Nakamoto for Exchanges](https://app.gitbook.com/o/hoh4mQXTl8NvI3cETroY/s/GVj1Z9vMuEOMe7oH7Wnq/~/changes/8/nakamoto-upgrade/nakamoto-rollout-plan/nakamoto-for-exchanges) guide for details.
diff --git a/docs/reference/nakamoto-upgrade/setting-up-a-primary-post-nakamoto-testnet-node.md b/docs/reference/nakamoto-upgrade/setting-up-a-primary-post-nakamoto-testnet-node.md
new file mode 100644
index 0000000000..e39538ff52
--- /dev/null
+++ b/docs/reference/nakamoto-upgrade/setting-up-a-primary-post-nakamoto-testnet-node.md
@@ -0,0 +1,293 @@
+# Setting Up a Primary Post Nakamoto Testnet Node
+
+### Setup A Stacks Primary Testnet Node
+
+Once your signer is upgraded to version 3.1.0.0.5.0 (https://github.com/stacks-network/stacks-core/releases/tag/signer-3.1.0.0.5.0) you’ll need to run a primary testnet node alongside it.
+
+You have two options here. The first is to run the Bash script below and it will handle everything for you, including creating the configuration file, downloading and extracting a chain state archive, and getting the node up and running.
+
+If you prefer to handle these yourself, step-by-step instructions are included below the Bash script.
+
+### Automated Bash Script
+
+{% hint style="warning" %}
+Be sure to edit your `auth_token` (previously `block_proposal_token`) field here to match the `auth_password` field in your signer config.
+{% endhint %}
+
+```bash
+STACKS_DIR="${HOME}/nakamoto-testnet"
+STACKS_RPC_PORT="40443"
+STACKS_P2P_PORT="40444"
+
+IMG="blockstack/stacks-core"
+VER="3.1.0.0.5"
+STX_NODE_CONFIG="${STACKS_DIR}/Config.toml"
+
+mkdir -p ${STACKS_DIR}/data
+curl -# -o ${STACKS_DIR}/data/testnet-stacks-blockchain-latest.tar.gz
+tar -xzvf ${STACKS_DIR}/data/testnet-stacks-blockchain-latest.tar.gz -C ${STACKS_DIR}/data/
+
+cat < ${STX_NODE_CONFIG}
+[node]
+working_dir = "/stacks-blockchain/data"
+rpc_bind = "0.0.0.0:20443"
+p2p_bind = "0.0.0.0:20444"
+bootstrap_node = "029266faff4c8e0ca4f934f34996a96af481df94a89b0c9bd515f3536a95682ddc@seed.testnet.hiro.so:30444"
+prometheus_bind = "0.0.0.0:9153"
+stacker = true
+
+[burnchain]
+chain = "bitcoin"
+mode = "krypton"
+peer_host = "bitcoin.regtest.hiro.so"
+peer_port = 18444
+pox_prepare_length = 100
+pox_reward_length = 900
+
+# Set your auth token, which the signer uses
+
+# This should match the auth_password field of your signer config
+[connection_options]
+auth_token = "12345"
+
+[[events_observer]]
+endpoint = "0.0.0.0.0:30000"
+events_keys = ["stackerdb", "block_proposal", "burn_blocks"]
+
+[[ustx_balance]]
+address = "ST2QKZ4FKHAH1NQKYKYAYZPY440FEPK7GZ1R5HBP2"
+amount = 10000000000000000
+
+[[ustx_balance]]
+address = "ST319CF5WV77KYR1H3GT0GZ7B8Q4AQPY42ETP1VPF"
+amount = 10000000000000000
+
+[[ustx_balance]]
+address = "ST221Z6TDTC5E0BYR2V624Q2ST6R0Q71T78WTAX6H"
+amount = 10000000000000000
+
+[[ustx_balance]]
+address = "ST2TFVBMRPS5SSNP98DQKQ5JNB2B6NZM91C4K3P7B"
+amount = 10000000000000000
+
+[fee_estimation]
+fee_estimator = "fuzzed_weighted_median_fee_rate"
+
+[[burnchain.epochs]]
+epoch_name = "1.0"
+start_height = 0
+
+[[burnchain.epochs]]
+epoch_name = "2.0"
+start_height = 0
+
+[[burnchain.epochs]]
+epoch_name = "2.05"
+start_height = 1
+
+[[burnchain.epochs]]
+epoch_name = "2.1"
+start_height = 2
+
+[[burnchain.epochs]]
+epoch_name = "2.2"
+start_height = 3
+
+[[burnchain.epochs]]
+epoch_name = "2.3"
+start_height = 4
+
+[[burnchain.epochs]]
+epoch_name = "2.4"
+start_height = 5
+
+[[burnchain.epochs]]
+epoch_name = "2.5"
+start_height = 6
+
+[[burnchain.epochs]]
+epoch_name = "3.0"
+start_height = 1_900
+
+[[burnchain.epochs]]
+epoch_name = "3.1"
+start_height = 2_000
+
+[[burnchain.epochs]]
+epoch_name = "3.2"
+start_height = 71_525
+EOF
+
+docker run -d \\
+ -v ${STX_NODE_CONFIG}:/config.toml \\
+ -v ${STACKS_DIR}/data:/stacks-blockchain/data \\
+ -p ${STACKS_RPC_PORT}:20443 \\
+ -p ${STACKS_P2P_PORT}:20444 \\
+ -e RUST_BACKTRACE=full \\
+ --name stacks-node \\
+ $IMG:$VER \\
+ stacks-node start --config /config.toml
+```
+
+### Manual Setup
+
+{% stepper %}
+{% step %}
+### Node Configuration
+
+Create a file called `node-config.toml`. Below is a sample of the configuration file you’ll need to use.
+
+```toml
+[node]
+working_dir = "/stacks-blockchain/data"
+rpc_bind = "0.0.0.0:20443"
+p2p_bind = "0.0.0.0:20444"
+bootstrap_node = "029266faff4c8e0ca4f934f34996a96af481df94a89b0c9bd515f3536a95682ddc@seed.testnet.hiro.so:30444"
+prometheus_bind = "0.0.0.0:9153"
+
+[burnchain]
+chain = "bitcoin"
+mode = "krypton"
+peer_host = "bitcoin.regtest.hiro.so"
+peer_port = 18444
+pox_prepare_length = 100
+pox_reward_length = 900
+
+[[events_observer]]
+endpoint = "0.0.0.0.0:30000"
+events_keys = ["stackerdb", "block_proposal", "burn_blocks"]
+
+# Set your auth token, which the signer uses
+
+# This should match the auth_password field of your signer config
+[connection_options]
+auth_token = "12345"
+
+[[ustx_balance]]
+address = "ST2QKZ4FKHAH1NQKYKYAYZPY440FEPK7GZ1R5HBP2"
+amount = 10000000000000000
+
+[[ustx_balance]]
+address = "ST319CF5WV77KYR1H3GT0GZ7B8Q4AQPY42ETP1VPF"
+amount = 10000000000000000
+
+[[ustx_balance]]
+address = "ST221Z6TDTC5E0BYR2V624Q2ST6R0Q71T78WTAX6H"
+amount = 10000000000000000
+
+[[ustx_balance]]
+address = "ST2TFVBMRPS5SSNP98DQKQ5JNB2B6NZM91C4K3P7B"
+amount = 10000000000000000
+
+[fee_estimation]
+fee_estimator = "fuzzed_weighted_median_fee_rate"
+
+[[burnchain.epochs]]
+epoch_name = "1.0"
+start_height = 0
+
+[[burnchain.epochs]]
+epoch_name = "2.0"
+start_height = 0
+
+[[burnchain.epochs]]
+epoch_name = "2.05"
+start_height = 1
+
+[[burnchain.epochs]]
+epoch_name = "2.1"
+start_height = 2
+
+[[burnchain.epochs]]
+epoch_name = "2.2"
+start_height = 3
+
+[[burnchain.epochs]]
+epoch_name = "2.3"
+start_height = 4
+
+[[burnchain.epochs]]
+epoch_name = "2.4"
+start_height = 5
+
+[[burnchain.epochs]]
+epoch_name = "2.5"
+start_height = 6
+
+[[burnchain.epochs]]
+epoch_name = "3.0"
+start_height = 1_900
+
+[[burnchain.epochs]]
+epoch_name = "3.1"
+start_height = 2_000
+
+[[burnchain.epochs]]
+epoch_name = "3.2"
+start_height = 71_525
+```
+
+Important aspects to change:
+
+* auth\_token: an authentication token that your signer uses to authenticate certain requests to your node. This must match the value you used as `auth_password` in the signer’s configuration.
+* events\_observer.endpoint: the host (IP and port) where your signer is configured to listen for events (e.g., `127.0.0.1:30000` or `my-signer.local:30000`).
+{% endstep %}
+
+{% step %}
+### Start with an archive
+
+If you are running your Stacks node on the primary testnet, it will be much faster to start with an archive of the chain state rather than syncing from genesis.
+
+Archives can be found from https://archive.hiro.so. For the Stacks node testnet, the latest snapshot can be found at: https://archive.hiro.so/testnet/stacks-blockchain/testnet-stacks-blockchain-latest.tar.gz. You can also browse all testnet snapshots at https://archive.hiro.so/testnet/stacks-blockchain/.
+
+Download this on the same machine that will run the Stacks node. Example commands:
+
+```bash
+curl -# -o stacks-snapshot.tar.gz -o /stacks-blockchain/data/latest.tar.gz
+
+tar -xzvf /stacks-blockchain/data/latest.tar.gz -C /stacks-blockchain/data
+```
+{% endstep %}
+
+{% step %}
+### Run a Stacks Node with Docker
+
+You can run the Stacks node as a Docker container using the `blockstack/stacks-core` image. When running the Docker container, ensure:
+
+* The port configured for `p2p_bind` must be exposed to the internet for egress.
+* The port configured for `rpc_bind` must be accessible by your signer.
+* `working_dir` needs to be on a volume with 3-5GB of available storage.
+* Include your `node-config.toml` file.
+
+Example docker run (run from the same directory as your `node-config.toml` or change STX\_NODE\_CONFIG):
+
+```bash
+IMG="blockstack/stacks-core"
+
+VER="3.1.0.0.5"
+
+STX_NODE_CONFIG="./node-config.toml"
+
+docker run -d \\
+-v $STX_NODE_CONFIG:/config.toml \\
+-v /var/stacks \\
+-p 20443:20443 \\
+-p 20444:20444 \\
+-e RUST_BACKTRACE=full \\
+--name stacks-node \\
+$IMG:$VER \\
+stacks-node start \\
+--config /config.toml
+```
+
+Or using a custom Dockerfile:
+
+```docker
+FROM blockstack/stacks-core:3.1.0.0.5
+COPY node-config.toml /config.toml
+EXPOSE 20444
+EXPOSE 20443
+CMD ["stacks-node", "start", "--config", "/config.toml"]
+```
+{% endstep %}
+{% endstepper %}
diff --git a/docs/reference/nakamoto-upgrade/what-is-the-nakamoto-release.md b/docs/reference/nakamoto-upgrade/what-is-the-nakamoto-release.md
new file mode 100644
index 0000000000..06af4c791e
--- /dev/null
+++ b/docs/reference/nakamoto-upgrade/what-is-the-nakamoto-release.md
@@ -0,0 +1,101 @@
+# What is the Nakamoto Release?
+
+The Nakamoto Release is a recent hard fork on the Stacks network designed to bring several benefits, chief among them are increased transaction throughput and 100% Bitcoin finality.
+
+With Nakamoto, Stacks block production would no longer be tied to miner elections. Instead, miners produce blocks at a fixed cadence, and the set of PoX Stackers rely on the miner elections to determine when the current miner should stop producing blocks and a new miner should start. This blockchain will only fork if 70% of Stackers approve the fork, and chain reorganization will be as difficult as reorganizing Bitcoin.
+
+The Nakamoto release brings many new capabilities and improvements to the Stacks blockchain by focusing on a set of core advancements: improving transaction speed, enhancing finality guarantees for transactions, mitigating Bitcoin miner MEV (miner extractable value) opportunities that affect PoX, and boosting robustness against chain reorganizations.
+
+### Previous Stacks Block Production Design
+
+The Stacks blockchain today produces blocks in accordance with the algorithms described in [SIP-001](https://github.com/stacksgov/sips/blob/main/sips/sip-001/sip-001-burn-election.md) and [SIP-007](https://github.com/stacksgov/sips/blob/main/sips/sip-007/sip-007-stacking-consensus.md), and [SIP-015](https://github.com/stacksgov/sips/blob/main/sips/sip-015/sip-015-network-upgrade.md). Miners compete to append a block to the blockchain through the miner selection process facilitated by a VRF backed sortition process. Miners submit a block-commit transaction to Bitcoin, which commits to the hash of the block the miner intends to append. The sortition process selects at most one block-commit in the subsequent Bitcoin block, which entitles the submitter to propagate their block and earn a block reward.
+
+{% hint style="info" %}
+Throughout this documentation and the SIPs, you'll frequently see the term "cryptographic sortition" or some variation thereof (miner sortition, the sortition, etc.). A Cryptographic sortition is a process of randomly selecting one or more entities from a set using cryptography. This is a decentralized and verifiable way to select participants for a variety of tasks, such as consensus protocols, lotteries, and auctions.
+
+More specifically, miner sortition in the context of Stacks is the weighted cryptographic sortition process by which a miner candidate is selected as the next miner (leader). Details of this process are in [SIP-001](https://github.com/stacksgov/sips/blob/main/sips/sip-001/sip-001-burn-election.md) with mechanism alterations in [SIP-007](https://github.com/stacksgov/sips/blob/main/sips/sip-007/sip-007-stacking-consensus.md).
+
+Nakamoto will introduce further mechanism alterations to this process.
+{% endhint %}
+
+### The Problems
+
+{% stepper %}
+{% step %}
+### Slow Bitcoin blocks, Stacks forks, and missed sortitions are disruptive to on-chain applications
+
+The act of waiting to produce a new block until after a sortition elects a valid miner ties best-case Stacks block production rate to the block production rate of Bitcoin, leading to very high transaction confirmation latency.
+{% endstep %}
+
+{% step %}
+### Microblocks are not effective in speeding up transaction confirmation time
+
+While microblocks have the potential to mitigate missed sortitions and improve transaction inclusion time, they do not work in practice because the protocol cannot ensure that microblocks will be confirmed until the next sortition happens. Additionally, new miners will often orphan recently-confirmed transactions from the old miner that were included in microblocks because there is no consensus-critical procedure that forces the next miner to build upon the latest microblock.
+{% endstep %}
+
+{% step %}
+### Stacks forks are not tied to Bitcoin forks, allowing cheap reorgs
+
+The cost to reorg the last N blocks in the Stacks blockchain is the cost to produce the next N + 1 Stacks blocks (i.e. by spending BTC), which is cheap compared to the cost of reorging the Bitcoin. This SIP describes an opportunity to tie the canonical Stacks fork to the Bitcoin blockchain such that the act of reorging Stacks chain history requires the Stacks miner to produce the fork with 70% of stacker sign-off.
+{% endstep %}
+
+{% step %}
+### Stacks forks arise due to poorly-connected miners
+
+If a set of miners has a hard time learning the canonical Stacks chain tip when they submit block-commits, then they will collectively orphan other miners who are better-connected. This has happened in practice.
+{% endstep %}
+
+{% step %}
+### Some Bitcoin miners censor other Stacks miners' block-commits
+
+Some Bitcoin miners run their own Stacks miners and deliberately exclude other Stacks miners' `block-commits` from their Bitcoin blocks. Once the STX block reward became sufficiently large this allowed them to pay a trivial PoX payout while guaranteeing that they would win the cryptographic sortition in their Bitcoin block. This was anticipated in the original design but the regularity with which it happens today is greater than the original protocol accounted for, and thus must be addressed now.
+{% endstep %}
+{% endstepper %}
+
+### The Solutions
+
+To address these shortcomings, Nakamoto applies three fundamental changes to the way Stacks works.
+
+* Fast blocks: The time taken for a user-submitted transaction to be mined within a block (and thus confirmed) will now take on the order of seconds, instead of tens of minutes. This is achieved by separating block production from cryptographic sortitions -- a winning miner may produce many blocks between two subsequent sortitions.
+* Bitcoin finality: Once a transaction is confirmed, reversing it is at least as hard as reversing a Bitcoin transaction. The Stacks blockchain no longer forks on its own.
+* Bitcoin Miner MEV Resistance: This proposal alters the sortition algorithm to ensure that Bitcoin miners do not have an advantage as Stacks miners. They must spend competitive amounts of Bitcoin currency to have a chance of earning STX.
+
+### Nakamoto Design
+
+To achieve these goals Nakamoto introduced the following changes to the Stacks protocol:
+
+{% stepper %}
+{% step %}
+### Decouple Stacks tenure changes from Bitcoin block arrivals
+
+In both today's system and Nakamoto, miners take turns appending blocks to the Stacks blockchain -- the next miner is selected by cryptographic sortition, and the miner has the duration of the Bitcoin block (its tenure) to announce a new block state. Nakamoto allows a miner to produce many Stacks blocks per Bitcoin block instead of one, and requiring the next miner to confirm all of them. There are no more microblocks or Bitcoin-anchored blocks; instead, there are only Nakamoto Stacks blocks. This will achieve fast block times.
+{% endstep %}
+
+{% step %}
+### Require stackers to collaborate before the next block can be produced
+
+Stackers will need to collectively validate, store, sign, and propagate each Nakamoto Stacks block the miner produces before the next block can be produced. Stackers must do this in order to earn their PoX payouts and unlock their STX (i.e. PoX is now treated as compensation from the miner for playing this essential role). In Nakamoto, a sortition only selects a new miner; it does not give the miner the power to unilaterally orphan confirmed transactions as it does today. This will ensure that miners do not produce forks and are able to confirm all prior Stacks blocks prior to selection.
+{% endstep %}
+
+{% step %}
+### Use stackers to police miner behavior
+
+A sortition causes the Stackers to carry out a tenure change by (a) agreeing on a "last-signed" block from the current miner, and (b) agreeing to only sign blocks from the new miner which descend from this last-signed block. Thus, Stackers police miner behavior -- Stackers prevent miners from mining forks during their tenure, and ensure that they begin their tenures by building atop the canonical chain tip. The new miner cannot orphan recently-confirmed transactions from the old miner because the signers who approved the tenure change are necessarily aware of all Stacks blocks that came before it. This further prevents miners from forking the Stacks blockchain.
+{% endstep %}
+
+{% step %}
+### Require miners to commit indexed block hash of the prior miner's first block in Bitcoin
+
+Require Stacks miners to commit the indexed block hash of the first block produced by the last Stacks miner in their block-commit transactions on the Bitcoin blockchain. This is the SHA512/256 hash of both the consensus hash of all previously-accepted Bitcoin transactions that Stacks recognizes, as well as the hash of the block itself (a block-commit today only contains the hash of the Stacks block). This will anchor the Stacks chain history to the Bitcoin up to the start of the previous miner's tenure, as well as all causally-dependent Bitcoin state that Stacks has processed. This ensures Bitcoin finality and resolves miner connectivity issues by putting fork prevention on Stackers.
+{% endstep %}
+
+{% step %}
+### Adopt a Bitcoin MEV solution which punishes block-commit censorship
+
+The probability a stacks miner wins a sortition should be altered such that omitting block commits of honest Stacks miners is not profitable to Bitcoin miners. The mechanics of this are outlined below.
+{% endstep %}
+{% endstepper %}
+
+Although Nakamoto is a breaking change, all smart contracts published prior to its activation will be usable after it activates.
+
+Let's dive into how each of these pieces work so we can get an in-depth understanding of exactly how Nakamoto works.
diff --git a/docs/reference/node-operations/rpc-api.md b/docs/reference/node-operations/rpc-api.md
new file mode 100644
index 0000000000..bbdab62829
--- /dev/null
+++ b/docs/reference/node-operations/rpc-api.md
@@ -0,0 +1,249 @@
+# RPC-API
+
+### Introduction
+
+The Stacks Blockchain API allows you to query the Stacks blockchain and interact with smart contracts. It was built to maintain pageable materialized views of the Stacks Blockchain.
+
+Note that the [Stacks Node RPC API](https://github.com/stacks-network/stacks-blockchain/) and the [Hiro Stacks API](https://www.hiro.so/stacks-api) are two different things. The Hiro API is a centralized service run by Hiro, a developer tooling company, that makes it easy to get onboarded and begin interacting with the Stacks blockchain in a RESTful way. You can also [run your own API server](https://docs.hiro.so/get-started/running-api-node).
+
+The Hiro Stacks API is a proxy for the Stacks Node API that makes it a bit easier to work with by providing additional functionality.
+
+The RPC API is generated by every Stacks node and allows developers to self-host their own node and API for a more decentralized architecture.
+
+The RPC API can be used without any authorization. The basepath for the API is:
+
+```bash
+# for mainnet, replace `testnet` with `mainnet`
+https://api.testnet.hiro.so/
+```
+
+{% hint style="warning" %}
+If you run a local node, it exposes an HTTP server on port `20443`. The info endpoint would be `localhost:20443/v2/info`.
+{% endhint %}
+
+***
+
+### Stacks Node RPC API endpoints
+
+The Stacks Blockchain RPC API is exposed by every running Stacks node. Below is an interactive list of common RPC endpoints.
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v2/transactions" method="post" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v2/map_entry/{contract_address}/{contract_name}/{map_name}" method="post" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v2/contracts/interface/{contract_address}/{contract_name}" method="get" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v2/contracts/source/{contract_address}/{contract_name}" method="get" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v2/contracts/call-read/{contract_address}/{contract_name}/{function_name}" method="post" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v3/contracts/fast-call-read/{contract_address}/{contract_name}/{function_name}" method="post" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v2/accounts/{principal}" method="get" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v2/fees/transaction" method="post" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v2/fees/transfer" method="get" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v2/info" method="get" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v2/pox" method="get" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v2/traits/{contract_address}/{contract_name}/{trait_contract_address}/{trait_contract_name}/{trait_name}" method="get" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v2/clarity/marf/{marf_key_hash}" method="get" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v2/clarity/metadata/{contract_address}/{contract_name}/{clarity_metadata_key}" method="get" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v2/constant_val/{contract_address}/{contract_name}/{constant_name}" method="get" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v3/block_proposal" method="post" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v3/stacker_set/{cycle_number}" method="get" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v3/blocks/{block_id}" method="get" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v3/blocks/height/{block_height}" method="get" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v3/tenures/info" method="get" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v3/tenures/{block_id}" method="get" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v3/tenures/blocks/{consensus_hash}" method="get" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v3/tenures/blocks/hash/{burnchain_block_hash}" method="get" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v3/tenures/blocks/height/{burnchain_block_height}" method="get" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v3/sortitions" method="get" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v3/sortitions/latest_and_last" method="get" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v3/sortitions/consensus/{consensus_hash}" method="get" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v3/sortitions/burn/{burn_header_hash}" method="get" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v3/sortitions/burn_height/{height}" method="get" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v3/signer/{signer_pubkey}/{cycle_number}" method="get" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v3/transaction/{txid}" method="get" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v3/health" method="get" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v2/attachments/{hash}" method="get" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v2/attachments/inv" method="get" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v2/microblocks/confirmed/{block_id}" method="get" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v2/microblocks/{microblock_id}" method="get" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v2/microblocks/unconfirmed/{block_id}/{seq}" method="get" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v2/microblocks" method="post" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v2/stackerdb/{principal}/{contract_name}/{slot_id}" method="get" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v2/stackerdb/{principal}/{contract_name}/{slot_id}/{slot_version}" method="get" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v2/stackerdb/{principal}/{contract_name}" method="get" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v2/stackerdb/{principal}/{contract_name}/chunks" method="post" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v2/stackerdb/{principal}/{contract_name}/replicas" method="get" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v2/data_var/{principal}/{contract_name}/{var_name}" method="get" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v2/headers/{quantity}" method="get" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v2/blocks/{block_id}" method="get" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v2/neighbors" method="get" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v3/tenures/fork_info/{start}/{stop}" method="get" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v3/tenures/tip/{consensus_hash}" method="get" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v2/transactions/unconfirmed/{txid}" method="get" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v2/blocks/upload/{consensus_hash}" method="post" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v2/mempool/query" method="post" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v3/blocks/upload" method="post" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+{% openapi-operation spec="stacks-blockchain-api" path="/v3/blocks/replay/{block_id}" method="get" %}
+[OpenAPI stacks-blockchain-api](https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml)
+{% endopenapi-operation %}
+
+***
+
+For details about request/response schemas, consult the Stacks node OpenAPI spec:\
+https://raw.githubusercontent.com/stacks-network/stacks-core/master/docs/rpc/openapi.yaml
diff --git a/docs/reference/node-operations/signer-configuration.md b/docs/reference/node-operations/signer-configuration.md
new file mode 100644
index 0000000000..ed5e7439a5
--- /dev/null
+++ b/docs/reference/node-operations/signer-configuration.md
@@ -0,0 +1,243 @@
+# Signer Configuration
+
+{% hint style="info" %}
+Note that in this version, the Stacks node will not boot if it sees config values that are unused. If your node is not booting, be sure to check your logs for any messages indicating
+{% endhint %}
+
+## Signer Configuration
+
+#### Signer Configuration File Options
+
+The signer configuration file is a TOML file that contains the configuration options for your signer. Below are the options you can set in the signer configuration file.
+
+| Name | Required | Description |
+| ---------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| node\_host | ✓ | IP:PORT where your Stacks node can be accessed. The port 20443 is the default RPC endpoint for Stacks nodes. Note that you must use an IP address - DNS hosts are not supported at this time. |
+| endpoint | ✓ | IP:PORT where the signer will expose an RPC endpoint for receiving events from your Stacks node. |
+| stacks\_private\_key | ✓ | Hex representation of the signer's Stacks private key used for communicating with the Stacks Node, including writing to the Stacker DB instance. |
+| network | ✓ | Network to use. One of "mainnet", "testnet" or "mocknet". |
+| auth\_password | ✓ | Authorization token for HTTP requests made from the signer to your Stacks node. |
+| db\_path | ✓ | Path to the signer's database file |
+| block\_proposal\_timeout\_ms | | Specifies the maximum time (in milliseconds) a signer waits after a Bitcoin block for a miner to produce their first Nakamoto block. If the miner exceeds this time, the signer marks their tenure as invalid and rejects subsequent block proposals. Default value of 600\_000 (10 minutes). |
+| metrics\_endpoint | | IP:PORT for Prometheus metrics collection. |
+| chain\_id | | An optional ChainID, only used for custom networks (like Nakamoto Testnet) |
+
+#### Example Configs
+
+Below are sample configuration files for running a Stacks node and signer provided in one place for convenience. You'll need to modify some of these according to the [How to Run a Signer](/broken/pages/261edd335c0b98fb052ad55906fbf90832800453) doc.
+
+#### Testnet Signer
+
+```toml
+# The IP address and port where your Stacks node can be accessed.
+# The port 20443 is the default RPC endpoint for Stacks nodes.
+# Note that you must use an IP address - DNS hosts are not supported at this time.
+# This should be the IP address accessible via Docker, usually via a network.
+node_host = "127.0.0.1:20443"
+
+# This is the location where the signer will expose an RPC endpoint for
+# receiving events from your Stacks node.
+endpoint = "127.0.0.1:30000"
+
+# Either “testnet” or “mainnet”
+network = "testnet"
+
+# this is a file path where your signer will persist data. If using Docker,
+# this must be within a volume, so that data can be persisted across restarts
+db_path = "/var/stacks/signer.sqlite"
+
+# an authentication token that is used for some HTTP requests made from the
+# signer to your Stacks node. You’ll need to use this later on when configuring
+# your Stacks node. You create this field yourself, rather than it being generated
+# with your private key.
+auth_password = "$your_http_auth_token"
+
+# This is the privateKey field from the keys you generated in the
+# previous step.
+stacks_private_key = "$your_stacks_private_key"
+```
+
+#### Stacks Node Testnet Config
+
+{% hint style="warning" %}
+Note that the `block_proposal_token` field has changed to `auth_token` in the Stacks node configuration file.
+{% endhint %}
+
+This is the configuration you'll need to run a Stacks follower node if you are also running a signer. Be sure to change the commented lines to the appropriate data for your setup. If you are not familiar with the process of setting up a signer, be sure to follow the [How to Run a Signer](/broken/pages/261edd335c0b98fb052ad55906fbf90832800453) guide.
+
+An overview of all Stacks node configuration options can be found in the [Stacks Node Configuration](/broken/pages/79a6d21c88b879210b9f2036268ace38ae6a02af) doc.
+
+Additions necessary specifically to run a signer are the `[connection_options]` and `[[events_observer]]` sections and the `stacker = true` line. There are also a few comments detailing other lines that need to change.
+
+```toml
+[node]
+
+rpc_bind = "0.0.0.0:20443"
+p2p_bind = "0.0.0.0:20444"
+bootstrap_node = "029266faff4c8e0ca4f934f34996a96af481df94a89b0c9bd515f3536a95682ddc@seed.testnet.hiro.so:30444"
+prometheus_bind = "127.0.0.1:9153"
+working_dir = "/hirosystems/data"
+local_peer_seed = "{{ redacted }}"
+
+# Required for nodes attached to signers, optional for other nodes
+stacker = true
+
+[burnchain]
+chain = "bitcoin"
+mode = "krypton"
+peer_host = "bitcoin.regtest.hiro.so"
+peer_port = 18444
+pox_prepare_length = 100
+pox_reward_length = 900
+
+# Set your auth token, which the signer uses
+# This should match the auth_password field of your signer config
+[connection_options]
+auth_token = "12345"
+
+# Set your signer as an event observer
+[[events_observer]]
+
+# This endpoint is where your signer will communicate with your Stacks node
+endpoint = "127.0.0.1:30000"
+events_keys = ["stackerdb", "block_proposal", "burn_blocks"]
+
+[[ustx_balance]]
+address = "ST2QKZ4FKHAH1NQKYKYAYZPY440FEPK7GZ1R5HBP2"
+amount = 10000000000000000
+
+[[ustx_balance]]
+address = "ST319CF5WV77KYR1H3GT0GZ7B8Q4AQPY42ETP1VPF"
+amount = 10000000000000000
+
+[[ustx_balance]]
+address = "ST221Z6TDTC5E0BYR2V624Q2ST6R0Q71T78WTAX6H"
+amount = 10000000000000000
+
+[[ustx_balance]]
+address = "ST2TFVBMRPS5SSNP98DQKQ5JNB2B6NZM91C4K3P7B"
+amount = 10000000000000000
+
+[fee_estimation]
+fee_estimator = "fuzzed_weighted_median_fee_rate"
+
+[[burnchain.epochs]]
+epoch_name = "1.0"
+start_height = 0
+
+[[burnchain.epochs]]
+epoch_name = "2.0"
+start_height = 0
+
+[[burnchain.epochs]]
+epoch_name = "2.05"
+start_height = 1
+
+[[burnchain.epochs]]
+epoch_name = "2.1"
+start_height = 2
+
+[[burnchain.epochs]]
+epoch_name = "2.2"
+start_height = 3
+
+[[burnchain.epochs]]
+epoch_name = "2.3"
+start_height = 4
+
+[[burnchain.epochs]]
+epoch_name = "2.4"
+start_height = 5
+
+[[burnchain.epochs]]
+epoch_name = "2.5"
+start_height = 6
+
+[[burnchain.epochs]]
+epoch_name = "3.0"
+start_height = 1_900
+
+[[burnchain.epochs]]
+epoch_name = "3.1"
+start_height = 2_000
+
+[[burnchain.epochs]]
+epoch_name = "3.2"
+start_height = 71_525
+```
+
+#### Mainnet Signer
+
+This config is very similar to the testnet config, except the `network` field is changed.
+
+```toml
+# The IP address and port where your Stacks node can be accessed.
+# The port 20443 is the default RPC endpoint for Stacks nodes.
+# Note that you must use an IP address - DNS hosts are not supported at this time.
+# This should be the IP address accessible via Docker, usually via a network.
+node_host = "127.0.0.1:20443"
+
+# This is the location where the signer will expose an RPC endpoint for
+# receiving events from your Stacks node.
+endpoint = "127.0.0.1:30000"
+
+# Either “testnet” or “mainnet”
+network = "mainnet"
+
+# this is a file path where your signer will persist data. If using Docker,
+# this must be within a volume, so that data can be persisted across restarts
+db_path = "/var/stacks/signer.sqlite"
+
+# an authentication token that is used for some HTTP requests made from the
+# signer to your Stacks node. You’ll need to use this later on when configuring
+# your Stacks node. You create this field yourself, rather than it being generated
+# with your private key.
+auth_password = "$your_http_auth_token"
+
+# This is the privateKey field from the keys you generated in the
+# previous step.
+stacks_private_key = "$your_stacks_private_key"
+
+# The IP address and port where prometheus metrics can be accessed.
+metrics_endpoint = "127.0.0.1:9154"
+
+# Determining when a time-based tenure extend will be accepted
+tenure_idle_timeout_secs = 120
+```
+
+#### Mainnet Stacks Node
+
+With a mainnet Stacks node config, you'll need to change the bootstrap node field and the burnchain fields. Other than that, the `ustx_balance` fields are not necessary.
+
+```toml
+[node]
+
+# Set this based on where you downloaded
+# the chain state archive as described in the How to Run a Signer guide:
+working_dir = "/data-dir-somewhere"
+rpc_bind = "0.0.0.0:20443"
+p2p_bind = "0.0.0.0:20444"
+
+# This is the node that your node will use to begin syncing chain state
+bootstrap_node = "02196f005965cebe6ddc3901b7b1cc1aa7a88f305bb8c5893456b8f9a605923893@seed.mainnet.hiro.so:20444,02539449ad94e6e6392d8c1deb2b4e61f80ae2a18964349bc14336d8b903c46a8c@cet.stacksnodes.org:20444,02ececc8ce79b8adf813f13a0255f8ae58d4357309ba0cedd523d9f1a306fcfb79@sgt.stacksnodes.org:20444,0303144ba518fe7a0fb56a8a7d488f950307a4330f146e1e1458fc63fb33defe96@est.stacksnodes.org:20444"
+
+# Required for nodes attached to signers, optional for other nodes
+stacker = true
+
+[burnchain]
+chain = "bitcoin"
+mode = "mainnet"
+peer_host = "bitcoin.mainnet.stacks.org"
+
+# Set your auth token, which the signer uses
+# This should match the auth_password field of your signer config
+[connection_options]
+auth_token = "12345"
+
+# Set your signer as an event observer
+[[events_observer]]
+
+# This endpoint is where your signer will communicate with your Stacks node
+endpoint = "127.0.0.1:30000"
+events_keys = ["stackerdb", "block_proposal", "burn_blocks"]
+```
diff --git a/docs/reference/node-operations/stacks-node-configuration.md b/docs/reference/node-operations/stacks-node-configuration.md
new file mode 100644
index 0000000000..63c8f42adc
--- /dev/null
+++ b/docs/reference/node-operations/stacks-node-configuration.md
@@ -0,0 +1,235 @@
+# Stacks Node Configuration
+
+{% hint style="info" %}
+Note that these config fields are for a Stacks follower node. If you are running a signer alongside your Stacks node, you'll want to use the sample file found on the [Signer Configuration](/broken/pages/8ea1fa91cfa819c25f545b0aca9bfc16c8c3ad28) page as it contains additional parameters needed for your signer and Stacks node to function properly.
+{% endhint %}
+
+### Usage
+
+```bash
+stacks-node sub-command [--subcommand-option ]
+```
+
+#### Subcommands
+
+* `mocknet`: start a mocknet instance using defaults
+* `testnet`: start a testnet instance using defaults (chainstate is not persistent)
+* `mainnet`: start a mainnet instance using defaults (chainstate is not persistent)
+* `start`: combined with `--config`, starts an instance with a specified configuration file
+* `version`: displays binary version
+* `help`: displays the help message
+
+### Configuration File Options
+
+The Stacks Blockchain configuration file has multiple sections under which an option may be placed.
+
+* node
+* events\_observer
+* connection\_options
+* burnchain
+* ustx\_balance
+* miner
+
+For reference, several configuration file examples are [available here](https://github.com/stacks-network/stacks-core/tree/master/sample/conf).
+
+#### node
+
+Contains various configuration options for the stacks-node binary.
+
+| Name | Required | Description |
+| ---------------------------- | -------- | ---------------------------------------------------------------------------------------------------------- |
+| rpc\_bind | ✓ | IPv4 address and port to open for RPC connections |
+| p2p\_bind | ✓ | IPv4 address and port to open for P2P connections |
+| working\_dir | | Absolute path to the directory where chainstate data will be stored |
+| data\_url | | IPv4 address and port for incoming RPC connections |
+| p2p\_address | | IPv4 address and port for incoming P2P connections |
+| bootstrap\_node | | Public key, IPv4 address, and port to bootstrap the chainstate |
+| wait\_time\_for\_microblocks | | The amount of time in ms to wait before trying to mine a block after catching up to the anchored chain tip |
+| seed | | The private key to use for mining. Only needed if `miner` is set to `true` |
+| local\_peer\_seed | | The private key to use for signing P2P messages in the networking stack |
+| miner | | Determines whether the node is running a follower (`false`) or a miner (`true`). Defaults to `false` |
+| mock\_mining | | Simulates running a miner (typically used for debugging) |
+| mock\_mining\_output\_dir | | Folder for mock mining data |
+| mine\_microblocks | | Determines whether the node will mine microblocks. Will only take effect if `miner` is set to `true` |
+| prometheus\_bind | | Address and port for Prometheus metrics collection. |
+| deny\_nodes | | List of ip addresses of nodes that should be ignored |
+| stacker | | Determines whether the node is running a stacker (`true`) that issues events for signer binary |
+
+#### events\_observer
+
+{% hint style="info" %}
+This section is _optional_ and not required
+
+However, if this section is added, **all** fields are required.
+{% endhint %}
+
+Contains options for sending events emitted to the [stacks-blockchain-api](https://github.com/hirosystems/stacks-blockchain-api) service.
+
+| Name | Required | Description |
+| ------------ | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| endpoint | ✓ | Address and port to a [stacks-blockchain-api](https://github.com/hirosystems/stacks-blockchain-api) service |
+| events\_keys | ✓ | Event keys for which to watch. The emitted node events can be restricted by account, function name and event type. Asterix ("\*") can be used to emit all events. |
+
+#### connection\_options
+
+{% hint style="info" %}
+This section is _optional_ and not required.
+{% endhint %}
+
+Specifies configuration options for others connecting to the stacks node.
+
+| Name | Required | Description |
+| ------------------------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| public\_ip\_address | | Public IPv4 to advertise to other nodes |
+| download\_interval | | Time (in seconds) between attempts to download blocks |
+| walk\_interval | | Time (in seconds) between attempts to walk the list of neighbors |
+| private\_neighbors | | If false, this node won't announce or accept neighbors that are behind private networks. Defaults to true. |
+| read\_only\_call\_limit\_read\_length | | Total number of bytes allowed to be read by an individual read-only function call |
+| read\_only\_call\_limit\_read\_count | | Total number of independent read operations permitted for an individual read-only function call |
+| read\_only\_call\_limit\_runtime | | [Runtime cost](https://github.com/stacksgov/sips/blob/main/sips/sip-006/sip-006-runtime-cost-assessment.md) limit for an individual read-only function call |
+
+#### burnchain
+
+This section contains configuration options pertaining to the blockchain the stacks-node binds to on the backend for proof-of-transfer (BTC).
+
+| Name | Required | Description |
+| ---------- | -------- | --------------------------------------------------------------------------------------------------------------------- |
+| chain | ✓ | The blockchain stacks-node binds to on the backend for proof-of-transfer. Only value supported: `bitcoin` |
+| mode | ✓ | The profile or test phase of which to run stacks-node. Valid values are \[ `mocknet`, `testnet`, `xenon`, `mainnet` ] |
+| peer\_host | | FQDN of the host running the backend Bitcoin blockchain |
+| rpc\_port | | RPC port of `peer_host` |
+| peer\_port | | P2P port of `peer_host` |
+
+**Mining**
+
+| Name | Required | Description |
+| -------------------------------- | -------- | -------------------------------------------------------------------------------------------------- |
+| burn\_fee\_cap | ✓ | Maximum amount (in sats) of "burn commitment" to broadcast for the next block's leader election |
+| satoshis\_per\_byte | ✓ | [Amount (in sats) per byte](https://bitcoinfees.net/) - Used to calculate the transaction fees |
+| commit\_anchor\_block\_within | | Sets the time period (in milliseconds) for commitments. Only used when `mode` is set to `mocknet`. |
+| tenure\_extend\_cost\_threshold | | Percentage of block budget that must be used before attempting a time-based tenure extend |
+| block\_rejection\_timeout\_steps | | Define the timeout to apply while waiting for signers responses, based on the amount of rejections |
+
+#### ustx\_balance
+
+{% hint style="info" %}
+This section is only required for the `testnet` and `mocknet` networks.
+
+However, if this section is added, **all** fields are required.
+{% endhint %}
+
+This section contains configuration options allocating microSTX per address in the genesis block
+
+This section can repeat multiple times, but each section can only define a single address.
+
+| Name | Required | Description |
+| ------- | -------- | --------------------------------------------------------------------- |
+| address | ✓ | Address which maintains a microSTX balance |
+| amount | ✓ | The balance of microSTX given to the address at the start of the node |
+
+### Example Mainnet Follower Configuration
+
+{% code title="stacks-node-mainnet.toml" %}
+```toml
+[node]
+working_dir = "/stacks-blockchain"
+rpc_bind = "0.0.0.0:30443"
+p2p_bind = "0.0.0.0:20444"
+bootstrap_node = "02196f005965cebe6ddc3901b7b1cc1aa7a88f305bb8c5893456b8f9a605923893@seed.mainnet.hiro.so:20444,02539449ad94e6e6392d8c1deb2b4e61f80ae2a18964349bc14336d8b903c46a8c@cet.stacksnodes.org:20444,02ececc8ce79b8adf813f13a0255f8ae58d4357309ba0cedd523d9f1a306fcfb79@sgt.stacksnodes.org:20444,0303144ba518fe7a0fb56a8a7d488f950307a4330f146e1e1458fc63fb33defe96@est.stacksnodes.org:20444"
+
+[burnchain]
+chain = "bitcoin"
+mode = "mainnet"
+peer_host = "localhost"
+peer_port = 8333
+
+[[events_observer]]
+endpoint = "localhost:3700"
+events_keys = ["*"]
+```
+{% endcode %}
+
+### Example Testnet Follower Configuration
+
+{% code title="stacks-node-testnet.toml" %}
+```toml
+[node]
+
+rpc_bind = "0.0.0.0:20443"
+p2p_bind = "0.0.0.0:20444"
+bootstrap_node = "029266faff4c8e0ca4f934f34996a96af481df94a89b0c9bd515f3536a95682ddc@seed.testnet.hiro.so:30444"
+prometheus_bind = "127.0.0.1:9153"
+working_dir = "/stacks-blockchain"
+
+[burnchain]
+chain = "bitcoin"
+mode = "krypton"
+peer_host = "bitcoin.regtest.hiro.so"
+peer_port = 18444
+pox_prepare_length = 100
+pox_reward_length = 900
+
+[[ustx_balance]]
+address = "ST2QKZ4FKHAH1NQKYKYAYZPY440FEPK7GZ1R5HBP2"
+amount = 10000000000000000
+
+[[ustx_balance]]
+address = "ST319CF5WV77KYR1H3GT0GZ7B8Q4AQPY42ETP1VPF"
+amount = 10000000000000000
+
+[[ustx_balance]]
+address = "ST221Z6TDTC5E0BYR2V624Q2ST6R0Q71T78WTAX6H"
+amount = 10000000000000000
+
+[[ustx_balance]]
+address = "ST2TFVBMRPS5SSNP98DQKQ5JNB2B6NZM91C4K3P7B"
+amount = 10000000000000000
+
+[fee_estimation]
+fee_estimator = "fuzzed_weighted_median_fee_rate"
+
+[[burnchain.epochs]]
+epoch_name = "1.0"
+start_height = 0
+
+[[burnchain.epochs]]
+epoch_name = "2.0"
+start_height = 0
+
+[[burnchain.epochs]]
+epoch_name = "2.05"
+start_height = 1
+
+[[burnchain.epochs]]
+epoch_name = "2.1"
+start_height = 2
+
+[[burnchain.epochs]]
+epoch_name = "2.2"
+start_height = 3
+
+[[burnchain.epochs]]
+epoch_name = "2.3"
+start_height = 4
+
+[[burnchain.epochs]]
+epoch_name = "2.4"
+start_height = 5
+
+[[burnchain.epochs]]
+epoch_name = "2.5"
+start_height = 6
+
+[[burnchain.epochs]]
+epoch_name = "3.0"
+start_height = 1_900
+
+[[burnchain.epochs]]
+epoch_name = "3.1"
+start_height = 2_000
+
+[[burnchain.epochs]]
+epoch_name = "3.2"
+start_height = 71_525
+```
+{% endcode %}
diff --git a/docs/reference/rendezvous/reference.md b/docs/reference/rendezvous/reference.md
new file mode 100644
index 0000000000..81ffff632f
--- /dev/null
+++ b/docs/reference/rendezvous/reference.md
@@ -0,0 +1,558 @@
+---
+description: >-
+ Complete reference for Rendezvous CLI commands, configuration options, and
+ advanced usage.
+---
+
+# Rendezvous Reference
+
+This reference explains how to use Rendezvous in different situations. By the end, you'll know when and how to use its features effectively.
+
+## What's Inside
+
+[Running Rendezvous](#running-rendezvous)
+ - [Positional Arguments](#positional-arguments)
+ - [Options](#options)
+ - [Summary](#summary)
+
+[Understanding Rendezvous](#understanding-rendezvous)
+ - [Example](#example)
+
+[The Rendezvous Context](#the-rendezvous-context)
+ - [How the Context Works](#how-the-context-works)
+ - [Using the context to write invariants](#using-the-context-to-write-invariants)
+
+[Discarding Property-Based Tests](#discarding-property-based-tests)
+ - [Discard Function](#discard-function)
+ - [In-Place Discarding](#in-place-discarding)
+ - [Discarding summary](#discarding-summary)
+
+[Custom Manifest Files](#custom-manifest-files)
+ - [Why use a custom manifest?](#why-use-a-custom-manifest)
+ - [A test double for `sbtc-registry`](#a-test-double-for-sbtc-registry)
+ - [A Custom Manifest File](#a-custom-manifest-file)
+ - [How It Works](#how-it-works)
+
+[Trait Reference Parameters](#trait-reference-parameters)
+ - [How Trait Reference Selection Works](#how-trait-reference-selection-works)
+ - [Example](#example-1)
+ - [Adding More Implementations](#adding-more-implementations)
+
+---
+
+## Running Rendezvous
+
+To run Rendezvous, use the following command:
+
+```bash
+rv [--seed] [--runs] [--bail] [--dial]
+```
+
+Let's break down each part of the command.
+
+### Positional Arguments
+
+Consider this example Clarinet project structure:
+
+```
+root
+├── Clarinet.toml
+├── contracts
+│ ├── contract.clar
+│ ├── contract.tests.clar
+└── settings
+ └── Devnet.toml
+```
+
+**1. Path to the Clarinet Project**
+
+The `` is the relative or absolute path to the root directory of the Clarinet project. This is where the `Clarinet.toml` file exists. **It is not the path to the `Clarinet.toml` file itself**.
+
+For example, if you're in the parent directory of `root`, the correct relative path would be:
+
+```bash
+rv ./root
+```
+
+**2. Contract Name**
+
+The `` is the name of the contract to be tested, as defined in `Clarinet.toml`.
+
+For example, if `Clarinet.toml` contains:
+
+```toml
+[contracts.contract]
+path = "contracts/contract.clar"
+```
+
+To test the contract named `contract`, you would run:
+
+```bash
+rv ./root contract
+```
+
+**3. Testing Type**
+
+The `` argument specifies the testing technique to use. The available options are:
+
+- `test` – Runs property-based tests.
+- `invariant` – Runs invariant tests.
+
+For a deeper understanding of these techniques and when to use each, see [Testing Methodologies](https://stacks-network.github.io/rendezvous/chapter_4.md) chapter of the [Rendezvous Docs](https://stacks-network.github.io/rendezvous/).
+
+**Running property-based tests**
+
+To run property-based tests for the `contract` contract, ensure that your test functions are defined in:
+
+```
+./root/contracts/contract.tests.clar
+```
+
+Then, execute:
+
+```bash
+rv ./root contract test
+```
+
+This tells Rendezvous to:
+
+- Load the **Clarinet project** located in `./root`.
+- Target the **contract** named `contract` as defined in `Clarinet.toml` by executing **property-based tests** defined in `contract.tests.clar`.
+
+**Running invariant tests**
+
+To run invariant tests for the `contract` contract, ensure that your invariant functions are defined in:
+
+```
+./root/contracts/contract.tests.clar
+```
+
+To run invariant tests, use:
+
+```bash
+rv ./root contract invariant
+```
+
+With this command, Rendezvous will:
+
+- Randomly **execute public function calls** in the `contract` contract.
+- **Randomly check the defined invariants** to ensure the contract's internal state remains valid.
+
+If an invariant check fails, it means the contract's state has **deviated from expected behavior**, revealing potential bugs.
+
+### Options
+
+Rendezvous also provides additional options to customize test execution:
+
+**1. Customizing the Number of Runs**
+
+By default, Rendezvous runs **100** test iterations. You can modify this using the `--runs` option:
+
+```bash
+rv root contract test --runs=500
+```
+
+This increases the number of test cases to **500**.
+
+**2. Replaying a Specific Sequence of Events**
+
+To reproduce a previous test sequence, you can use the `--seed` option. This ensures that the same random values are used across test runs:
+
+```bash
+rv root contract test --seed=12345
+```
+
+**How to Find the Replay Seed**
+
+When Rendezvous detects an issue, it includes the seed needed to reproduce the test in the failure report. Here’s an example of a failure report with the seed:
+
+```
+Error: Property failed after 2 tests.
+Seed : 426141810
+
+Counterexample:
+...
+
+What happened? Rendezvous went on a rampage and found a weak spot:
+...
+```
+
+In this case, the seed is `426141810`. You can use it to rerun the exact same test scenario:
+
+```bash
+rv root contract test --seed=426141810
+```
+
+**3. Stop After First Failure**
+
+By default, Rendezvous will start the shrinking process after finding a failure. To stop immediately when the first failure is detected, use the `--bail` option:
+
+```bash
+rv root contract test --bail
+```
+
+This is useful when you want to examine the first failure without waiting for the complete test run and shrinking process to finish.
+
+**4. Using Dialers**
+
+Dialers allow you to define **pre- and post-execution functions** using JavaScript **during invariant testing**. To use a custom dialer file, run:
+
+```bash
+rv root contract invariant --dial=./custom-dialer.js
+```
+
+A good example of a dialer can be found in the Rendezvous repository, within the example Clarinet project, inside the [sip010.js file](https://github.com/stacks-network/rendezvous/blob/272b9247cdfcd5d12da89254e622e712d6e29e5e/example/sip010.js).
+
+In that file, you’ll find a **post-dialer** designed as a **sanity check** for SIP-010 token contracts. It ensures that the `transfer` function correctly emits the required **print event** containing the `memo`, as specified in [SIP-010](https://github.com/stacksgov/sips/blob/6ea251726353bd1ad1852aabe3d6cf1ebfe02830/sips/sip-010/sip-010-fungible-token-standard.md?plain=1#L69).
+
+**How Dialers Work**
+
+During **invariant testing**, Rendezvous picks up dialers when executing public function calls:
+
+- **Pre-dialers** run **before** each public function call.
+- **Post-dialers** run **after** each public function call.
+
+Both have access to an object containing:
+
+- `selectedFunction` – The function being executed.
+- `functionCall` – The result of the function call (`undefined` for **pre-dialers**).
+- `clarityValueArguments` – The generated Clarity values used as arguments.
+
+**Example: Post-Dialer for SIP-010**
+
+Below is a **post-dialer** that verifies SIP-010 compliance by ensuring that the `transfer` function emits a print event containing the `memo`.
+
+```js
+async function postTransferSip010PrintEvent(context) {
+ const { selectedFunction, functionCall, clarityValueArguments } = context;
+
+ // Ensure this check runs only for the "transfer" function.
+ if (selectedFunction.name !== "transfer") return;
+
+ const functionCallEvents = functionCall.events;
+ const memoParameterIndex = 3; // The memo parameter is the fourth argument.
+
+ const memoGeneratedArgumentCV = clarityValueArguments[memoParameterIndex];
+
+ // If the memo argument is `none`, there's nothing to validate.
+ if (memoGeneratedArgumentCV.type === "none") return;
+
+ // Ensure the memo argument is an option (`some`).
+ if (memoGeneratedArgumentCV.type !== "some") {
+ throw new Error("The memo argument must be an option type!");
+ }
+
+ // Convert the `some` value to hex for comparison.
+ const hexMemoArgumentValue = cvToHex(memoGeneratedArgumentCV.value);
+
+ // Find the print event in the function call events.
+ const sip010PrintEvent = functionCallEvents.find(
+ (ev) => ev.event === "print_event"
+ );
+
+ if (!sip010PrintEvent) {
+ throw new Error(
+ "No print event found. The transfer function must emit the SIP-010 print event containing the memo!"
+ );
+ }
+
+ const sip010PrintEventValue = sip010PrintEvent.data.raw_value;
+
+ // Validate that the emitted print event matches the memo argument.
+ if (sip010PrintEventValue !== hexMemoArgumentValue) {
+ throw new Error(
+ `Print event memo value does not match the memo argument: ${hexMemoArgumentValue} !== ${sip010PrintEventValue}`
+ );
+ }
+}
+```
+
+This dialer ensures that any SIP-010 token contract properly emits the **memo print event** during transfers, helping to catch deviations from the standard.
+
+### Summary
+
+| Argument/Option | Description | Example |
+| ---------------------------- | -------------------------------------------------------------------------------- | ------------------------------------------------- |
+| `` | Path to the Clarinet project (where `Clarinet.toml` is located). | `rv root contract test` |
+| `` | Name of the contract to test (as in `Clarinet.toml`). | `rv root contract test` |
+| `` | Type of test (`test` for property-based tests, `invariant` for invariant tests). | `rv root contract test` |
+| `--runs=` | Sets the number of test iterations (default: 100). | `rv root contract test --runs=500` |
+| `--seed=` | Uses a specific seed for reproducibility. | `rv root contract test --seed=12345` |
+| `--dial=` | Loads JavaScript dialers from a file for pre/post-processing. | `rv root contract test --dial=./custom-dialer.js` |
+
+---
+
+## Understanding Rendezvous
+
+Rendezvous makes **property-based tests** and **invariant tests** first-class. Tests are written in the same language as the system under test. This helps developers master the contract language. It also pushes boundaries—programmers shape their thoughts first, then express them using the language's tools.
+
+When Rendezvous initializes a **Simnet session** using a given Clarinet project, it **does not modify any contract** listed in Clarinet.toml—except for the **target contract**. During testing, Rendezvous updates the target contract by merging:
+
+1. **The original contract source code**
+2. **The test contract** (which includes property-based tests and invariants)
+3. **The Rendezvous context**, which helps track function calls and execution details
+
+### Example
+
+Let’s say we have a contract named `checker` with the following source:
+
+```clarity
+;; checker.clar
+
+(define-public (check-it (flag bool))
+ (if flag (ok 1) (err u100))
+)
+```
+
+And its test contract, `checker.tests`:
+
+```clarity
+;; checker.tests.clar
+
+(define-public (test-1)
+ (ok true)
+)
+
+(define-read-only (invariant-1)
+ true
+)
+```
+
+When Rendezvous runs the tests, it **automatically generates a modified contract** that includes the original contract, the tests, and an additional **context** for tracking execution. The final contract source deployed in the Simnet session will look like this:
+
+```
+(define-public (check-it (flag bool))
+ (if flag (ok 1) (err u100))
+)
+
+(define-map context (string-ascii 100) {
+ called: uint
+ ;; other data
+ }
+)
+
+(define-public (update-context (function-name (string-ascii 100)) (called uint))
+ (ok (map-set context function-name {called: called}))
+)
+
+(define-public (test-1)
+ (ok true)
+)
+
+(define-read-only (invariant-1)
+ true
+)
+```
+
+While the original contract source and test functions are familiar, the **context** is new. Let's take a closer look at it.
+
+## The Rendezvous Context
+
+Rendezvous introduces a **context** to track function calls and execution details during testing. This allows for better tracking of execution details and invariant validation.
+
+### How the Context Works
+
+When a function is successfully executed during a test, Rendezvous records its execution details in a **Clarity map**. This map helps track how often specific functions are called successfully and can be extended for additional tracking in the future.
+
+Here’s how the context is structured:
+
+```clarity
+(define-map context (string-ascii 100) {
+ called: uint
+ ;; Additional fields can be added here
+})
+
+(define-public (update-context (function-name (string-ascii 100)) (called uint))
+ (ok (map-set context function-name {called: called}))
+)
+```
+
+**Breaking it down**
+
+- **`context` map** → Keeps track of execution data, storing how many times each function has been called successfully.
+- **`update-context` function** → Updates the `context` map whenever a function executes, ensuring accurate tracking.
+
+### Using the context to write invariants
+
+By tracking function calls, the context helps invariants ensure **stronger correctness guarantees**. For example, an invariant can verify that a counter **stays above zero by checking the number of successful `increment` and `decrement` calls**.
+
+**Example invariant using the `context`**
+
+```clarity
+(define-read-only (invariant-counter-gt-zero)
+ (let
+ (
+ (increment-num-calls
+ (default-to u0 (get called (map-get? context "increment")))
+ )
+ (decrement-num-calls
+ (default-to u0 (get called (map-get? context "decrement")))
+ )
+ )
+ (if
+ (<= increment-num-calls decrement-num-calls)
+ true
+ (> (var-get counter) u0)
+ )
+ )
+)
+```
+
+By embedding execution tracking into the contract, Rendezvous enables **more effective smart contract testing**, making it easier to catch bugs and check the contract correctness.
+
+## Discarding Property-Based Tests
+
+Rendezvous generates a wide range of inputs, but not all inputs are valid for every test. To **skip tests with invalid inputs**, there are two approaches:
+
+### Discard Function
+
+A **separate function** determines whether a test should run.
+
+> Rules for a Discard Function:
+>
+> - Must be **read-only**.
+> - Name must match the property test function, prefixed with `"can-"`.
+> - Parameters must **mirror** the property test’s parameters.
+> - Must return `true` **only if inputs are valid**, allowing the test to run.
+
+**Discard function example**
+
+```clarity
+(define-read-only (can-test-add (n uint))
+ (> n u1) ;; Only allow tests where n > 1
+)
+
+(define-public (test-add (n uint))
+ (let
+ ((counter-before (get-counter)))
+ (try! (add n))
+ (asserts! (is-eq (get-counter) (+ counter-before n)) (err u403))
+ (ok true)
+ )
+)
+```
+
+Here, `can-test-add` ensures that the test **never executes** for `n <= 1`.
+
+### In-Place Discarding
+
+Instead of using a separate function, **the test itself decides whether to run**. If the inputs are invalid, the test returns `(ok false)`, discarding itself.
+
+**In-place discarding example**
+
+```clarity
+(define-public (test-add (n uint))
+ (let
+ ((counter-before (get-counter)))
+ (ok
+ (if
+ (<= n u1) ;; If n <= 1, discard the test.
+ false
+ (begin
+ (try! (add n))
+ (asserts! (is-eq (get-counter) (+ counter-before n)) (err u403))
+ true
+ )
+ )
+ )
+ )
+)
+```
+
+In this case, if `n <= 1`, the test **discards itself** by returning `(ok false)`, skipping execution.
+
+### Discarding summary
+
+| **Discard Mechanism** | **When to Use** |
+| ----------------------- | ----------------------------------------------------------------- |
+| **Discard Function** | When skipping execution **before** running the test is necessary. |
+| **In-Place Discarding** | When discarding logic is simple and part of the test itself. |
+
+In general, **in-place discarding is preferred** because it keeps test logic together and is easier to maintain. Use a **discard function** only when it's important to prevent execution entirely.
+
+## Custom Manifest Files
+
+Some smart contracts need a special `Clarinet.toml` file to allow Rendezvous to create state transitions in the contract. Rendezvous supports this feature by **automatically searching for `Clarinet-.toml` first**. This allows you to use test doubles while keeping tests easy to manage.
+
+### Why use a custom manifest?
+
+A great example is the **sBTC contract suite**.
+
+For testing the [`sbtc-token`](https://github.com/stacks-network/sbtc/blob/b624e4a8f08eb589a435719b200873e8aa5b3305/contracts/contracts/sbtc-token.clar#L30-L35) contract, the `sbtc-registry` authorization function [`is-protocol-caller`](https://github.com/stacks-network/sbtc/blob/b624e4a8f08eb589a435719b200873e8aa5b3305/contracts/contracts/sbtc-registry.clar#L361-L369) is **too restrictive**. Normally, it only allows calls from protocol contracts, making it **impossible to directly test certain state transitions** in `sbtc-token`.
+
+To work around this, you need two things:
+
+### A test double for `sbtc-registry`
+
+You can create an `sbtc-registry` test double called `sbtc-registry-double.clar`:
+
+```clarity
+;; contracts/sbtc-registry-double.clar
+
+...
+
+(define-constant deployer tx-sender)
+
+;; Allows the deployer to act as a protocol contract for testing
+(define-read-only (is-protocol-caller (contract-flag (buff 1)) (contract principal))
+ (begin
+ (asserts! (is-eq tx-sender deployer) (err u1234567)) ;; Enforces deployer check
+ (ok true)
+ )
+)
+
+...
+```
+
+This **loosens** the restriction just enough for testing by allowing the `deployer` to act as a protocol caller, while still enforcing an access check.
+
+### A Custom Manifest File
+
+Next, create `Clarinet-sbtc-token.toml` to tell Rendezvous to use the test double **only when targeting `sbtc-token`**:
+
+```toml
+# Clarinet-sbtc-token.toml
+
+...
+
+[contracts.sbtc-registry]
+path = 'contracts/sbtc-registry-double.clar'
+clarity_version = 3
+epoch = 3.0
+
+...
+```
+
+### How It Works
+
+- When testing `sbtc-token`, Rendezvous **first checks** if `Clarinet-sbtc-token.toml` exists.
+- If found, it **uses this file** to initialize Simnet.
+- If not, it **falls back** to the standard `Clarinet.toml`.
+
+This ensures that the test double is only used when testing `sbtc-token`, keeping tests realistic while allowing necessary state transitions.
+
+## Trait Reference Parameters
+
+Rendezvous automatically generates arguments for function calls. It handles most Clarity types without any setup from you. However, **trait references** require special handling since Rendezvous cannot generate them automatically.
+
+### How Trait Reference Selection Works
+
+When your functions accept trait reference parameters, you must include at least one trait implementation in your Clarinet project. This can be either a project contract or a requirement.
+
+Here's how Rendezvous handles trait references:
+
+1. **Project Scanning** – Before testing begins, Rendezvous scans your project for functions that use trait references.
+2. **Implementation Discovery** – It searches the contract AST for matching trait implementations and adds them to a selection pool.
+3. **Random Selection** – During test execution, Rendezvous randomly picks an implementation from the pool and uses it as a function argument.
+
+This process allows Rendezvous to create meaningful state transitions and validate your invariants or property-based tests.
+
+### Example
+
+The `example` Clarinet project demonstrates this feature. The [send-tokens](https://github.com/stacks-network/rendezvous/blob/9c02aa7c2571b3795debc657bd433fd9bf7f19eb/example/contracts/send-tokens.clar) contract contains [one public function](https://github.com/stacks-network/rendezvous/blob/9c02aa7c2571b3795debc657bd433fd9bf7f19eb/example/contracts/send-tokens.clar#L3-L7) and [one property-based test](https://github.com/stacks-network/rendezvous/blob/9c02aa7c2571b3795debc657bd433fd9bf7f19eb/example/contracts/send-tokens.tests.clar#L24-L47) that both accept trait references.
+
+To enable testing, the project includes [rendezvous-token](https://github.com/stacks-network/rendezvous/blob/9c02aa7c2571b3795debc657bd433fd9bf7f19eb/example/contracts/rendezvous-token.clar), which implements the required trait.
+
+### Adding More Implementations
+
+You can include multiple eligible trait implementations in your project. Adding more implementations allows Rendezvous to introduce greater randomness during testing and increases behavioral diversity. If a function that accepts a trait implementation parameter is called X times, those calls are distributed across the available implementations. As the number of implementations grows, Rendezvous has more options to choose from on each call, producing a wider range of behaviors — and uncovering edge cases that may be missed when relying on a single implementation.
diff --git a/docs/reference/stacks.js/sbtc.md b/docs/reference/stacks.js/sbtc.md
new file mode 100644
index 0000000000..fd780ee22f
--- /dev/null
+++ b/docs/reference/stacks.js/sbtc.md
@@ -0,0 +1,321 @@
+# sbtc
+
+Build and manage sBTC deposits and withdrawals on Bitcoin and Stacks.
+
+The `sbtc` package provides functions for creating sBTC deposits on Bitcoin and interacting with the sBTC protocol across Bitcoin and Stacks networks.
+
+## Installation
+
+```bash
+npm install sbtc
+```
+
+## Deposit functions
+
+### buildSbtcDepositAddress
+
+`buildSbtcDepositAddress` creates a Bitcoin address for sBTC deposits with embedded metadata.
+
+Signature
+
+```ts
+function buildSbtcDepositAddress(options: DepositAddressOptions): DepositAddress
+```
+
+Parameters
+
+| Name | Type | Required | Description |
+| ------------------ | ---------------- | -------- | ---------------------------------------------- |
+| `stacksAddress` | `string` | Yes | Stacks address to receive sBTC |
+| `signersPublicKey` | `string` | Yes | Aggregated public key of signers |
+| `maxSignerFee` | `number` | No | Maximum fee for signers (default: 80,000 sats) |
+| `reclaimLockTime` | `number` | No | Lock time for reclaim script (default: 6,000) |
+| `network` | `BitcoinNetwork` | No | Bitcoin network to use (default: MAINNET) |
+
+Example
+
+```ts
+import { buildSbtcDepositAddress, SbtcApiClientMainnet } from 'sbtc';
+
+const client = new SbtcApiClientMainnet();
+
+// Build deposit address
+const deposit = buildSbtcDepositAddress({
+ stacksAddress: 'SP3FGQ8Z7JY9BWYZ5WM53E0M9NK7WHJF0691NZ159',
+ signersPublicKey: await client.fetchSignersPublicKey(),
+ maxSignerFee: 80_000, // Fee taken from deposit amount
+ reclaimLockTime: 6_000
+});
+
+// Send BTC to deposit.address using any Bitcoin wallet
+const txid = await wallet.sendTransfer({
+ recipient: deposit.address,
+ amount: 1_000_000 // 0.01 BTC
+});
+
+// Notify signers about the deposit
+await client.notifySbtc({ txid, ...deposit });
+```
+
+### buildSbtcDepositTx
+
+`buildSbtcDepositTx` creates a complete Bitcoin transaction for sBTC deposits.
+
+Signature
+
+```ts
+function buildSbtcDepositTx(options: DepositTxOptions): DepositTransaction
+```
+
+Parameters
+
+| Name | Type | Required | Description |
+| ------------------ | ------------------ | -------- | ---------------------------------------------- |
+| `amountSats` | `number \| bigint` | Yes | Amount to deposit in satoshis |
+| `stacksAddress` | `string` | Yes | Stacks address to receive sBTC |
+| `signersPublicKey` | `string` | Yes | Aggregated public key of signers |
+| `maxSignerFee` | `number` | No | Maximum fee for signers (default: 80,000 sats) |
+| `reclaimLockTime` | `number` | No | Lock time for reclaim (default: 144) |
+| `network` | `BitcoinNetwork` | No | Bitcoin network to use |
+
+Example
+
+```ts
+import { buildSbtcDepositTx, SbtcApiClientMainnet } from 'sbtc';
+
+const client = new SbtcApiClientMainnet();
+
+// Build deposit transaction
+const deposit = buildSbtcDepositTx({
+ amountSats: 100_000,
+ stacksAddress: 'SP3FGQ8Z7JY9BWYZ5WM53E0M9NK7WHJF0691NZ159',
+ signersPublicKey: await client.fetchSignersPublicKey()
+});
+
+// Sign transaction
+deposit.transaction.sign(privateKey);
+deposit.transaction.finalize();
+
+// Broadcast and notify
+const txid = await client.broadcastTx(deposit.transaction);
+await client.notifySbtc(deposit);
+```
+
+### sbtcDepositHelper
+
+`sbtcDepositHelper` creates a fully-formed deposit transaction from UTXOs.
+
+Signature
+
+```ts
+function sbtcDepositHelper(options: DepositHelperOptions): Promise
+```
+
+Parameters
+
+| Name | Type | Required | Description |
+| ---------------------- | ------------------ | -------- | ------------------------------------ |
+| `amountSats` | `number \| bigint` | Yes | Amount to deposit in satoshis |
+| `stacksAddress` | `string` | Yes | Stacks address to receive sBTC |
+| `signersPublicKey` | `string` | Yes | Aggregated public key of signers |
+| `feeRate` | `number` | Yes | Fee rate in sat/vbyte |
+| `utxos` | `UtxoWithTx[]` | Yes | UTXOs to fund the transaction |
+| `bitcoinChangeAddress` | `string` | Yes | Address for change output |
+| `reclaimPublicKey` | `string` | No | Public key for reclaiming deposits |
+| `reclaimLockTime` | `number` | No | Lock time for reclaim (default: 144) |
+| `maxSignerFee` | `number` | No | Maximum signer fee (default: 80,000) |
+| `network` | `BitcoinNetwork` | No | Bitcoin network (default: MAINNET) |
+
+Example
+
+```ts
+import { sbtcDepositHelper, SbtcApiClientMainnet } from 'sbtc';
+
+const client = new SbtcApiClientMainnet();
+const btcAddress = 'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4';
+
+// Create complete deposit transaction
+const deposit = await sbtcDepositHelper({
+ amountSats: 1_000_000,
+ stacksAddress: 'SP3FGQ8Z7JY9BWYZ5WM53E0M9NK7WHJF0691NZ159',
+ signersPublicKey: await client.fetchSignersPublicKey(),
+ feeRate: await client.fetchFeeRate('medium'),
+ utxos: await client.fetchUtxos(btcAddress),
+ bitcoinChangeAddress: btcAddress
+});
+
+// Sign and broadcast
+deposit.transaction.sign(privateKey);
+deposit.transaction.finalize();
+
+const txid = await client.broadcastTx(deposit.transaction);
+await client.notifySbtc(deposit);
+```
+
+## API clients
+
+### SbtcApiClientMainnet
+
+`SbtcApiClientMainnet` provides mainnet API access for sBTC operations.
+
+```ts
+import { SbtcApiClientMainnet } from 'sbtc';
+
+const client = new SbtcApiClientMainnet();
+```
+
+### SbtcApiClientTestnet
+
+`SbtcApiClientTestnet` provides testnet API access for sBTC operations.
+
+```ts
+import { SbtcApiClientTestnet } from 'sbtc';
+
+const client = new SbtcApiClientTestnet();
+```
+
+### SbtcApiClientDevenv
+
+`SbtcApiClientDevenv` provides local development API access.
+
+```ts
+import { SbtcApiClientDevenv } from 'sbtc';
+
+const client = new SbtcApiClientDevenv();
+```
+
+## Client methods
+
+### fetchSignersPublicKey
+
+`fetchSignersPublicKey` retrieves the aggregated public key of sBTC signers.
+
+```ts
+const publicKey = await client.fetchSignersPublicKey();
+// '02abc123...' (32-byte hex string)
+```
+
+### fetchSignersAddress
+
+`fetchSignersAddress` retrieves the Bitcoin address of sBTC signers.
+
+```ts
+const address = await client.fetchSignersAddress();
+// 'bc1p...' (p2tr address)
+```
+
+### fetchFeeRate
+
+`fetchFeeRate` retrieves current Bitcoin network fee rates.
+
+```ts
+const feeRate = await client.fetchFeeRate('medium');
+// 15 (sat/vbyte)
+
+// Also supports 'low' and 'high'
+const lowFee = await client.fetchFeeRate('low');
+const highFee = await client.fetchFeeRate('high');
+```
+
+### fetchUtxos
+
+`fetchUtxos` retrieves unspent transaction outputs for a Bitcoin address.
+
+```ts
+const utxos = await client.fetchUtxos('bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4');
+// Array of UTXOs with transaction data
+```
+
+### broadcastTx
+
+`broadcastTx` broadcasts a Bitcoin transaction to the network.
+
+```ts
+const txid = await client.broadcastTx(transaction);
+// '0x1234abcd...'
+```
+
+### notifySbtc
+
+`notifySbtc` notifies the sBTC API about a deposit transaction.
+
+```ts
+const response = await client.notifySbtc({
+ txid,
+ stacksAddress,
+ reclaimScript,
+ depositScript
+});
+// { status: 200, statusMessage: 'OK' }
+```
+
+### fetchSbtcBalance
+
+`fetchSbtcBalance` retrieves the sBTC balance for a Stacks address.
+
+```ts
+const balance = await client.fetchSbtcBalance('SP3FGQ8Z7JY9BWYZ5WM53E0M9NK7WHJF0691NZ159');
+// 1000000n (in micro-sBTC)
+```
+
+## Configuration
+
+### Client configuration options
+
+| Name | Type | Description |
+| -------------- | -------- | ------------------------- |
+| `sbtcContract` | `string` | sBTC contract address |
+| `sbtcApiUrl` | `string` | sBTC API (Emily) base URL |
+| `btcApiUrl` | `string` | Bitcoin API base URL |
+| `stxApiUrl` | `string` | Stacks API base URL |
+
+### Custom client configuration
+
+```ts
+import { SbtcApiClient } from 'sbtc';
+
+const client = new SbtcApiClient({
+ sbtcContract: 'SP000000000000000000002Q6VF78.sbtc',
+ sbtcApiUrl: 'https://api.sbtc.tech',
+ btcApiUrl: 'https://mempool.space/api',
+ stxApiUrl: 'https://api.mainnet.hiro.so'
+});
+```
+
+## Complete deposit example
+
+```ts
+import { sbtcDepositHelper, SbtcApiClientMainnet } from 'sbtc';
+
+async function depositBtcForSbtc() {
+ const client = new SbtcApiClientMainnet();
+ const btcAddress = 'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4';
+ const stxAddress = 'SP3FGQ8Z7JY9BWYZ5WM53E0M9NK7WHJF0691NZ159';
+
+ // 1. Create deposit transaction
+ const deposit = await sbtcDepositHelper({
+ amountSats: 100_000,
+ stacksAddress: stxAddress,
+ signersPublicKey: await client.fetchSignersPublicKey(),
+ feeRate: await client.fetchFeeRate('medium'),
+ utxos: await client.fetchUtxos(btcAddress),
+ bitcoinChangeAddress: btcAddress
+ });
+
+ // 2. Sign transaction
+ deposit.transaction.sign(privateKey);
+ deposit.transaction.finalize();
+
+ // 3. Broadcast to Bitcoin network
+ const txid = await client.broadcastTx(deposit.transaction);
+ console.log('Bitcoin transaction:', txid);
+
+ // 4. Notify sBTC signers
+ await client.notifySbtc(deposit);
+ console.log('Deposit submitted successfully');
+
+ // 5. Check sBTC balance (after confirmation)
+ const balance = await client.fetchSbtcBalance(stxAddress);
+ console.log('sBTC balance:', balance);
+}
+```
diff --git a/docs/reference/stacks.js/stacks-connect.md b/docs/reference/stacks.js/stacks-connect.md
new file mode 100644
index 0000000000..c6f9d23a70
--- /dev/null
+++ b/docs/reference/stacks.js/stacks-connect.md
@@ -0,0 +1,354 @@
+# @stacks/connect
+
+The `@stacks/connect` package provides a simple interface for connecting web applications to Stacks wallets, enabling user authentication, transaction signing, and message signing capabilities.
+
+## Installation
+
+{% code title="Install with npm" %}
+```bash
+npm install @stacks/connect
+```
+{% endcode %}
+
+## Connection functions
+
+### connect
+
+`connect` initiates a wallet connection and stores user addresses in local storage.
+
+Signature:
+
+```ts
+function connect(options?: ConnectOptions): Promise
+```
+
+Parameters
+
+| Name | Type | Required | Description |
+| --------- | ---------------- | -------- | ------------------------------------ |
+| `options` | `ConnectOptions` | No | Configuration options for connection |
+
+Examples
+
+Basic connection
+
+```ts
+import { connect } from '@stacks/connect';
+
+const response = await connect();
+// Response contains user addresses stored in local storage
+```
+
+Connection with options
+
+```ts
+const response = await connect({
+ forceWalletSelect: true,
+ approvedProviderIds: ['LeatherProvider', 'xverse']
+});
+```
+
+### isConnected
+
+`isConnected` checks if a wallet is currently connected.
+
+```ts
+import { isConnected } from '@stacks/connect';
+
+if (isConnected()) {
+ console.log('Wallet is connected');
+}
+```
+
+### disconnect
+
+`disconnect` clears the connection state and local storage.
+
+```ts
+import { disconnect } from '@stacks/connect';
+
+disconnect(); // Clears wallet connection
+```
+
+### getLocalStorage
+
+`getLocalStorage` retrieves stored connection data.
+
+```ts
+import { getLocalStorage } from '@stacks/connect';
+
+const data = getLocalStorage();
+// {
+// "addresses": {
+// "stx": [{ "address": "SP2MF04VAGYHGAZWGTEDW5VYCPDWWSY08Z1QFNDSN" }],
+// "btc": [{ "address": "bc1pp3ha248m0mnaevhp0txfxj5xaxmy03h0j7zuj2upg34mt7s7e32q7mdfae" }]
+// }
+// }
+```
+
+## Request method
+
+### request
+
+`request` is the primary method for interacting with connected wallets.
+
+Signature:
+
+```ts
+function request(
+ options: RequestOptions | undefined,
+ method: T,
+ params?: MethodParams[T]
+): Promise