From 4de949fe18d0bddcd2f88dff689dc9cebd04e652 Mon Sep 17 00:00:00 2001 From: Matt Moyer Date: Wed, 17 Feb 2021 17:02:57 -0600 Subject: [PATCH 01/11] Rework docs sidebar to have some nesting. Signed-off-by: Matt Moyer --- site/config.yaml | 14 -------------- site/content/docs/_index.md | 4 ++++ site/content/docs/architecture.md | 4 ++++ .../docs/concierge-and-supervisor-demo.md | 4 ++++ site/content/docs/concierge-only-demo.md | 5 +++++ site/content/docs/demo.md | 5 +++++ site/content/docs/install.md | 4 ++++ site/content/docs/scope.md | 4 ++++ ...css_8967e03afb92eb0cac064520bf021ba2.content | 2 +- .../pinniped/assets/scss/_components.scss | 5 +++++ .../pinniped/layouts/partials/docs-sidebar.html | 17 +++++++++++++---- 11 files changed, 49 insertions(+), 19 deletions(-) diff --git a/site/config.yaml b/site/config.yaml index 963c79fa..3e9754d5 100644 --- a/site/config.yaml +++ b/site/config.yaml @@ -22,17 +22,3 @@ markup: noClasses: false style: monokailight tabWidth: 4 -menu: - docs: - - name: Overview - url: /docs/ - weight: 100 - - name: Install - url: /docs/install/ - weight: 110 - - name: Architecture - url: /docs/architecture/ - - name: Demo - url: /docs/demo/ - - name: Scope - url: /docs/scope/ diff --git a/site/content/docs/_index.md b/site/content/docs/_index.md index faa092cb..4eef0121 100644 --- a/site/content/docs/_index.md +++ b/site/content/docs/_index.md @@ -2,6 +2,10 @@ title: "Pinniped Documentation" cascade: layout: docs +menu: + docs: + name: Overview + weight: 1 --- ![Pinniped Logo](/docs/img/pinniped_logo.svg) diff --git a/site/content/docs/architecture.md b/site/content/docs/architecture.md index 77a94278..e6c8acd5 100644 --- a/site/content/docs/architecture.md +++ b/site/content/docs/architecture.md @@ -2,6 +2,10 @@ title: "Pinniped Architecture" cascade: layout: docs +menu: + docs: + name: Architecture + weight: 100 --- # Architecture diff --git a/site/content/docs/concierge-and-supervisor-demo.md b/site/content/docs/concierge-and-supervisor-demo.md index 0274c409..ff38d188 100644 --- a/site/content/docs/concierge-and-supervisor-demo.md +++ b/site/content/docs/concierge-and-supervisor-demo.md @@ -2,6 +2,10 @@ title: "Pinniped Concierge and Supervisor Demo" cascade: layout: docs +menu: + docs: + name: Concierge with Supervisor + parent: demo --- # Trying Pinniped Supervisor and Concierge diff --git a/site/content/docs/concierge-only-demo.md b/site/content/docs/concierge-only-demo.md index 8ecfa94a..deecfb0f 100644 --- a/site/content/docs/concierge-only-demo.md +++ b/site/content/docs/concierge-only-demo.md @@ -2,6 +2,11 @@ title: "Pinniped Concierge Only Demo" cascade: layout: docs +menu: + docs: + name: Concierge with Webhook + parent: demo + weight: 100 --- # Trying Pinniped Concierge diff --git a/site/content/docs/demo.md b/site/content/docs/demo.md index 0e4be526..1134f014 100644 --- a/site/content/docs/demo.md +++ b/site/content/docs/demo.md @@ -2,6 +2,11 @@ title: "Pinniped Demo" cascade: layout: docs +menu: + docs: + name: Demo + identifier: demo + weight: 40 --- # Trying Pinniped diff --git a/site/content/docs/install.md b/site/content/docs/install.md index 91b9a0e6..4fffc9ef 100644 --- a/site/content/docs/install.md +++ b/site/content/docs/install.md @@ -2,6 +2,10 @@ title: "Installing Pinniped" cascade: layout: docs +menu: + docs: + name: Install + weight: 10 --- # Installing Pinniped diff --git a/site/content/docs/scope.md b/site/content/docs/scope.md index 75bcaa19..09cedc2c 100644 --- a/site/content/docs/scope.md +++ b/site/content/docs/scope.md @@ -2,6 +2,10 @@ title: "Pinniped Scope" cascade: layout: docs +menu: + docs: + name: Scope + weight: 200 --- diff --git a/site/resources/_gen/assets/scss/scss/site.scss_8967e03afb92eb0cac064520bf021ba2.content b/site/resources/_gen/assets/scss/scss/site.scss_8967e03afb92eb0cac064520bf021ba2.content index 1ce27817..96023260 100644 --- a/site/resources/_gen/assets/scss/scss/site.scss_8967e03afb92eb0cac064520bf021ba2.content +++ b/site/resources/_gen/assets/scss/scss/site.scss_8967e03afb92eb0cac064520bf021ba2.content @@ -1,3 +1,3 @@ -body{font-family:"Metropolis-Light",Helvetica,sans-serif;margin:0px;line-height:1.25}.wrapper{max-width:980px;margin:0px auto;padding:20px}@media only screen and (max-width: 767px){.wrapper{max-width:100%}}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0}.clearfix:after{clear:both}h1,h2,h3,h4,h5,h6{font-weight:300}h1{font-size:36px}h2{font-size:28px}h3{font-size:22px}h4{font-size:18px}li{list-style-type:none;display:inline;padding-right:25px;font-size:14px;line-height:1.7em}li:last-of-type{padding-right:0px}p{line-height:1.7em;font-weight:300;font-size:16px;color:#333}a{font-size:16px;text-decoration:none;color:#0095D3;font-family:"Metropolis-Medium",Helvetica,sans-serif}button{background-color:unset;border:none}.button{color:#0095D3;font-size:12px;font-weight:600;background-color:#fff;border-radius:3px;padding:14px 10px;min-width:200px;text-transform:uppercase;border:1px solid #fff}.button.secondary{background-color:#0091DA;color:#fff}.button.tertiary{border:1px solid #0095D3}.buttons{margin-top:40px}.buttons .button:first-of-type{margin-right:30px}@media only screen and (max-width: 767px){.buttons .button:first-of-type{margin:0px 0px 20px 0px}}.strong{font-family:"Metropolis-Medium",Helvetica,sans-serif}.bg-grey{background-color:#F2F2F2}.grid.three{display:grid;grid-template-columns:1fr 1fr 1fr;row-gap:20px;column-gap:20px}@media only screen and (max-width: 767px){.grid.three{grid-template-columns:1fr}}.grid.two{display:grid;grid-template-columns:1fr 1fr}@media only screen and (max-width: 767px){.grid.two{grid-template-columns:1fr}}@font-face{font-family:"Metropolis-Bold";src:url("/fonts/Metropolis-Bold.eot");src:url("/fonts/Metropolis-Bold.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Bold.woff2") format("woff2"),url("/fonts/Metropolis-Bold.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-BoldItalic";src:url("/fonts/Metropolis-BoldItalic.eot");src:url("/fonts/Metropolis-BoldItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-BoldItalic.woff2") format("woff2"),url("/fonts/Metropolis-BoldItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Light";src:url("/fonts/Metropolis-Light.eot");src:url("/fonts/Metropolis-Light.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Light.woff2") format("woff2"),url("/fonts/Metropolis-Light.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-LightItalic";src:url("/fonts/Metropolis-LightItalic.eot");src:url("/fonts/Metropolis-LightItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-LightItalic.woff2") format("woff2"),url("/fonts/Metropolis-LightItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Regular";src:url("/fonts/Metropolis-Regular.eot");src:url("/fonts/Metropolis-Regular.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Regular.woff2") format("woff2"),url("/fonts/Metropolis-Regular.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-RegularItalic";src:url("/fonts/Metropolis-RegularItalic.eot");src:url("/fonts/Metropolis-RegularItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-RegularItalic.woff2") format("woff2"),url("/fonts/Metropolis-RegularItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Medium";src:url("/fonts/Metropolis-Medium.eot");src:url("/fonts/Metropolis-Medium.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Medium.woff2") format("woff2"),url("/fonts/Metropolis-Medium.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-MediumItalic";src:url("/fonts/Metropolis-MediumItalic.eot");src:url("/fonts/Metropolis-MediumItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-MediumItalic.woff2") format("woff2"),url("/fonts/Metropolis-MediumItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-SemiBold";src:url("/fonts/Metropolis-SemiBold.eot");src:url("/fonts/Metropolis-SemiBold.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-SemiBold.woff2") format("woff2"),url("/fonts/Metropolis-SemiBold.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-SemiBoldItalic";src:url("/fonts/Metropolis-SemiBoldItalic.eot");src:url("/fonts/Metropolis-SemiBoldItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-SemiBoldItalic.woff2") format("woff2"),url("/fonts/Metropolis-SemiBoldItalic.woff") format("woff");font-weight:normal;font-style:normal}header .wrapper{padding:10px 20px}header .desktop-links{float:right;margin:15px 0px 0px 0px;padding-left:0px}header a{color:#333;font-family:"Metropolis-Light",Helvetica,sans-serif}header a.active{font-family:"Metropolis-Medium",Helvetica,sans-serif}header li img{vertical-align:bottom;margin-right:10px}header .mobile{display:none}@media only screen and (min-width: 768px) and (max-width: 1279px){header .desktop-links li{padding-right:10px}}@media only screen and (max-width: 767px){header{position:relative}header .expanded-icon{display:none;padding:11px 3px 0px 0px}header .collapsed-icon{padding-top:12px}header .mobile-menu-visible .mobile{display:block}header .mobile-menu-visible .mobile .collapsed-icon{display:none}header .mobile-menu-visible .mobile .expanded-icon{display:block}header .desktop-links{display:none}header .mobile{display:block}header button{float:right}header button:focus{outline:none}header ul{padding-left:0px}header ul li{display:block;margin:20px 0px}header .mobile-menu{position:absolute;background-color:#fff;width:100%;top:70px;left:0px;padding-bottom:20px;display:none}header .mobile-menu .header-links{margin:0px 20px}header .mobile-menu .social{margin:0px 20px;padding-top:20px}header .mobile-menu .social img{vertical-align:middle;padding-right:10px}header .mobile-menu .social a{font-size:14px;padding-right:35px}header .mobile-menu .social a:last-of-type{padding-right:0px}}body{font-family:"Metropolis-Light",Helvetica,sans-serif;margin:0px;line-height:1.25}.wrapper{max-width:980px;margin:0px auto;padding:20px}@media only screen and (max-width: 767px){.wrapper{max-width:100%}}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0}.clearfix:after{clear:both}h1,h2,h3,h4,h5,h6{font-weight:300}h1{font-size:36px}h2{font-size:28px}h3{font-size:22px}h4{font-size:18px}li{list-style-type:none;display:inline;padding-right:25px;font-size:14px;line-height:1.7em}li:last-of-type{padding-right:0px}p{line-height:1.7em;font-weight:300;font-size:16px;color:#333}a{font-size:16px;text-decoration:none;color:#0095D3;font-family:"Metropolis-Medium",Helvetica,sans-serif}button{background-color:unset;border:none}.button{color:#0095D3;font-size:12px;font-weight:600;background-color:#fff;border-radius:3px;padding:14px 10px;min-width:200px;text-transform:uppercase;border:1px solid #fff}.button.secondary{background-color:#0091DA;color:#fff}.button.tertiary{border:1px solid #0095D3}.buttons{margin-top:40px}.buttons .button:first-of-type{margin-right:30px}@media only screen and (max-width: 767px){.buttons .button:first-of-type{margin:0px 0px 20px 0px}}.strong{font-family:"Metropolis-Medium",Helvetica,sans-serif}.bg-grey{background-color:#F2F2F2}.grid.three{display:grid;grid-template-columns:1fr 1fr 1fr;row-gap:20px;column-gap:20px}@media only screen and (max-width: 767px){.grid.three{grid-template-columns:1fr}}.grid.two{display:grid;grid-template-columns:1fr 1fr}@media only screen and (max-width: 767px){.grid.two{grid-template-columns:1fr}}@font-face{font-family:"Metropolis-Bold";src:url("/fonts/Metropolis-Bold.eot");src:url("/fonts/Metropolis-Bold.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Bold.woff2") format("woff2"),url("/fonts/Metropolis-Bold.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-BoldItalic";src:url("/fonts/Metropolis-BoldItalic.eot");src:url("/fonts/Metropolis-BoldItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-BoldItalic.woff2") format("woff2"),url("/fonts/Metropolis-BoldItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Light";src:url("/fonts/Metropolis-Light.eot");src:url("/fonts/Metropolis-Light.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Light.woff2") format("woff2"),url("/fonts/Metropolis-Light.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-LightItalic";src:url("/fonts/Metropolis-LightItalic.eot");src:url("/fonts/Metropolis-LightItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-LightItalic.woff2") format("woff2"),url("/fonts/Metropolis-LightItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Regular";src:url("/fonts/Metropolis-Regular.eot");src:url("/fonts/Metropolis-Regular.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Regular.woff2") format("woff2"),url("/fonts/Metropolis-Regular.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-RegularItalic";src:url("/fonts/Metropolis-RegularItalic.eot");src:url("/fonts/Metropolis-RegularItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-RegularItalic.woff2") format("woff2"),url("/fonts/Metropolis-RegularItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Medium";src:url("/fonts/Metropolis-Medium.eot");src:url("/fonts/Metropolis-Medium.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Medium.woff2") format("woff2"),url("/fonts/Metropolis-Medium.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-MediumItalic";src:url("/fonts/Metropolis-MediumItalic.eot");src:url("/fonts/Metropolis-MediumItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-MediumItalic.woff2") format("woff2"),url("/fonts/Metropolis-MediumItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-SemiBold";src:url("/fonts/Metropolis-SemiBold.eot");src:url("/fonts/Metropolis-SemiBold.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-SemiBold.woff2") format("woff2"),url("/fonts/Metropolis-SemiBold.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-SemiBoldItalic";src:url("/fonts/Metropolis-SemiBoldItalic.eot");src:url("/fonts/Metropolis-SemiBoldItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-SemiBoldItalic.woff2") format("woff2"),url("/fonts/Metropolis-SemiBoldItalic.woff") format("woff");font-weight:normal;font-style:normal}footer .left-links{padding:0px;float:left}footer .left-links li img{vertical-align:bottom;margin-right:10px}footer .left-links li a{color:#333;font-weight:300;font-size:12px;font-family:"Metropolis-Light",Helvetica,sans-serif}footer .right-links{float:right}footer .right-links p{margin:0px}footer .right-links .copywrite{font-size:12px;padding-right:10px}footer .right-links .copywrite a{font-size:12px;color:#333;font-family:"Metropolis-Light",Helvetica,sans-serif}footer .right-links a{vertical-align:middle}@media only screen and (max-width: 767px){footer .left-links{width:100%;float:none}footer .left-links li{display:block;width:33%;float:left;padding-right:0px}footer .right-links{width:100%;padding-top:20px}footer .right-links .image{display:none}}body{font-family:"Metropolis-Light",Helvetica,sans-serif;margin:0px;line-height:1.25}.wrapper{max-width:980px;margin:0px auto;padding:20px}@media only screen and (max-width: 767px){.wrapper{max-width:100%}}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0}.clearfix:after{clear:both}h1,h2,h3,h4,h5,h6{font-weight:300}h1{font-size:36px}h2{font-size:28px}h3{font-size:22px}h4{font-size:18px}li{list-style-type:none;display:inline;padding-right:25px;font-size:14px;line-height:1.7em}li:last-of-type{padding-right:0px}p{line-height:1.7em;font-weight:300;font-size:16px;color:#333}a{font-size:16px;text-decoration:none;color:#0095D3;font-family:"Metropolis-Medium",Helvetica,sans-serif}button{background-color:unset;border:none}.button{color:#0095D3;font-size:12px;font-weight:600;background-color:#fff;border-radius:3px;padding:14px 10px;min-width:200px;text-transform:uppercase;border:1px solid #fff}.button.secondary{background-color:#0091DA;color:#fff}.button.tertiary{border:1px solid #0095D3}.buttons{margin-top:40px}.buttons .button:first-of-type{margin-right:30px}@media only screen and (max-width: 767px){.buttons .button:first-of-type{margin:0px 0px 20px 0px}}.strong{font-family:"Metropolis-Medium",Helvetica,sans-serif}.bg-grey{background-color:#F2F2F2}.grid.three{display:grid;grid-template-columns:1fr 1fr 1fr;row-gap:20px;column-gap:20px}@media only screen and (max-width: 767px){.grid.three{grid-template-columns:1fr}}.grid.two{display:grid;grid-template-columns:1fr 1fr}@media only screen and (max-width: 767px){.grid.two{grid-template-columns:1fr}}@font-face{font-family:"Metropolis-Bold";src:url("/fonts/Metropolis-Bold.eot");src:url("/fonts/Metropolis-Bold.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Bold.woff2") format("woff2"),url("/fonts/Metropolis-Bold.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-BoldItalic";src:url("/fonts/Metropolis-BoldItalic.eot");src:url("/fonts/Metropolis-BoldItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-BoldItalic.woff2") format("woff2"),url("/fonts/Metropolis-BoldItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Light";src:url("/fonts/Metropolis-Light.eot");src:url("/fonts/Metropolis-Light.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Light.woff2") format("woff2"),url("/fonts/Metropolis-Light.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-LightItalic";src:url("/fonts/Metropolis-LightItalic.eot");src:url("/fonts/Metropolis-LightItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-LightItalic.woff2") format("woff2"),url("/fonts/Metropolis-LightItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Regular";src:url("/fonts/Metropolis-Regular.eot");src:url("/fonts/Metropolis-Regular.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Regular.woff2") format("woff2"),url("/fonts/Metropolis-Regular.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-RegularItalic";src:url("/fonts/Metropolis-RegularItalic.eot");src:url("/fonts/Metropolis-RegularItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-RegularItalic.woff2") format("woff2"),url("/fonts/Metropolis-RegularItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Medium";src:url("/fonts/Metropolis-Medium.eot");src:url("/fonts/Metropolis-Medium.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Medium.woff2") format("woff2"),url("/fonts/Metropolis-Medium.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-MediumItalic";src:url("/fonts/Metropolis-MediumItalic.eot");src:url("/fonts/Metropolis-MediumItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-MediumItalic.woff2") format("woff2"),url("/fonts/Metropolis-MediumItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-SemiBold";src:url("/fonts/Metropolis-SemiBold.eot");src:url("/fonts/Metropolis-SemiBold.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-SemiBold.woff2") format("woff2"),url("/fonts/Metropolis-SemiBold.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-SemiBoldItalic";src:url("/fonts/Metropolis-SemiBoldItalic.eot");src:url("/fonts/Metropolis-SemiBoldItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-SemiBoldItalic.woff2") format("woff2"),url("/fonts/Metropolis-SemiBoldItalic.woff") format("woff");font-weight:normal;font-style:normal}.hero{background-color:#0091DA;color:#fff}.hero .text-block{max-width:550px;padding:0px 0px 10px 0px}.hero .text-block p{margin-bottom:20px;font-size:18px;color:#fff}.hero h2{font-size:36px}.hero.homepage{background-image:url(/img/hero-image.png);background-position:center center;background-repeat:no-repeat;background-size:cover;padding-bottom:80px}@media only screen and (max-width: 767px){.hero .text-block{max-width:unset;margin-right:0px}.hero .button{display:block;text-align:center}.hero.homepage{background-image:none}}.grid-container{margin-top:-80px}.grid-container .grid.three{padding-bottom:20px}.grid-container .grid.three .card{position:relative;padding:30px 20px;background-color:#fff;text-align:center;box-shadow:0px 2px 10px rgba(0,0,0,0.2)}.grid-container .grid.three .card h3{color:#333;font-size:22px}.grid-container .grid.three .card p{color:#333}.introduction .grid.two{column-gap:140px;padding:35px 20px}.introduction .grid.two p{margin:0px;font-size:16px}.introduction .grid.two p.strong{color:#333}@media only screen and (max-width: 767px){.introduction{padding:0px 20px}.introduction .col:first-of-type{padding-bottom:50px}}.use-cases .grid{grid-template-columns:220px 1fr;margin-bottom:30px;grid-template-areas:"image text"}.use-cases .grid .image{background-color:#0091DA;text-align:center;display:flex;align-items:center;justify-content:center;grid-area:image}.use-cases .grid .image img{justify-self:center}.use-cases .grid .text{border:1px solid #F2F2F2;padding:30px;grid-area:text}.use-cases .grid .text a.button{display:block;max-width:138px;text-align:center;padding:5px 10px;min-width:unset}.use-cases .grid.image-right{grid-template-columns:1fr 220px;grid-template-areas:"text image"}@media only screen and (max-width: 767px){.use-cases .grid.image-right{grid-template-columns:1fr;grid-template-areas:"image" "text"}}@media only screen and (max-width: 767px){.use-cases .grid{grid-template-columns:1fr;grid-template-rows:minmax(160px, 1fr);grid-template-areas:"image" "text"}}.use-cases h2{color:#111}.use-cases p.strong{color:#1B3951;font-size:16px}.team{background-color:#1D428A}.team h2,.team h3,.team p{color:#fff}.team p{font-size:16px}.team a{color:#fff;font-weight:300;text-decoration:underline}.team .grid.three{row-gap:40px;margin:40px 0px}.team .bio{display:grid;grid-template-columns:120px 1fr;column-gap:20px}.team .bio .info{align-self:center}.team .bio .info p{margin:0px}.team .bio .info p.name{font-size:16px;font-family:"Metropolis-Medium",Helvetica,sans-serif}.team .bio .info p.position{font-size:14px}.hero.subpage{background-image:url(/img/blog-hero-image.png);background-position:center center;background-repeat:no-repeat;background-size:cover;padding-bottom:140px}.experimental .grid.three .col{padding:0px}.experimental .icon{background-color:#0091DA;padding:25px;min-height:95px;display:flex;align-items:center;justify-content:center}.experimental .content{padding:25px}.experimental .content .example{background-color:#F2F2F2}.blog{padding-bottom:50px}.blog .col{border:1px solid #F2F2F2}.blog .col img{width:100%}.blog .col .content{padding:0px 20px}.blog.landing{background-color:#fff;margin-top:-90px}.blog.landing h3 a{font-size:16px}.blog.landing .pagination{margin:30px auto 50px auto}.blog.landing .pagination ul{padding:0px;text-align:center}.blog.landing .pagination ul li{padding:0px}.blog.landing .pagination ul li a{padding:5px 10px}.blog.landing .pagination ul li a.active{background-color:#F2F2F2;border-radius:50%}.blog.landing .pagination ul li.left-arrow{margin-right:15px}.blog.landing .pagination ul li.right-arrow{margin-left:15px}.blog .blog-post{background-color:#fff;margin:-110px 0px 0px -30px;padding:30px 90px 30px 30px}.blog .blog-post .author{color:#0095D3;margin:0px}.blog .blog-post .date{color:#111;margin:0px;font-weight:600}.blog .blog-post .header,.blog .blog-post h4{color:#111;font-weight:600}.blog .blog-post a{font-size:16px}.blog .blog-post ul{list-style-type:disc;padding-left:20px}.blog .blog-post ul li:first-child{margin-top:10px}.blog .blog-post ul li{list-style-type:unset;display:list-item;margin-bottom:10px;font-size:14px;color:#333;line-height:1.6em;list-style-image:url(/img/arrow.svg)}.blog .blog-post ol li:first-child{margin-top:10px}.blog .blog-post ol li{list-style-type:decimal;display:list-item;margin-bottom:10px;font-size:16px;color:#333}.blog .blog-post code{background-color:#fff;color:#333;border:2px solid #EFEFEF;padding:2px 8px}.blog .blog-post code .c1{color:#0095D3;font-style:italic}.blog .blog-post code .se{color:#ff0000}.blog .blog-post pre{white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word}.blog .blog-post pre code{display:block;border:15px solid #EFEFEF;padding:15px;margin-bottom:30px}.blog .blog-post img{max-width:100%}.blog .blog-post strong{font-family:"Metropolis-Medium",Helvetica,sans-serif}.getting-started{background-color:#F2F2F2;color:#111}.getting-started p{color:#111;font-size:16px}.getting-started .left-side{width:50%;float:left}.getting-started .right-side{width:25%;float:right}.getting-started h2{font-size:30px;margin-bottom:0px}.getting-started a{display:block;max-width:138px;text-align:center;padding:10px;min-width:unset}.getting-started .button{margin-top:50px;border:1px solid #0095D3}@media only screen and (max-width: 767px){.getting-started .wrapper{padding-bottom:40px}.getting-started .left-side{width:100%;float:none}.getting-started .right-side{width:100%;float:none}.getting-started .button{display:block;text-align:center;max-width:unset;margin-top:20px}}.community{background-color:#fff;margin-top:-90px;padding:30px 30px 50px 30px}.community .grid .col{border:1px solid #F2F2F2}.community .grid .col .icon{display:flex;align-items:center;justify-content:center;min-height:140px}.community .grid .col .content{padding:0px 20px 20px 20px;text-align:center}.community .grid .col .content h3{margin-top:0px}.docs{background-color:#fff;margin-top:-90px;padding:30px 30px 50px 30px}.docs .side-nav{width:25%;float:left}.docs .side-nav ul{padding-left:0px;margin-bottom:35px}.docs .side-nav ul li{display:list-item;margin-bottom:15px}.docs .side-nav ul li a{color:#333;font-size:14px}.docs .side-nav ul li a.active{color:#0095D3}.docs .side-nav ul li.heading{color:#111;font-size:14px}.docs .docs-content{width:75%;float:right}.docs .docs-content a{font-size:14px}.docs .docs-content ul{list-style-type:disc;padding-left:20px}.docs .docs-content ul li:first-child{margin-top:10px}.docs .docs-content ul li{list-style-type:unset;display:list-item;margin-bottom:10px;font-size:16px;color:#333;line-height:1.6em;list-style-image:url(/img/arrow.svg)}.docs .docs-content ol li:first-child{margin-top:10px}.docs .docs-content ol li{list-style-type:decimal;display:list-item;margin-bottom:10px;font-size:16px;color:#333}.docs .docs-content code{background-color:#fff;color:#333;border:2px solid #EFEFEF;padding:2px 8px}.docs .docs-content code .c1{color:#0095D3;font-style:italic}.docs .docs-content code .se{color:#ff0000}.docs .docs-content pre{white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word}.docs .docs-content pre code{display:block;border:15px solid #EFEFEF;padding:15px;margin-bottom:30px}.docs .docs-content img{max-width:100%}.chroma{color:#272822;background-color:#fafafa}.chroma .err{color:#960050;background-color:#1e0010}.chroma .lntd{vertical-align:top;padding:0;margin:0;border:0}.chroma .lntable{border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block}.chroma .hl{display:block;width:100%;background-color:#ffffcc}.chroma .lnt{margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f}.chroma .ln{margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f}.chroma .k{color:#00a8c8}.chroma .kc{color:#00a8c8}.chroma .kd{color:#00a8c8}.chroma .kn{color:#f92672}.chroma .kp{color:#00a8c8}.chroma .kr{color:#00a8c8}.chroma .kt{color:#00a8c8}.chroma .n{color:#111111}.chroma .na{color:#75af00}.chroma .nb{color:#111111}.chroma .bp{color:#111111}.chroma .nc{color:#75af00}.chroma .no{color:#00a8c8}.chroma .nd{color:#75af00}.chroma .ni{color:#111111}.chroma .ne{color:#75af00}.chroma .nf{color:#75af00}.chroma .fm{color:#111111}.chroma .nl{color:#111111}.chroma .nn{color:#111111}.chroma .nx{color:#75af00}.chroma .py{color:#111111}.chroma .nt{color:#f92672}.chroma .nv{color:#111111}.chroma .vc{color:#111111}.chroma .vg{color:#111111}.chroma .vi{color:#111111}.chroma .vm{color:#111111}.chroma .l{color:#ae81ff}.chroma .ld{color:#d88200}.chroma .s{color:#d88200}.chroma .sa{color:#d88200}.chroma .sb{color:#d88200}.chroma .sc{color:#d88200}.chroma .dl{color:#d88200}.chroma .sd{color:#d88200}.chroma .s2{color:#d88200}.chroma .se{color:#8045ff}.chroma .sh{color:#d88200}.chroma .si{color:#d88200}.chroma .sx{color:#d88200}.chroma .sr{color:#d88200}.chroma .s1{color:#d88200}.chroma .ss{color:#d88200}.chroma .m{color:#ae81ff}.chroma .mb{color:#ae81ff}.chroma .mf{color:#ae81ff}.chroma .mh{color:#ae81ff}.chroma .mi{color:#ae81ff}.chroma .il{color:#ae81ff}.chroma .mo{color:#ae81ff}.chroma .o{color:#f92672}.chroma .ow{color:#f92672}.chroma .p{color:#111111}.chroma .c{color:#75715e}.chroma .ch{color:#75715e}.chroma .cm{color:#75715e}.chroma .c1{color:#75715e}.chroma .cs{color:#75715e}.chroma .cp{color:#75715e}.chroma .cpf{color:#75715e}.chroma .ge{font-style:italic}.chroma .gs{font-weight:bold} +body{font-family:"Metropolis-Light",Helvetica,sans-serif;margin:0px;line-height:1.25}.wrapper{max-width:980px;margin:0px auto;padding:20px}@media only screen and (max-width: 767px){.wrapper{max-width:100%}}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0}.clearfix:after{clear:both}h1,h2,h3,h4,h5,h6{font-weight:300}h1{font-size:36px}h2{font-size:28px}h3{font-size:22px}h4{font-size:18px}li{list-style-type:none;display:inline;padding-right:25px;font-size:14px;line-height:1.7em}li:last-of-type{padding-right:0px}p{line-height:1.7em;font-weight:300;font-size:16px;color:#333}a{font-size:16px;text-decoration:none;color:#0095D3;font-family:"Metropolis-Medium",Helvetica,sans-serif}button{background-color:unset;border:none}.button{color:#0095D3;font-size:12px;font-weight:600;background-color:#fff;border-radius:3px;padding:14px 10px;min-width:200px;text-transform:uppercase;border:1px solid #fff}.button.secondary{background-color:#0091DA;color:#fff}.button.tertiary{border:1px solid #0095D3}.buttons{margin-top:40px}.buttons .button:first-of-type{margin-right:30px}@media only screen and (max-width: 767px){.buttons .button:first-of-type{margin:0px 0px 20px 0px}}.strong{font-family:"Metropolis-Medium",Helvetica,sans-serif}.bg-grey{background-color:#F2F2F2}.grid.three{display:grid;grid-template-columns:1fr 1fr 1fr;row-gap:20px;column-gap:20px}@media only screen and (max-width: 767px){.grid.three{grid-template-columns:1fr}}.grid.two{display:grid;grid-template-columns:1fr 1fr}@media only screen and (max-width: 767px){.grid.two{grid-template-columns:1fr}}@font-face{font-family:"Metropolis-Bold";src:url("/fonts/Metropolis-Bold.eot");src:url("/fonts/Metropolis-Bold.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Bold.woff2") format("woff2"),url("/fonts/Metropolis-Bold.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-BoldItalic";src:url("/fonts/Metropolis-BoldItalic.eot");src:url("/fonts/Metropolis-BoldItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-BoldItalic.woff2") format("woff2"),url("/fonts/Metropolis-BoldItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Light";src:url("/fonts/Metropolis-Light.eot");src:url("/fonts/Metropolis-Light.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Light.woff2") format("woff2"),url("/fonts/Metropolis-Light.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-LightItalic";src:url("/fonts/Metropolis-LightItalic.eot");src:url("/fonts/Metropolis-LightItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-LightItalic.woff2") format("woff2"),url("/fonts/Metropolis-LightItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Regular";src:url("/fonts/Metropolis-Regular.eot");src:url("/fonts/Metropolis-Regular.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Regular.woff2") format("woff2"),url("/fonts/Metropolis-Regular.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-RegularItalic";src:url("/fonts/Metropolis-RegularItalic.eot");src:url("/fonts/Metropolis-RegularItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-RegularItalic.woff2") format("woff2"),url("/fonts/Metropolis-RegularItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Medium";src:url("/fonts/Metropolis-Medium.eot");src:url("/fonts/Metropolis-Medium.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Medium.woff2") format("woff2"),url("/fonts/Metropolis-Medium.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-MediumItalic";src:url("/fonts/Metropolis-MediumItalic.eot");src:url("/fonts/Metropolis-MediumItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-MediumItalic.woff2") format("woff2"),url("/fonts/Metropolis-MediumItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-SemiBold";src:url("/fonts/Metropolis-SemiBold.eot");src:url("/fonts/Metropolis-SemiBold.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-SemiBold.woff2") format("woff2"),url("/fonts/Metropolis-SemiBold.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-SemiBoldItalic";src:url("/fonts/Metropolis-SemiBoldItalic.eot");src:url("/fonts/Metropolis-SemiBoldItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-SemiBoldItalic.woff2") format("woff2"),url("/fonts/Metropolis-SemiBoldItalic.woff") format("woff");font-weight:normal;font-style:normal}header .wrapper{padding:10px 20px}header .desktop-links{float:right;margin:15px 0px 0px 0px;padding-left:0px}header a{color:#333;font-family:"Metropolis-Light",Helvetica,sans-serif}header a.active{font-family:"Metropolis-Medium",Helvetica,sans-serif}header li img{vertical-align:bottom;margin-right:10px}header .mobile{display:none}@media only screen and (min-width: 768px) and (max-width: 1279px){header .desktop-links li{padding-right:10px}}@media only screen and (max-width: 767px){header{position:relative}header .expanded-icon{display:none;padding:11px 3px 0px 0px}header .collapsed-icon{padding-top:12px}header .mobile-menu-visible .mobile{display:block}header .mobile-menu-visible .mobile .collapsed-icon{display:none}header .mobile-menu-visible .mobile .expanded-icon{display:block}header .desktop-links{display:none}header .mobile{display:block}header button{float:right}header button:focus{outline:none}header ul{padding-left:0px}header ul li{display:block;margin:20px 0px}header .mobile-menu{position:absolute;background-color:#fff;width:100%;top:70px;left:0px;padding-bottom:20px;display:none}header .mobile-menu .header-links{margin:0px 20px}header .mobile-menu .social{margin:0px 20px;padding-top:20px}header .mobile-menu .social img{vertical-align:middle;padding-right:10px}header .mobile-menu .social a{font-size:14px;padding-right:35px}header .mobile-menu .social a:last-of-type{padding-right:0px}}body{font-family:"Metropolis-Light",Helvetica,sans-serif;margin:0px;line-height:1.25}.wrapper{max-width:980px;margin:0px auto;padding:20px}@media only screen and (max-width: 767px){.wrapper{max-width:100%}}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0}.clearfix:after{clear:both}h1,h2,h3,h4,h5,h6{font-weight:300}h1{font-size:36px}h2{font-size:28px}h3{font-size:22px}h4{font-size:18px}li{list-style-type:none;display:inline;padding-right:25px;font-size:14px;line-height:1.7em}li:last-of-type{padding-right:0px}p{line-height:1.7em;font-weight:300;font-size:16px;color:#333}a{font-size:16px;text-decoration:none;color:#0095D3;font-family:"Metropolis-Medium",Helvetica,sans-serif}button{background-color:unset;border:none}.button{color:#0095D3;font-size:12px;font-weight:600;background-color:#fff;border-radius:3px;padding:14px 10px;min-width:200px;text-transform:uppercase;border:1px solid #fff}.button.secondary{background-color:#0091DA;color:#fff}.button.tertiary{border:1px solid #0095D3}.buttons{margin-top:40px}.buttons .button:first-of-type{margin-right:30px}@media only screen and (max-width: 767px){.buttons .button:first-of-type{margin:0px 0px 20px 0px}}.strong{font-family:"Metropolis-Medium",Helvetica,sans-serif}.bg-grey{background-color:#F2F2F2}.grid.three{display:grid;grid-template-columns:1fr 1fr 1fr;row-gap:20px;column-gap:20px}@media only screen and (max-width: 767px){.grid.three{grid-template-columns:1fr}}.grid.two{display:grid;grid-template-columns:1fr 1fr}@media only screen and (max-width: 767px){.grid.two{grid-template-columns:1fr}}@font-face{font-family:"Metropolis-Bold";src:url("/fonts/Metropolis-Bold.eot");src:url("/fonts/Metropolis-Bold.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Bold.woff2") format("woff2"),url("/fonts/Metropolis-Bold.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-BoldItalic";src:url("/fonts/Metropolis-BoldItalic.eot");src:url("/fonts/Metropolis-BoldItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-BoldItalic.woff2") format("woff2"),url("/fonts/Metropolis-BoldItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Light";src:url("/fonts/Metropolis-Light.eot");src:url("/fonts/Metropolis-Light.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Light.woff2") format("woff2"),url("/fonts/Metropolis-Light.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-LightItalic";src:url("/fonts/Metropolis-LightItalic.eot");src:url("/fonts/Metropolis-LightItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-LightItalic.woff2") format("woff2"),url("/fonts/Metropolis-LightItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Regular";src:url("/fonts/Metropolis-Regular.eot");src:url("/fonts/Metropolis-Regular.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Regular.woff2") format("woff2"),url("/fonts/Metropolis-Regular.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-RegularItalic";src:url("/fonts/Metropolis-RegularItalic.eot");src:url("/fonts/Metropolis-RegularItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-RegularItalic.woff2") format("woff2"),url("/fonts/Metropolis-RegularItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Medium";src:url("/fonts/Metropolis-Medium.eot");src:url("/fonts/Metropolis-Medium.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Medium.woff2") format("woff2"),url("/fonts/Metropolis-Medium.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-MediumItalic";src:url("/fonts/Metropolis-MediumItalic.eot");src:url("/fonts/Metropolis-MediumItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-MediumItalic.woff2") format("woff2"),url("/fonts/Metropolis-MediumItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-SemiBold";src:url("/fonts/Metropolis-SemiBold.eot");src:url("/fonts/Metropolis-SemiBold.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-SemiBold.woff2") format("woff2"),url("/fonts/Metropolis-SemiBold.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-SemiBoldItalic";src:url("/fonts/Metropolis-SemiBoldItalic.eot");src:url("/fonts/Metropolis-SemiBoldItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-SemiBoldItalic.woff2") format("woff2"),url("/fonts/Metropolis-SemiBoldItalic.woff") format("woff");font-weight:normal;font-style:normal}footer .left-links{padding:0px;float:left}footer .left-links li img{vertical-align:bottom;margin-right:10px}footer .left-links li a{color:#333;font-weight:300;font-size:12px;font-family:"Metropolis-Light",Helvetica,sans-serif}footer .right-links{float:right}footer .right-links p{margin:0px}footer .right-links .copywrite{font-size:12px;padding-right:10px}footer .right-links .copywrite a{font-size:12px;color:#333;font-family:"Metropolis-Light",Helvetica,sans-serif}footer .right-links a{vertical-align:middle}@media only screen and (max-width: 767px){footer .left-links{width:100%;float:none}footer .left-links li{display:block;width:33%;float:left;padding-right:0px}footer .right-links{width:100%;padding-top:20px}footer .right-links .image{display:none}}body{font-family:"Metropolis-Light",Helvetica,sans-serif;margin:0px;line-height:1.25}.wrapper{max-width:980px;margin:0px auto;padding:20px}@media only screen and (max-width: 767px){.wrapper{max-width:100%}}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0}.clearfix:after{clear:both}h1,h2,h3,h4,h5,h6{font-weight:300}h1{font-size:36px}h2{font-size:28px}h3{font-size:22px}h4{font-size:18px}li{list-style-type:none;display:inline;padding-right:25px;font-size:14px;line-height:1.7em}li:last-of-type{padding-right:0px}p{line-height:1.7em;font-weight:300;font-size:16px;color:#333}a{font-size:16px;text-decoration:none;color:#0095D3;font-family:"Metropolis-Medium",Helvetica,sans-serif}button{background-color:unset;border:none}.button{color:#0095D3;font-size:12px;font-weight:600;background-color:#fff;border-radius:3px;padding:14px 10px;min-width:200px;text-transform:uppercase;border:1px solid #fff}.button.secondary{background-color:#0091DA;color:#fff}.button.tertiary{border:1px solid #0095D3}.buttons{margin-top:40px}.buttons .button:first-of-type{margin-right:30px}@media only screen and (max-width: 767px){.buttons .button:first-of-type{margin:0px 0px 20px 0px}}.strong{font-family:"Metropolis-Medium",Helvetica,sans-serif}.bg-grey{background-color:#F2F2F2}.grid.three{display:grid;grid-template-columns:1fr 1fr 1fr;row-gap:20px;column-gap:20px}@media only screen and (max-width: 767px){.grid.three{grid-template-columns:1fr}}.grid.two{display:grid;grid-template-columns:1fr 1fr}@media only screen and (max-width: 767px){.grid.two{grid-template-columns:1fr}}@font-face{font-family:"Metropolis-Bold";src:url("/fonts/Metropolis-Bold.eot");src:url("/fonts/Metropolis-Bold.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Bold.woff2") format("woff2"),url("/fonts/Metropolis-Bold.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-BoldItalic";src:url("/fonts/Metropolis-BoldItalic.eot");src:url("/fonts/Metropolis-BoldItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-BoldItalic.woff2") format("woff2"),url("/fonts/Metropolis-BoldItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Light";src:url("/fonts/Metropolis-Light.eot");src:url("/fonts/Metropolis-Light.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Light.woff2") format("woff2"),url("/fonts/Metropolis-Light.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-LightItalic";src:url("/fonts/Metropolis-LightItalic.eot");src:url("/fonts/Metropolis-LightItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-LightItalic.woff2") format("woff2"),url("/fonts/Metropolis-LightItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Regular";src:url("/fonts/Metropolis-Regular.eot");src:url("/fonts/Metropolis-Regular.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Regular.woff2") format("woff2"),url("/fonts/Metropolis-Regular.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-RegularItalic";src:url("/fonts/Metropolis-RegularItalic.eot");src:url("/fonts/Metropolis-RegularItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-RegularItalic.woff2") format("woff2"),url("/fonts/Metropolis-RegularItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Medium";src:url("/fonts/Metropolis-Medium.eot");src:url("/fonts/Metropolis-Medium.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Medium.woff2") format("woff2"),url("/fonts/Metropolis-Medium.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-MediumItalic";src:url("/fonts/Metropolis-MediumItalic.eot");src:url("/fonts/Metropolis-MediumItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-MediumItalic.woff2") format("woff2"),url("/fonts/Metropolis-MediumItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-SemiBold";src:url("/fonts/Metropolis-SemiBold.eot");src:url("/fonts/Metropolis-SemiBold.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-SemiBold.woff2") format("woff2"),url("/fonts/Metropolis-SemiBold.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-SemiBoldItalic";src:url("/fonts/Metropolis-SemiBoldItalic.eot");src:url("/fonts/Metropolis-SemiBoldItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-SemiBoldItalic.woff2") format("woff2"),url("/fonts/Metropolis-SemiBoldItalic.woff") format("woff");font-weight:normal;font-style:normal}.hero{background-color:#0091DA;color:#fff}.hero .text-block{max-width:550px;padding:0px 0px 10px 0px}.hero .text-block p{margin-bottom:20px;font-size:18px;color:#fff}.hero h2{font-size:36px}.hero.homepage{background-image:url(/img/hero-image.png);background-position:center center;background-repeat:no-repeat;background-size:cover;padding-bottom:80px}@media only screen and (max-width: 767px){.hero .text-block{max-width:unset;margin-right:0px}.hero .button{display:block;text-align:center}.hero.homepage{background-image:none}}.grid-container{margin-top:-80px}.grid-container .grid.three{padding-bottom:20px}.grid-container .grid.three .card{position:relative;padding:30px 20px;background-color:#fff;text-align:center;box-shadow:0px 2px 10px rgba(0,0,0,0.2)}.grid-container .grid.three .card h3{color:#333;font-size:22px}.grid-container .grid.three .card p{color:#333}.introduction .grid.two{column-gap:140px;padding:35px 20px}.introduction .grid.two p{margin:0px;font-size:16px}.introduction .grid.two p.strong{color:#333}@media only screen and (max-width: 767px){.introduction{padding:0px 20px}.introduction .col:first-of-type{padding-bottom:50px}}.use-cases .grid{grid-template-columns:220px 1fr;margin-bottom:30px;grid-template-areas:"image text"}.use-cases .grid .image{background-color:#0091DA;text-align:center;display:flex;align-items:center;justify-content:center;grid-area:image}.use-cases .grid .image img{justify-self:center}.use-cases .grid .text{border:1px solid #F2F2F2;padding:30px;grid-area:text}.use-cases .grid .text a.button{display:block;max-width:138px;text-align:center;padding:5px 10px;min-width:unset}.use-cases .grid.image-right{grid-template-columns:1fr 220px;grid-template-areas:"text image"}@media only screen and (max-width: 767px){.use-cases .grid.image-right{grid-template-columns:1fr;grid-template-areas:"image" "text"}}@media only screen and (max-width: 767px){.use-cases .grid{grid-template-columns:1fr;grid-template-rows:minmax(160px, 1fr);grid-template-areas:"image" "text"}}.use-cases h2{color:#111}.use-cases p.strong{color:#1B3951;font-size:16px}.team{background-color:#1D428A}.team h2,.team h3,.team p{color:#fff}.team p{font-size:16px}.team a{color:#fff;font-weight:300;text-decoration:underline}.team .grid.three{row-gap:40px;margin:40px 0px}.team .bio{display:grid;grid-template-columns:120px 1fr;column-gap:20px}.team .bio .info{align-self:center}.team .bio .info p{margin:0px}.team .bio .info p.name{font-size:16px;font-family:"Metropolis-Medium",Helvetica,sans-serif}.team .bio .info p.position{font-size:14px}.hero.subpage{background-image:url(/img/blog-hero-image.png);background-position:center center;background-repeat:no-repeat;background-size:cover;padding-bottom:140px}.experimental .grid.three .col{padding:0px}.experimental .icon{background-color:#0091DA;padding:25px;min-height:95px;display:flex;align-items:center;justify-content:center}.experimental .content{padding:25px}.experimental .content .example{background-color:#F2F2F2}.blog{padding-bottom:50px}.blog .col{border:1px solid #F2F2F2}.blog .col img{width:100%}.blog .col .content{padding:0px 20px}.blog.landing{background-color:#fff;margin-top:-90px}.blog.landing h3 a{font-size:16px}.blog.landing .pagination{margin:30px auto 50px auto}.blog.landing .pagination ul{padding:0px;text-align:center}.blog.landing .pagination ul li{padding:0px}.blog.landing .pagination ul li a{padding:5px 10px}.blog.landing .pagination ul li a.active{background-color:#F2F2F2;border-radius:50%}.blog.landing .pagination ul li.left-arrow{margin-right:15px}.blog.landing .pagination ul li.right-arrow{margin-left:15px}.blog .blog-post{background-color:#fff;margin:-110px 0px 0px -30px;padding:30px 90px 30px 30px}.blog .blog-post .author{color:#0095D3;margin:0px}.blog .blog-post .date{color:#111;margin:0px;font-weight:600}.blog .blog-post .header,.blog .blog-post h4{color:#111;font-weight:600}.blog .blog-post a{font-size:16px}.blog .blog-post ul{list-style-type:disc;padding-left:20px}.blog .blog-post ul li:first-child{margin-top:10px}.blog .blog-post ul li{list-style-type:unset;display:list-item;margin-bottom:10px;font-size:14px;color:#333;line-height:1.6em;list-style-image:url(/img/arrow.svg)}.blog .blog-post ol li:first-child{margin-top:10px}.blog .blog-post ol li{list-style-type:decimal;display:list-item;margin-bottom:10px;font-size:16px;color:#333}.blog .blog-post code{background-color:#fff;color:#333;border:2px solid #EFEFEF;padding:2px 8px}.blog .blog-post code .c1{color:#0095D3;font-style:italic}.blog .blog-post code .se{color:#ff0000}.blog .blog-post pre{white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word}.blog .blog-post pre code{display:block;border:15px solid #EFEFEF;padding:15px;margin-bottom:30px}.blog .blog-post img{max-width:100%}.blog .blog-post strong{font-family:"Metropolis-Medium",Helvetica,sans-serif}.getting-started{background-color:#F2F2F2;color:#111}.getting-started p{color:#111;font-size:16px}.getting-started .left-side{width:50%;float:left}.getting-started .right-side{width:25%;float:right}.getting-started h2{font-size:30px;margin-bottom:0px}.getting-started a{display:block;max-width:138px;text-align:center;padding:10px;min-width:unset}.getting-started .button{margin-top:50px;border:1px solid #0095D3}@media only screen and (max-width: 767px){.getting-started .wrapper{padding-bottom:40px}.getting-started .left-side{width:100%;float:none}.getting-started .right-side{width:100%;float:none}.getting-started .button{display:block;text-align:center;max-width:unset;margin-top:20px}}.community{background-color:#fff;margin-top:-90px;padding:30px 30px 50px 30px}.community .grid .col{border:1px solid #F2F2F2}.community .grid .col .icon{display:flex;align-items:center;justify-content:center;min-height:140px}.community .grid .col .content{padding:0px 20px 20px 20px;text-align:center}.community .grid .col .content h3{margin-top:0px}.docs{background-color:#fff;margin-top:-90px;padding:30px 30px 50px 30px}.docs .side-nav{width:25%;float:left}.docs .side-nav ul{padding-left:0px;margin-bottom:35px}.docs .side-nav ul ul{padding-left:15px;margin-top:10px;margin-bottom:15px}.docs .side-nav ul li{display:list-item;margin-bottom:15px}.docs .side-nav ul li a{color:#333;font-size:14px}.docs .side-nav ul li a.active{color:#0095D3}.docs .side-nav ul li.heading{color:#111;font-size:14px}.docs .docs-content{width:75%;float:right}.docs .docs-content a{font-size:14px}.docs .docs-content ul{list-style-type:disc;padding-left:20px}.docs .docs-content ul li:first-child{margin-top:10px}.docs .docs-content ul li{list-style-type:unset;display:list-item;margin-bottom:10px;font-size:16px;color:#333;line-height:1.6em;list-style-image:url(/img/arrow.svg)}.docs .docs-content ol li:first-child{margin-top:10px}.docs .docs-content ol li{list-style-type:decimal;display:list-item;margin-bottom:10px;font-size:16px;color:#333}.docs .docs-content code{background-color:#fff;color:#333;border:2px solid #EFEFEF;padding:2px 8px}.docs .docs-content code .c1{color:#0095D3;font-style:italic}.docs .docs-content code .se{color:#ff0000}.docs .docs-content pre{white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word}.docs .docs-content pre code{display:block;border:15px solid #EFEFEF;padding:15px;margin-bottom:30px}.docs .docs-content img{max-width:100%}.chroma{color:#272822;background-color:#fafafa}.chroma .err{color:#960050;background-color:#1e0010}.chroma .lntd{vertical-align:top;padding:0;margin:0;border:0}.chroma .lntable{border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block}.chroma .hl{display:block;width:100%;background-color:#ffffcc}.chroma .lnt{margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f}.chroma .ln{margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f}.chroma .k{color:#00a8c8}.chroma .kc{color:#00a8c8}.chroma .kd{color:#00a8c8}.chroma .kn{color:#f92672}.chroma .kp{color:#00a8c8}.chroma .kr{color:#00a8c8}.chroma .kt{color:#00a8c8}.chroma .n{color:#111111}.chroma .na{color:#75af00}.chroma .nb{color:#111111}.chroma .bp{color:#111111}.chroma .nc{color:#75af00}.chroma .no{color:#00a8c8}.chroma .nd{color:#75af00}.chroma .ni{color:#111111}.chroma .ne{color:#75af00}.chroma .nf{color:#75af00}.chroma .fm{color:#111111}.chroma .nl{color:#111111}.chroma .nn{color:#111111}.chroma .nx{color:#75af00}.chroma .py{color:#111111}.chroma .nt{color:#f92672}.chroma .nv{color:#111111}.chroma .vc{color:#111111}.chroma .vg{color:#111111}.chroma .vi{color:#111111}.chroma .vm{color:#111111}.chroma .l{color:#ae81ff}.chroma .ld{color:#d88200}.chroma .s{color:#d88200}.chroma .sa{color:#d88200}.chroma .sb{color:#d88200}.chroma .sc{color:#d88200}.chroma .dl{color:#d88200}.chroma .sd{color:#d88200}.chroma .s2{color:#d88200}.chroma .se{color:#8045ff}.chroma .sh{color:#d88200}.chroma .si{color:#d88200}.chroma .sx{color:#d88200}.chroma .sr{color:#d88200}.chroma .s1{color:#d88200}.chroma .ss{color:#d88200}.chroma .m{color:#ae81ff}.chroma .mb{color:#ae81ff}.chroma .mf{color:#ae81ff}.chroma .mh{color:#ae81ff}.chroma .mi{color:#ae81ff}.chroma .il{color:#ae81ff}.chroma .mo{color:#ae81ff}.chroma .o{color:#f92672}.chroma .ow{color:#f92672}.chroma .p{color:#111111}.chroma .c{color:#75715e}.chroma .ch{color:#75715e}.chroma .cm{color:#75715e}.chroma .c1{color:#75715e}.chroma .cs{color:#75715e}.chroma .cp{color:#75715e}.chroma .cpf{color:#75715e}.chroma .ge{font-style:italic}.chroma .gs{font-weight:bold} /*# sourceMappingURL=style.css.map */ \ No newline at end of file diff --git a/site/themes/pinniped/assets/scss/_components.scss b/site/themes/pinniped/assets/scss/_components.scss index dd301bec..b62de86d 100644 --- a/site/themes/pinniped/assets/scss/_components.scss +++ b/site/themes/pinniped/assets/scss/_components.scss @@ -411,6 +411,11 @@ ul { padding-left: 0px; margin-bottom: 35px; + ul { + padding-left: 15px; + margin-top: 10px; + margin-bottom: 15px; + } li { display: list-item; margin-bottom: 15px; diff --git a/site/themes/pinniped/layouts/partials/docs-sidebar.html b/site/themes/pinniped/layouts/partials/docs-sidebar.html index 41a107b3..cdd79d4b 100644 --- a/site/themes/pinniped/layouts/partials/docs-sidebar.html +++ b/site/themes/pinniped/layouts/partials/docs-sidebar.html @@ -1,8 +1,17 @@
    - {{ $currentPage := . }} - {{ range .Site.Menus.docs }} -
  • {{ .Name }}
  • - {{ end }} + {{- $currentPage := . }} + {{- range .Site.Menus.docs }} +
  • + {{ .Name }} + {{- if .HasChildren }} + + {{- end }} +
  • + {{- end }}
\ No newline at end of file From 3721632de273f7998de39b425935ef6b1ce86cf4 Mon Sep 17 00:00:00 2001 From: Matt Moyer Date: Thu, 18 Feb 2021 10:10:35 -0600 Subject: [PATCH 02/11] Move scope doc out of website to SCOPE.md. This is contributor-focused, so we decided to move it into GitHub only for now. Signed-off-by: Matt Moyer --- CONTRIBUTING.md | 2 +- SCOPE.md | 32 ++++++++++++++++++++++++++++ site/content/docs/scope.md | 43 -------------------------------------- 3 files changed, 33 insertions(+), 44 deletions(-) create mode 100644 SCOPE.md delete mode 100644 site/content/docs/scope.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 20d3e1bf..c00094b4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,7 +8,7 @@ Please see the [Code of Conduct](./CODE_OF_CONDUCT.md). ## Project Scope -Learn about the [scope](https://pinniped.dev/docs/scope/) of the project. +See [SCOPE.md](./SCOPE.md) for some guidelines about what we consider in and out of scope for Pinniped. ## Community Meetings diff --git a/SCOPE.md b/SCOPE.md new file mode 100644 index 00000000..91dff3bd --- /dev/null +++ b/SCOPE.md @@ -0,0 +1,32 @@ +# Project Scope + +The Pinniped project is guided by the following principles. + +- Pinniped lets you plug any external identity providers into Kubernetes. + These integrations follow enterprise-grade security principles. +- Pinniped is easy to install and use on any Kubernetes cluster via distribution-specific integration mechanisms. +- Pinniped uses a declarative configuration via Kubernetes APIs. +- Pinniped provides optimal user experience when authenticating to many clusters at one time. +- Pinniped provides enterprise-grade security posture via secure defaults and revocable or very short-lived credentials. +- Where possible, Pinniped will contribute ideas and code to upstream Kubernetes. + +When contributing to Pinniped, please consider whether your contribution follows +these guiding principles. + +## Out Of Scope + +The following items are out of scope for the Pinniped project. + +- Authorization. +- Standalone identity provider for general use. +- Machine-to-machine (service) identity. +- Running outside of Kubernetes. + +## Roadmap + +See our [open milestones][milestones] and the [`priority/backlog` label][backlog] for an idea about what's next on our roadmap. + +For more details on proposing features and bugs, check out our [contributing](./CONTRIBUTING.md) doc. + +[milestones]: https://github.com/vmware-tanzu/pinniped/milestones +[backlog]: https://github.com/vmware-tanzu/pinniped/labels/priority%2Fbacklog \ No newline at end of file diff --git a/site/content/docs/scope.md b/site/content/docs/scope.md deleted file mode 100644 index 09cedc2c..00000000 --- a/site/content/docs/scope.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -title: "Pinniped Scope" -cascade: - layout: docs -menu: - docs: - name: Scope - weight: 200 ---- - - -# Project Scope - -The Pinniped project is guided by the following principles. -* Pinniped lets you plug any external identity providers into - Kubernetes. These integrations follow enterprise-grade security principles. -* Pinniped is easy to install and use on any Kubernetes cluster via - distribution-specific integration mechanisms. -* Pinniped uses a declarative configuration via Kubernetes APIs. -* Pinniped provides optimal user experience when authenticating to many - clusters at one time. -* Pinniped provides enterprise-grade security posture via secure defaults and - revocable or very short-lived credentials. -* Where possible, Pinniped will contribute ideas and code to upstream - Kubernetes. - -When contributing to Pinniped, please consider whether your contribution follows -these guiding principles. - -## Out Of Scope - -The following items are out of scope for the Pinniped project. -* Authorization. -* Standalone identity provider for general use. -* Machine-to-machine (service) identity. -* Running outside of Kubernetes. - -## Roadmap - -More details coming soon! - -For more details on proposing features and bugs, check out our -[contributing](https://github.com/vmware-tanzu/pinniped/blob/main/CONTRIBUTING.md) doc. From f2db76a0d5789a61926d2a79fb583f8401e6e975 Mon Sep 17 00:00:00 2001 From: Matt Moyer Date: Mon, 22 Feb 2021 09:36:29 -0600 Subject: [PATCH 03/11] Fix typo in multiple-pinnipeds post. Signed-off-by: Matt Moyer --- site/content/posts/multiple-pinnipeds.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/content/posts/multiple-pinnipeds.md b/site/content/posts/multiple-pinnipeds.md index e875db13..5ce0a610 100644 --- a/site/content/posts/multiple-pinnipeds.md +++ b/site/content/posts/multiple-pinnipeds.md @@ -87,7 +87,7 @@ The default behavior of Pinniped remains unchanged, and we made sure to implemen ### Advantages and Disadvantages -With v0.5.0, each instance of Pinniped to be upgraded and operated 100% independently, with no coordination or shared state needed. +With v0.5.0, each instance of Pinniped can be upgraded and operated 100% independently, with no coordination or shared state needed. One remaining constraint is that each instance should be deployed into its own namespace. This ensures that any other standard Kubernetes objects such as Secrets and ConfigMaps referenced by the configuration do not overlap. From 7a1d92a8d4c19db7271ebb1caf805b4630a1ce48 Mon Sep 17 00:00:00 2001 From: Matt Moyer Date: Mon, 22 Feb 2021 17:52:23 -0600 Subject: [PATCH 04/11] Restructure docs into new layout. Signed-off-by: Matt Moyer --- README.md | 14 +- deploy/concierge/README.md | 40 +--- deploy/supervisor/README.md | 185 +----------------- site/content/community/_index.html | 4 +- site/content/docs/_index.md | 58 ++---- site/content/docs/background/_index.md | 13 ++ .../docs/{ => background}/architecture.md | 16 +- site/content/docs/demo.md | 14 -- site/content/docs/howto/_index.md | 14 ++ .../docs/howto/configure-concierge-jwt.md | 142 ++++++++++++++ .../docs/howto/configure-concierge-webhook.md | 116 +++++++++++ .../docs/howto/configure-supervisor.md | 161 +++++++++++++++ site/content/docs/howto/install-cli.md | 55 ++++++ site/content/docs/howto/install-concierge.md | 60 ++++++ site/content/docs/howto/install-supervisor.md | 59 ++++++ site/content/docs/install.md | 25 --- site/content/docs/reference/_index.md | 13 ++ site/content/docs/reference/api.md | 12 ++ site/content/docs/reference/cli.md | 84 ++++++++ .../docs/reference/supported-clusters.md | 29 +++ site/content/docs/tutorials/_index.md | 15 ++ .../concierge-and-supervisor-demo.md | 99 +++++----- .../{ => tutorials}/concierge-only-demo.md | 112 ++++++----- site/netlify.toml | 5 + ...s_8967e03afb92eb0cac064520bf021ba2.content | 2 +- site/themes/pinniped/assets/scss/_base.scss | 7 + .../pinniped/assets/scss/_components.scss | 31 ++- .../pinniped/layouts/_default/docs.html | 4 +- .../layouts/shortcodes/buttonicon.html | 1 + .../layouts/shortcodes/buttonlink.html | 2 + .../layouts/shortcodes/dangernote.html | 4 + .../pinniped/layouts/shortcodes/docsmenu.html | 15 ++ .../static/img/alert-circle-outline.svg | 1 + site/themes/pinniped/static/img/download.png | Bin 0 -> 354 bytes 34 files changed, 973 insertions(+), 439 deletions(-) create mode 100644 site/content/docs/background/_index.md rename site/content/docs/{ => background}/architecture.md (96%) delete mode 100644 site/content/docs/demo.md create mode 100644 site/content/docs/howto/_index.md create mode 100644 site/content/docs/howto/configure-concierge-jwt.md create mode 100644 site/content/docs/howto/configure-concierge-webhook.md create mode 100644 site/content/docs/howto/configure-supervisor.md create mode 100644 site/content/docs/howto/install-cli.md create mode 100644 site/content/docs/howto/install-concierge.md create mode 100644 site/content/docs/howto/install-supervisor.md delete mode 100644 site/content/docs/install.md create mode 100644 site/content/docs/reference/_index.md create mode 100644 site/content/docs/reference/api.md create mode 100644 site/content/docs/reference/cli.md create mode 100644 site/content/docs/reference/supported-clusters.md create mode 100644 site/content/docs/tutorials/_index.md rename site/content/docs/{ => tutorials}/concierge-and-supervisor-demo.md (72%) rename site/content/docs/{ => tutorials}/concierge-only-demo.md (62%) create mode 100644 site/themes/pinniped/layouts/shortcodes/buttonicon.html create mode 100644 site/themes/pinniped/layouts/shortcodes/buttonlink.html create mode 100644 site/themes/pinniped/layouts/shortcodes/dangernote.html create mode 100644 site/themes/pinniped/layouts/shortcodes/docsmenu.html create mode 100644 site/themes/pinniped/static/img/alert-circle-outline.svg create mode 100644 site/themes/pinniped/static/img/download.png diff --git a/README.md b/README.md index b4c27431..196569d0 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ install procedure across all types and origins of Kubernetes clusters, declarative configuration via Kubernetes APIs, enterprise-grade integrations with IDPs, and distribution-specific integration strategies. -### Example Use Cases +### Example use cases * Your team uses a large enterprise IDP, and has many clusters that they manage. Pinniped provides: @@ -39,17 +39,15 @@ The Pinniped Concierge can be configured to hook into the Pinniped Supervisor's federated credentials, or it can authenticate users directly via external IDP credentials. -To learn more, see [architecture](https://pinniped.dev/docs/architecture/). +To learn more, see [architecture](https://pinniped.dev/docs/background/architecture/). -Pinniped Architecture Sketch - -## Trying Pinniped +## Getting started with Pinniped Care to kick the tires? It's easy to [install and try Pinniped](https://pinniped.dev/docs/demo/). -## Community Meetings +## Community meetings -Pinniped is better because of our contributors and maintainers. It is because of you that we can bring great software to the community. Please join us during our online community meetings, occuring every first and third Thursday of the month at 9AM PT / 12PM PT. Use [this Zoom Link](https://vmware.zoom.us/j/93798188973?pwd=T3pIMWxReEQvcWljNm1admRoZTFSZz09) to attend and add any agenda items you wish to discuss to [the notes document](https://hackmd.io/rd_kVJhjQfOvfAWzK8A3tQ?view). Join our [Google Group](https://groups.google.com/u/1/g/project-pinniped) to receive invites to this meeting. +Pinniped is better because of our contributors and maintainers. It is because of you that we can bring great software to the community. Please join us during our online community meetings, occurring every first and third Thursday of the month at 9 AM PT / 12 PM PT. Use [this Zoom Link](https://vmware.zoom.us/j/93798188973?pwd=T3pIMWxReEQvcWljNm1admRoZTFSZz09) to attend and add any agenda items you wish to discuss to [the notes document](https://hackmd.io/rd_kVJhjQfOvfAWzK8A3tQ?view). Join our [Google Group](https://groups.google.com/u/1/g/project-pinniped) to receive invites to this meeting. If the meeting day falls on a US holiday, please consider that occurrence of the meeting to be canceled. @@ -61,7 +59,7 @@ Got a question, comment, or idea? Please don't hesitate to reach out via the Git Contributions are welcome. Before contributing, please see the [contributing guide](CONTRIBUTING.md). -## Reporting Security Vulnerabilities +## Reporting security vulnerabilities Please follow the procedure described in [SECURITY.md](SECURITY.md). diff --git a/deploy/concierge/README.md b/deploy/concierge/README.md index bd65216f..39ce06b2 100644 --- a/deploy/concierge/README.md +++ b/deploy/concierge/README.md @@ -1,39 +1,3 @@ -# Deploying +# Pinniped Concierge Deployment -## Connecting Pinniped to an Identity Provider - -If you would like to try Pinniped, but you don't have a compatible identity provider, -you can use Pinniped's test identity provider. -See [deploy/local-user-authenticator/README.md](../../deploy/local-user-authenticator/README.md) -for details. - -## Installing the Latest Version with Default Options - -```bash -kubectl apply -f https://get.pinniped.dev/latest/install-pinniped-concierge.yaml -``` - -## Installing a Specific Version with Default Options - -Choose your preferred [release](https://github.com/vmware-tanzu/pinniped/releases) version number -and use it to replace the version number in the URL below. - -```bash -# Replace v0.4.1 with your preferred version in the URL below -kubectl apply -f https://get.pinniped.dev/v0.4.1/install-pinniped-concierge.yaml -``` - -## Installing with Custom Options - -Creating your own deployment YAML file requires `ytt` from [Carvel](https://carvel.dev/) to template the YAML files -in the `deploy/concierge` directory. -Either [install `ytt`](https://get-ytt.io/) or use the [container image from Dockerhub](https://hub.docker.com/r/k14s/image/tags). - -1. `git clone` this repo and `git checkout` the release version tag of the release that you would like to deploy. -1. The configuration options are in [deploy/concierge/values.yml](values.yaml). - Fill in the values in that file, or override those values using additional `ytt` command-line options in - the command below. Use the release version tag as the `image_tag` value. -2. In a terminal, cd to this `deploy/concierge` directory -3. To generate the final YAML files, run `ytt --file .` -4. Deploy the generated YAML using your preferred deployment tool, such as `kubectl` or [`kapp`](https://get-kapp.io/). - For example: `ytt --file . | kapp deploy --yes --app pinniped --diff-changes --file -` +See [the how-to guide for details](https://pinniped.dev/docs/howto/install-concierge/). diff --git a/deploy/supervisor/README.md b/deploy/supervisor/README.md index 4df8f81c..04d84b81 100644 --- a/deploy/supervisor/README.md +++ b/deploy/supervisor/README.md @@ -1,184 +1,3 @@ -# Deploying the Pinniped Supervisor +# Pinniped Supervisor Deployment -## What is the Pinniped Supervisor? - -The Pinniped Supervisor app is a component of the Pinniped OIDC and Cluster Federation solutions. -It can be deployed when those features are needed. - -## Installing the Latest Version with Default Options - -```bash -kubectl apply -f https://get.pinniped.dev/latest/install-pinniped-supervisor.yaml -``` - -## Installing a Specific Version with Default Options - -Choose your preferred [release](https://github.com/vmware-tanzu/pinniped/releases) version number -and use it to replace the version number in the URL below. - -```bash -# Replace v0.4.1 with your preferred version in the URL below -kubectl apply -f https://get.pinniped.dev/v0.4.1/install-pinniped-supervisor.yaml -``` - -## Installing with Custom Options - -Creating your own deployment YAML file requires `ytt` from [Carvel](https://carvel.dev/) to template the YAML files -in the `deploy/supervisor` directory. -Either [install `ytt`](https://get-ytt.io/) or use the [container image from Dockerhub](https://hub.docker.com/r/k14s/image/tags). - -1. `git clone` this repo and `git checkout` the release version tag of the release that you would like to deploy. -1. The configuration options are in [deploy/supervisor/values.yml](values.yaml). - Fill in the values in that file, or override those values using additional `ytt` command-line options in - the command below. Use the release version tag as the `image_tag` value. -2. In a terminal, cd to this `deploy/supervisor` directory -3. To generate the final YAML files, run `ytt --file .` -4. Deploy the generated YAML using your preferred deployment tool, such as `kubectl` or [`kapp`](https://get-kapp.io/). - For example: `ytt --file . | kapp deploy --yes --app pinniped-supervisor --diff-changes --file -` - -## Configuring After Installing - -### Exposing the Supervisor App as a Service - -The Supervisor app's endpoints should be exposed as HTTPS endpoints with proper TLS certificates signed by a -Certificate Authority which will be trusted by your user's web browsers. Because there are -many ways to expose TLS services from a Kubernetes cluster, the Supervisor app leaves this up to the user. -The most common ways are: - -1. Define an [`Ingress` resource](https://kubernetes.io/docs/concepts/services-networking/ingress/) with TLS certificates. - In this case, the ingress will terminate TLS. Typically, the ingress will then talk plain HTTP to its backend, - which would be a NodePort or LoadBalancer Service in front of the HTTP port 8080 of the Supervisor pods. - - The required configuration of the Ingress is specific to your cluster's Ingress Controller, so please refer to the - documentation from your Kubernetes provider. If you are using a cluster from a cloud provider, then you'll probably - want to start with that provider's documentation. For example, if your cluster is a Google GKE cluster, refer to - the [GKE documentation for Ingress](https://cloud.google.com/kubernetes-engine/docs/concepts/ingress). - Otherwise, the Kubernetes documentation provides a list of popular - [Ingress Controllers](https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/), including - [Contour](https://projectcontour.io/) and many others. - -1. Or, define a [TCP LoadBalancer Service](https://kubernetes.io/docs/concepts/services-networking/service/#loadbalancer) - which is a layer 4 load balancer and does not terminate TLS. In this case, the Supervisor app will need to be - configured with TLS certificates and will terminate the TLS connection itself (see the section about FederationDomain - below). The LoadBalancer Service should be configured to use the HTTPS port 443 of the Supervisor pods as its `targetPort`. - - *Warning:* Do not expose the Supervisor's port 8080 to the public. It would not be secure for the OIDC protocol - to use HTTP, because the user's secret OIDC tokens would be transmitted across the network without encryption. - -1. Or, expose the Supervisor app using a Kubernetes service mesh technology, e.g. [Istio](https://istio.io/). - Please see the documentation for your service mesh. Generally, the setup would be similar to the description - above for defining an ingress, expect the service mesh would probably provide both the ingress with TLS termination - and the service. - -For either of the first two options mentioned above, if you installed using `ytt` then you can use -the related `service_*` options from [deploy/supervisor/values.yml](values.yaml) to create a Service. -If you installed using `install-supervisor.yaml` then you can create -the Service separately after installing the Supervisor app. There is no `Ingress` included in the `ytt` templates, -so if you choose to use an Ingress then you'll need to create that separately after installing the Supervisor app. - -#### Example: Using a LoadBalancer Service - -This is an example of creating a LoadBalancer Service to expose port 8443 of the Supervisor app outside the cluster. - -```yaml -apiVersion: v1 -kind: Service -metadata: - name: pinniped-supervisor-loadbalancer - # Assuming that this is the namespace where the supervisor was installed. This is the default in install-supervisor.yaml. - namespace: pinniped-supervisor -spec: - type: LoadBalancer - selector: - # Assuming that this is how the supervisor pods are labeled. This is the default in install-supervisor.yaml. - app: pinniped-supervisor - ports: - - protocol: TCP - port: 443 - targetPort: 8443 -``` - -#### Example: Using a NodePort Service - -A NodePort Service exposes the app as a port on the nodes of the cluster. - -This is convenient for use with kind clusters, because kind can -[expose node ports as localhost ports on the host machine](https://kind.sigs.k8s.io/docs/user/configuration/#extra-port-mappings) -without requiring an Ingress, although -[kind also supports several Ingress Controllers](https://kind.sigs.k8s.io/docs/user/ingress). - -A NodePort Service could also be used behind an Ingress which is terminating TLS. - -For example: - -```yaml -apiVersion: v1 -kind: Service -metadata: - name: pinniped-supervisor-nodeport - # Assuming that this is the namespace where the supervisor was installed. This is the default in install-supervisor.yaml. - namespace: pinniped-supervisor -spec: - type: NodePort - selector: - # Assuming that this is how the supervisor pods are labeled. This is the default in install-supervisor.yaml. - app: pinniped-supervisor - ports: - - protocol: TCP - port: 80 - targetPort: 8080 - nodePort: 31234 # This is the port that you would forward to the kind host. Or omit this key for a random port. -``` - -### Configuring the Supervisor to Act as an OIDC Provider - -The Supervisor can be configured as an OIDC provider by creating `FederationDomain` resources -in the same namespace where the Supervisor app was installed. For example: - -```yaml -apiVersion: config.supervisor.pinniped.dev/v1alpha1 -kind: FederationDomain -metadata: - name: my-provider - # Assuming that this is the namespace where the supervisor was installed. This is the default in install-supervisor.yaml. - namespace: pinniped-supervisor -spec: - # The hostname would typically match the DNS name of the public ingress or load balancer for the cluster. - # Any path can be specified, which allows a single hostname to have multiple different issuers. The path is optional. - issuer: https://my-issuer.example.com/any/path - - # Optionally configure the name of a Secret in the same namespace, of type `kubernetes.io/tls`, - # which contains the TLS serving certificate for the HTTPS endpoints served by this OIDC Provider. - tls: - secretName: my-tls-cert-secret -``` - -#### Configuring TLS for the Supervisor OIDC Endpoints - -If you have terminated TLS outside the app, for example using an Ingress with TLS certificates, then you do not need to -configure TLS certificates on the FederationDomain. - -If you are using a LoadBalancer Service to expose the Supervisor app outside your cluster, then you will -also need to configure the Supervisor app to terminate TLS. There are two places to configure TLS certificates: - -1. Each `FederationDomain` can be configured with TLS certificates, using the `spec.tls.secretName` field. - -1. The default TLS certificate for all OIDC providers can be configured by creating a Secret called -`pinniped-supervisor-default-tls-certificate` in the same namespace in which the Supervisor was installed. - -The default TLS certificate will be used for all OIDC providers which did not declare a `spec.tls.secretName`. -Also, the `spec.tls.secretName` will be ignored for incoming requests to the OIDC endpoints -that use an IP address as the host, so those requests will always present the default TLS certificates -to the client. When the request includes the hostname, and that hostname matches the hostname of an `Issuer`, -then the TLS certificate defined by the `spec.tls.secretName` will be used. If that issuer did not -define `spec.tls.secretName` then the default TLS certificate will be used. If neither exists, -then the client will get a TLS error because the server will not present any TLS certificate. - -It is recommended that you have a DNS entry for your load balancer or Ingress, and that you configure the -OIDC provider's `Issuer` using that DNS hostname, and that the TLS certificate for that provider also -covers that same hostname. - -You can create the certificate Secrets however you like, for example you could use [cert-manager](https://cert-manager.io/) -or `kubectl create secret tls`. -Keep in mind that your users will load some of these endpoints in their web browsers, so the TLS certificates -should be signed by a Certificate Authority that will be trusted by their browsers. +See [the how-to guide for details](https://pinniped.dev/docs/howto/install-supervisor/). diff --git a/site/content/community/_index.html b/site/content/community/_index.html index 5726b819..d4c9aa60 100644 --- a/site/content/community/_index.html +++ b/site/content/community/_index.html @@ -16,8 +16,8 @@ layout: section }}">
-

}}">Check out Github

-

Head over to our git repo and check out the discussions and issues sections.

+

}}">Check out GitHub

+

Head over to our GitHub repo and check out the discussions and issues.

diff --git a/site/content/docs/_index.md b/site/content/docs/_index.md index 4eef0121..704c0d52 100644 --- a/site/content/docs/_index.md +++ b/site/content/docs/_index.md @@ -1,5 +1,4 @@ --- -title: "Pinniped Documentation" cascade: layout: docs menu: @@ -8,58 +7,25 @@ menu: weight: 1 --- -![Pinniped Logo](/docs/img/pinniped_logo.svg) +# Getting started with Pinniped -## Overview +Pinniped is an authentication service for Kubernetes clusters. +As a Kubernetes cluster administrator or user, you can learn how Pinniped works, see how to use it on your clusters, and dive into internals of Pinniped's APIs and architecture. -Pinniped provides identity services to Kubernetes. +Have a question, comment, or idea? Please reach out via [GitHub Discussions](https://github.com/vmware-tanzu/pinniped/discussions) or [join the Pinniped community meetings]({{< ref "/community" >}}). -Pinniped allows cluster administrators to easily plug in external identity -providers (IDPs) into Kubernetes clusters. This is achieved via a uniform -install procedure across all types and origins of Kubernetes clusters, -declarative configuration via Kubernetes APIs, enterprise-grade integrations -with IDPs, and distribution-specific integration strategies. +## Tutorials -### Example Use Cases +{{< docsmenu "tutorials" >}} -* Your team uses a large enterprise IDP, and has many clusters that they - manage. Pinniped provides: - * Seamless and robust integration with the IDP - * Easy installation across clusters of any type and origin - * A simplified login flow across all clusters -* Your team shares a single cluster. Pinniped provides: - * Simple configuration to integrate an IDP - * Individual, revocable identities +## How-to guides -### Architecture +{{< docsmenu "howtos" >}} -Pinniped offers credential exchange to enable a user to exchange an external IDP -credential for a short-lived, cluster-specific credential. Pinniped supports various -IDP types and implements different integration strategies for various Kubernetes -distributions to make authentication possible. +## Reference -To learn more, see [docs/architecture](/docs/architecture). +{{< docsmenu "reference" >}} -Pinniped Architecture Sketch +## Background -## Trying Pinniped - -Care to kick the tires? It's easy to [install and try Pinniped](/docs/demo). - -## Discussion - -Got a question, comment, or idea? Please don't hesitate to reach out via the GitHub [Discussions](https://github.com/vmware-tanzu/pinniped/discussions) tab at the top of this page. - -## Contributions - -Contributions are welcome. Before contributing, please see the [contributing guide](https://github.com/vmware-tanzu/pinniped/blob/main/CONTRIBUTING.md). - -## Reporting Security Vulnerabilities - -Please follow the procedure described in [SECURITY.md](https://github.com/vmware-tanzu/pinniped/blob/main/SECURITY.md). - -## License - -Pinniped is open source and licensed under Apache License Version 2.0. See [LICENSE](https://github.com/vmware-tanzu/pinniped/blob/main/LICENSE). - -Copyright 2020 the Pinniped contributors. All Rights Reserved. +{{< docsmenu "background" >}} diff --git a/site/content/docs/background/_index.md b/site/content/docs/background/_index.md new file mode 100644 index 00000000..5916ea0e --- /dev/null +++ b/site/content/docs/background/_index.md @@ -0,0 +1,13 @@ +--- +cascade: + layout: docs +menu: + docs: + name: Background + identifier: background + weight: 80 +--- + +# Pinniped background + +{{< docsmenu "background" >}} diff --git a/site/content/docs/architecture.md b/site/content/docs/background/architecture.md similarity index 96% rename from site/content/docs/architecture.md rename to site/content/docs/background/architecture.md index e6c8acd5..5e6469a2 100644 --- a/site/content/docs/architecture.md +++ b/site/content/docs/background/architecture.md @@ -1,20 +1,20 @@ --- -title: "Pinniped Architecture" +title: Architecture +description: Dive into the overall design and implementation details of Pinniped. cascade: layout: docs menu: docs: name: Architecture weight: 100 + parent: background --- - -# Architecture - The principal purpose of Pinniped is to allow users to access Kubernetes clusters. Pinniped hopes to enable this access across a wide range of Kubernetes environments with zero configuration. Pinniped is composed of two parts. + 1. The Pinniped Supervisor is an OIDC server which allows users to authenticate with an external identity provider (IDP), and then issues its own federation ID tokens to be passed on to clusters based on the user information from the IDP. @@ -28,14 +28,6 @@ understood by the host Kubernetes cluster. Pinniped supports various authenticator types and OIDC identity providers and implements different integration strategies for various Kubernetes distributions to make authentication possible. -## Supported Kubernetes Cluster Types - -Pinniped supports the following types of Kubernetes clusters: - -- Clusters where the Kube Controller Manager pod is accessible from Pinniped's pods. - -Support for other types of Kubernetes distributions is coming soon. - ## External Identity Provider Integrations The Pinniped Supervisor will federate identity from one or more IDPs. diff --git a/site/content/docs/demo.md b/site/content/docs/demo.md deleted file mode 100644 index 1134f014..00000000 --- a/site/content/docs/demo.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -title: "Pinniped Demo" -cascade: - layout: docs -menu: - docs: - name: Demo - identifier: demo - weight: 40 ---- - -# Trying Pinniped -1. [Concierge with webhook demo](/docs/concierge-only-demo) -1. [Concierge with Supervisor and JWT authenticator demo](/docs/concierge-and-supervisor-demo) diff --git a/site/content/docs/howto/_index.md b/site/content/docs/howto/_index.md new file mode 100644 index 00000000..d53105e6 --- /dev/null +++ b/site/content/docs/howto/_index.md @@ -0,0 +1,14 @@ +--- +title: Pinniped How-To Guides +cascade: + layout: docs +menu: + docs: + name: How-to Guides + identifier: howtos + weight: 50 +--- + +These how-to guides show you how to install and configure the Pinniped command-line tool, Concierge, and Supervisor: + +{{< docsmenu "howtos" >}} diff --git a/site/content/docs/howto/configure-concierge-jwt.md b/site/content/docs/howto/configure-concierge-jwt.md new file mode 100644 index 00000000..36386de4 --- /dev/null +++ b/site/content/docs/howto/configure-concierge-jwt.md @@ -0,0 +1,142 @@ +--- +title: Configure the Pinniped Concierge to validate JWT tokens +description: Set up JSON Web Token (JWT) based token authentication on an individual Kubernetes cluster. +cascade: + layout: docs +menu: + docs: + name: Configure Concierge JWT Authentication + weight: 25 + parent: howtos +--- +The Concierge can validate [JSON Web Tokens (JWTs)](https://tools.ietf.org/html/rfc7519), which are commonly issued by [OpenID Connect (OIDC)](https://openid.net/connect/) identity providers. + +This guide shows you how to use this capability _without_ the Pinniped Supervisor. +This is most useful if you have only a single cluster and want to authenticate to it via an existing OIDC provider. + +If you have multiple clusters, you may want to [install]({{< ref "install-supervisor" >}}) and [configure]({{< ref "configure-supervisor" >}}) the Pinniped Supervisor. + +## Prerequisites + +Before starting, you should have the [command-line tool installed]({{< ref "install-cli" >}}) locally and [Concierge running in your cluster]({{< ref "install-concierge" >}}). + +You should also have some existing OIDC issuer configuration: + +- An OIDC provider that supports [discovery](https://openid.net/specs/openid-connect-discovery-1_0.html) and the `email` scope. +- A public client with callback URI `http://127.0.0.1:12345/callback` and `email` scope. + +## Create a JWTAuthenticator + +Create a JWTAuthenticator describing how to validate tokens from your OIDC issuer: + +```yaml +apiVersion: authentication.concierge.pinniped.dev/v1alpha1 +kind: JWTAuthenticator +metadata: + name: my-jwt-authenticator +spec: + issuer: https://my-issuer.example.com/any/path + audience: my-client-id + claims: + username: email +``` + +If you've saved this into a file `my-jwt-authenticator.yaml`, then install it into your cluster using: + +```sh +kubectl apply -f my-jwt-authenticator.yaml +``` + +## Generate a kubeconfig file + +Generate a kubeconfig file to target the JWTAuthenticator: + +```sh +pinniped get kubeconfig \ + --oidc-client-id my-client-id \ + --oidc-scopes openid,email \ + --oidc-listen-port 12345 \ + > my-cluster.yaml +``` + +This creates a kubeconfig YAML file `my-cluster.yaml` that targets your JWTAuthenticator using `pinniped login oidc` as an [ExecCredential plugin](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#client-go-credential-plugins). + +It should look something like below: + +```yaml +apiVersion: v1 +kind: Config +current-context: pinniped +clusters: +- cluster: + certificate-authority-data: LS0tLS[...] + server: https://my-kubernetes-api-endpoint.example.com:59986 + name: pinniped +contexts: +- context: + cluster: pinniped + user: pinniped + name: pinniped +users: +- name: pinniped + user: + exec: + apiVersion: client.authentication.k8s.io/v1beta1 + command: /usr/local/bin/pinniped + args: + - login + - oidc + - --enable-concierge + - --concierge-api-group-suffix=pinniped.dev + - --concierge-authenticator-name=my-jwt-authenticator + - --concierge-authenticator-type=jwt + - --concierge-endpoint=https://my-kubernetes-api-endpoint.example.com:59986 + - --concierge-ca-bundle-data=LS0tLS[...] + - --issuer=https://my-oidc-issuer.example.com/any/path + - --client-id=my-client-id + - --scopes=offline_access,openid,email + - --listen-port=12345 + - --request-audience=my-client-id +``` + +## Use the kubeconfig file + +Use the kubeconfig with `kubectl` to access your cluster: + +```sh +kubectl --kubeconfig my-cluster.yaml get namespaces +``` + +You should see: + +- The `pinniped login oidc` command is executed automatically by `kubectl`. + +- Pinniped opens your browser window and directs you to login with your identity provider. + +- After you've logged in, you see a page telling you `you have been logged in and may now close this tab`. + +- In your shell, you see your clusters namespaces. + + If instead you get an access denied error, you may need to create a ClusterRoleBinding for the `email` of your OIDC account, for example: + + ```sh + kubectl create clusterrolebinding my-user-admin \ + --clusterrole admin \ + --user my-username@example.com + ``` + +## Other notes + +- Pinniped kubeconfig files do not contain secrets and are safe to share between users. + +- Temporary OIDC session credentials such as ID, access, and refresh tokens are stored in: + - `~/.config/pinniped/sessions.yaml` (macOS/Linux) + - `%USERPROFILE%/.config/pinniped/sessions.yaml` (Windows). + +- If your OIDC provider supports [wildcard port number matching](https://tools.ietf.org/html/draft-ietf-oauth-security-topics-16#section-2.1) for localhost URIs, you can omit the `--oidc-listen-port` flag to use a randomly chosen ephemeral TCP port. + +- The Pinniped command-line tool can only act as a public client with no client secret. + If your provider only supports non-public clients, consider using the Pinniped Supervisor. + +- In general, it is not safe to use the same OIDC client across multiple clusters. + If you need to access multiple clusters, please [install the Pinniped Supervisor]({{< ref "install-supervisor" >}}). \ No newline at end of file diff --git a/site/content/docs/howto/configure-concierge-webhook.md b/site/content/docs/howto/configure-concierge-webhook.md new file mode 100644 index 00000000..ead557fc --- /dev/null +++ b/site/content/docs/howto/configure-concierge-webhook.md @@ -0,0 +1,116 @@ +--- +title: Configure the Pinniped Concierge to validate webhook tokens +description: Set up webhook-based token authentication on an individual Kubernetes cluster. +cascade: + layout: docs +menu: + docs: + name: Configure Concierge Webhook Authentication + weight: 26 + parent: howtos +--- + +The Concierge can validate arbitrary tokens via an external webhook endpoint using the [same validation process as Kubernetes itself](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#webhook-token-authentication). + +## Prerequisites + +Before starting, you should have the [command-line tool installed]({{< ref "install-cli" >}}) locally and [Concierge running in your cluster]({{< ref "install-concierge" >}}). + +You should also have a custom TokenReview webhook endpoint: + +- Your webhook endpoint must handle the `authentication.k8s.io/v1` [TokenReview API](https://kubernetes.io/docs/reference/kubernetes-api/authentication-resources/token-review-v1/#TokenReview). + +- Your webhook must be accessible from the Concierge pod over HTTPS. + +## Create a WebhookAuthenticator + +Create a WebhookAuthenticator describing how to validate tokens using your webhook: + +```yaml +apiVersion: authentication.concierge.pinniped.dev/v1alpha1 +kind: WebhookAuthenticator +metadata: + name: my-webhook-authenticator +spec: + # HTTPS endpoint to be called as a webhook + endpoint: https://my-webhook.example.com/any/path + tls: + # base64-encoded PEM CA bundle (optional) + certificateAuthorityData: "LS0tLS1CRUdJTi[...]" +``` + +If you've saved this into a file `my-webhook-authenticator.yaml`, then install it into your cluster using: + +```sh +kubectl apply -f my-webhook-authenticator.yaml +``` + +## Generate a kubeconfig file + +Generate a kubeconfig file to target the WebhookAuthenticator: + +```sh +pinniped get kubeconfig \ + --static-token-env MY_CLUSTER_ACCESS_TOKEN \ + > my-cluster.yaml +``` + +This creates a kubeconfig YAML file `my-cluster.yaml` that targets your WebhookAuthenticator using `pinniped login static` as an [ExecCredential plugin](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#client-go-credential-plugins). + +It should look something like below: + +```yaml +apiVersion: v1 +kind: Config +current-context: pinniped +clusters: +- cluster: + certificate-authority-data: LS0tLS[...] + server: https://my-kubernetes-api-endpoint.example.com:59986 + name: pinniped +contexts: +- context: + cluster: pinniped + user: pinniped + name: pinniped +users: +- name: pinniped + user: + exec: + apiVersion: client.authentication.k8s.io/v1beta1 + command: /usr/local/bin/pinniped + args: + - login + - oidc + - login + - static + - --enable-concierge + - --concierge-api-group-suffix=pinniped.dev + - --concierge-authenticator-name=my-webhook-authenticator + - --concierge-authenticator-type=webhook + - --concierge-endpoint=https://127.0.0.1:59986 + - --concierge-ca-bundle-data=LS0tLS[...] + - --token-env=MY_CLUSTER_ACCESS_TOKEN +``` + +## Use the kubeconfig file + +Set the `$MY_CLUSTER_ACCESS_TOKEN` environment variable and use the kubeconfig with `kubectl` to access your cluster: + +```sh +MY_CLUSTER_ACCESS_TOKEN=secret-token kubectl --kubeconfig my-cluster.yaml get namespaces +``` + +You should see: + +- The `pinniped login static` command is silently executed automatically by `kubectl`. + +- The command-line tool sends your token to the Concierge which validates it by making a request to your webhook endpoint. + +- In your shell, you see your clusters namespaces. + + If instead you get an access denied error, you may need to create a ClusterRoleBinding for the username/groups returned by your webhook, for example: + + ```sh + kubectl create clusterrolebinding my-user-admin --clusterrole admin --user my-username + ``` diff --git a/site/content/docs/howto/configure-supervisor.md b/site/content/docs/howto/configure-supervisor.md new file mode 100644 index 00000000..a5ddf342 --- /dev/null +++ b/site/content/docs/howto/configure-supervisor.md @@ -0,0 +1,161 @@ +--- +title: Configure the Pinniped Supervisor as an OIDC issuer +description: Set up the Pinniped Supervisor to provide seamless login flows across multiple clusters. +cascade: + layout: docs +menu: + docs: + name: Configure Supervisor + weight: 35 + parent: howtos +--- +The Supervisor is an [OpenID Connect (OIDC)](https://openid.net/connect/) issuer that supports connecting a single "upstream" OIDC identity provider to many "downstream" cluster clients. + +This guide show you how to use this capability to issue [JSON Web Tokens (JWTs)](https://tools.ietf.org/html/rfc7519) that can be validated by the [Pinniped Concierge]({{< ref "configure-concierge-jwt" >}}). + +Before starting, you should have the [command-line tool installed]({{< ref "install-cli" >}}) locally and the Concierge [installed]({{< ref "install-concierge" >}}) in your cluster. + +## Expose the Supervisor app as a service + +The Supervisor app's endpoints should be exposed as HTTPS endpoints with proper TLS certificates signed by a certificate authority (CA) which is trusted by your user's web browsers. + +Because there are many ways to expose TLS services from a Kubernetes cluster, the Supervisor app leaves this up to the user. +The most common ways are: + +1. Define an [`Ingress` resource](https://kubernetes.io/docs/concepts/services-networking/ingress/) with TLS certificates. + In this case, the ingress terminates TLS. Typically, the ingress then talks plain HTTP to its backend, + which would be a NodePort or LoadBalancer Service in front of the HTTP port 8080 of the Supervisor pods. + + The required configuration of the Ingress is specific to your cluster's Ingress Controller, so please refer to the + documentation from your Kubernetes provider. If you are using a cluster from a cloud provider, then you'll probably + want to start with that provider's documentation. For example, if your cluster is a Google GKE cluster, refer to + the [GKE documentation for Ingress](https://cloud.google.com/kubernetes-engine/docs/concepts/ingress). + Otherwise, the Kubernetes documentation provides a list of popular + [Ingress Controllers](https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/), including + [Contour](https://projectcontour.io/) and many others. + +1. Or, define a [TCP LoadBalancer Service](https://kubernetes.io/docs/concepts/services-networking/service/#loadbalancer) + which is a layer 4 load balancer and does not terminate TLS. In this case, the Supervisor app needs to be + configured with TLS certificates and terminates the TLS connection itself (see the section about FederationDomain + below). The LoadBalancer Service should be configured to use the HTTPS port 443 of the Supervisor pods as its `targetPort`. + + *Warning:* do not expose the Supervisor's port 8080 to the public. It would not be secure for the OIDC protocol + to use HTTP, because the user's secret OIDC tokens would be transmitted across the network without encryption. + +1. Or, expose the Supervisor app using a Kubernetes service mesh technology, for example [Istio](https://istio.io/). + Please see the documentation for your service mesh. Generally, the setup would be similar to the previous description + for defining an ingress, except the service mesh would probably provide both the ingress with TLS termination + and the service. + +For either of the first two options, if you installed using `ytt` then you can use +the related `service_*` options from [deploy/supervisor/values.yml](values.yaml) to create a Service. +If you installed using `install-supervisor.yaml` then you can create +the Service separately after installing the Supervisor app. There is no `Ingress` included in the `ytt` templates, +so if you choose to use an Ingress then you'll need to create that separately after installing the Supervisor app. + +#### Example: Using a LoadBalancer Service + +This is an example of creating a LoadBalancer Service to expose port 8443 of the Supervisor app outside the cluster. + +```yaml +apiVersion: v1 +kind: Service +metadata: + name: pinniped-supervisor-loadbalancer + # Assuming that this is the namespace where the supervisor was installed. This is the default in install-supervisor.yaml. + namespace: pinniped-supervisor +spec: + type: LoadBalancer + selector: + # Assuming that this is how the supervisor pods are labeled. This is the default in install-supervisor.yaml. + app: pinniped-supervisor + ports: + - protocol: TCP + port: 443 + targetPort: 8443 +``` + +#### Example: Using a NodePort Service + +A NodePort Service exposes the app as a port on the nodes of the cluster. + +This is convenient for use with kind clusters, because kind can +[expose node ports as localhost ports on the host machine](https://kind.sigs.k8s.io/docs/user/configuration/#extra-port-mappings) +without requiring an Ingress, although +[kind also supports several Ingress Controllers](https://kind.sigs.k8s.io/docs/user/ingress). + +A NodePort Service could also be used behind an Ingress which is terminating TLS. + +For example: + +```yaml +apiVersion: v1 +kind: Service +metadata: + name: pinniped-supervisor-nodeport + # Assuming that this is the namespace where the supervisor was installed. This is the default in install-supervisor.yaml. + namespace: pinniped-supervisor +spec: + type: NodePort + selector: + # Assuming that this is how the supervisor pods are labeled. This is the default in install-supervisor.yaml. + app: pinniped-supervisor + ports: + - protocol: TCP + port: 80 + targetPort: 8080 + nodePort: 31234 # This is the port that you would forward to the kind host. Or omit this key for a random port. +``` + +### Configuring the Supervisor to act as an OIDC provider + +The Supervisor can be configured as an OIDC provider by creating `FederationDomain` resources +in the same namespace where the Supervisor app was installed. For example: + +```yaml +apiVersion: config.supervisor.pinniped.dev/v1alpha1 +kind: FederationDomain +metadata: + name: my-provider + # Assuming that this is the namespace where the supervisor was installed. This is the default in install-supervisor.yaml. + namespace: pinniped-supervisor +spec: + # The hostname would typically match the DNS name of the public ingress or load balancer for the cluster. + # Any path can be specified, which allows a single hostname to have multiple different issuers. The path is optional. + issuer: https://my-issuer.example.com/any/path + + # Optionally configure the name of a Secret in the same namespace, of type `kubernetes.io/tls`, + # which contains the TLS serving certificate for the HTTPS endpoints served by this OIDC Provider. + tls: + secretName: my-tls-cert-secret +``` + +#### Configuring TLS for the Supervisor OIDC endpoints + +If you have terminated TLS outside the app, for example using an Ingress with TLS certificates, then you do not need to +configure TLS certificates on the FederationDomain. + +If you are using a LoadBalancer Service to expose the Supervisor app outside your cluster, then you +also need to configure the Supervisor app to terminate TLS. There are two places to configure TLS certificates: + +1. Each `FederationDomain` can be configured with TLS certificates, using the `spec.tls.secretName` field. + +1. The default TLS certificate for all OIDC providers can be configured by creating a Secret called +`pinniped-supervisor-default-tls-certificate` in the same namespace in which the Supervisor was installed. + +The default TLS certificate are used for all OIDC providers which did not declare a `spec.tls.secretName`. +Also, the `spec.tls.secretName` is ignored for incoming requests to the OIDC endpoints +that use an IP address as the host, so those requests always present the default TLS certificates +to the client. When the request includes the hostname, and that hostname matches the hostname of an `Issuer`, +then the TLS certificate defined by the `spec.tls.secretName` is used. If that issuer did not +define `spec.tls.secretName` then the default TLS certificate is used. If neither exists, +then the client gets a TLS error because the server does not present any TLS certificate. + +It is recommended that you have a DNS entry for your load balancer or Ingress, and that you configure the +OIDC provider's `Issuer` using that DNS hostname, and that the TLS certificate for that provider also +covers that same hostname. + +You can create the certificate Secrets however you like, for example you could use [cert-manager](https://cert-manager.io/) +or `kubectl create secret tls`. +Keep in mind that your users must load some of these endpoints in their web browsers, so the TLS certificates +should be signed by a certificate authority that is trusted by their browsers. diff --git a/site/content/docs/howto/install-cli.md b/site/content/docs/howto/install-cli.md new file mode 100644 index 00000000..353d8f43 --- /dev/null +++ b/site/content/docs/howto/install-cli.md @@ -0,0 +1,55 @@ +--- +title: Install the Pinniped command-line tool +description: Download and set up the `pinniped` command-line tool on macOS, Linux, or Windows clients. +cascade: + layout: docs +menu: + docs: + name: Install CLI + weight: 10 + parent: howtos +--- +The `pinniped` command-line tool is used to generate Pinniped-compatible kubeconfig files, and is also an important part of the Pinniped-based login flow. + +It must be installed by administrators setting up a Pinniped cluster as well as by users accessing a Pinniped-enabled cluster. + +## Install using Homebrew on macOS or Linux + +Use [Homebrew](https://brew.sh/) to install from the Pinniped [tap](https://github.com/vmware-tanzu/homebrew-pinniped): + +- `brew install vmware-tanzu/pinniped/pinniped-cli` + +## Download binaries + +Find the appropriate binary for your platform from the [latest release](https://github.com/vmware-tanzu/pinniped/releases/latest): + +{{< buttonlink href="https://get.pinniped.dev/latest/pinniped-cli-darwin-amd64" >}}Download for macOS/amd64{{< buttonicon "download.png" >}}{{< /buttonlink >}} + +{{< buttonlink href="https://get.pinniped.dev/latest/pinniped-cli-linux-amd64" >}}Download for Linux/amd64{{< buttonicon "download.png" >}}{{< /buttonlink >}} + +{{< buttonlink href="https://get.pinniped.dev/latest/pinniped-cli-windows-amd64" >}}Download for Windows/amd64{{< buttonicon "download.png" >}}{{< /buttonlink >}} + +You should put the command-line tool somewhere on your `$PATH`, such as `/usr/local/bin` on macOS/Linux. +You'll also need to mark the file as executable. + +To find specific versions or view all available platforms and architectures, visit the [releases page](https://github.com/vmware-tanzu/pinniped/releases/). + +### Gatekeeper + +If you are using macOS, you may get an error dialog when you first run `pinniped` that says `“pinniped” cannot be opened because the developer cannotbe verified`. +Cancel this dialog, open System Preferences, click Security & Privacy, and click the Allow Anyway button next to the Pinniped message. + +Run the command again and another dialog appears saying `macOS cannot verify the developer of “pinniped”. Are you sure you want to open it?`. +Click Open to allow the command to proceed. + +## Install a specific version via script + +For example, to install v0.4.1 on Linux/amd64: + +```sh +curl -Lso pinniped https://get.pinniped.dev/v0.4.1/pinniped-cli-linux-amd64 \ + && chmod +x pinniped \ + && sudo mv pinniped /usr/local/bin/pinniped +``` + +*Next, [install the Concierge]({{< ref "install-concierge.md" >}})!* diff --git a/site/content/docs/howto/install-concierge.md b/site/content/docs/howto/install-concierge.md new file mode 100644 index 00000000..e8e66714 --- /dev/null +++ b/site/content/docs/howto/install-concierge.md @@ -0,0 +1,60 @@ +--- +title: Install the Pinniped Concierge +description: Install the Pinniped Concierge service in a Kubernetes cluster. +cascade: + layout: docs +menu: + docs: + name: Install Concierge + weight: 20 + parent: howtos +--- +This guide shows you how to install the Pinniped Concierge. +You should have a [supported Kubernetes cluster]({{< ref "../reference/supported-clusters" >}}). + +## With default options + +1. Install the latest version of the Concierge into the `pinniped-concierge` namespace with default options: + + - `kubectl apply -f https://get.pinniped.dev/latest/install-pinniped-concierge.yaml` + +## With specific version and default options + +1. Choose your preferred [release](https://github.com/vmware-tanzu/pinniped/releases) version number and use it to replace the version number in the URL below. + +1. Install the Concierge into the `pinniped-concierge` namespace with default options: + + - `kubectl apply -f https://get.pinniped.dev/v0.4.1/install-pinniped-concierge.yaml` + + *Replace v0.4.1 with your preferred version number.* + +## With custom options + +Pinniped uses [ytt](https://carvel.dev/ytt/) from [Carvel](https://carvel.dev/) as a templating system. + +1. Install the `ytt` command-line tool using the instructions from the [Carvel documentation](https://carvel.dev/#whole-suite). + +1. Clone the Pinniped GitHub repository and visit the `deploy/concierge` directory: + + - `git clone git@github.com:vmware-tanzu/pinniped.git` + - `cd pinniped/deploy/concierge` + +1. Customize configuration parameters: + + - Edit `values.yaml` with your custom values. + - See the [default values](http://github.com/vmware-tanzu/pinniped/tree/main/deploy/concierge/values.yaml) for documentation about individual configuration parameters. + +1. Render templated YAML manifests: + + - `ytt --file .` + +1. Deploy the templated YAML manifests: + + - *If you're using `kubectl`:* + + `ytt --file . | kubectl apply -f -` + - *If you're using [`kapp` from Carvel](https://carvel.dev/kapp/):* + + `ytt --file . | kapp deploy --yes --app pinniped-concierge --diff-changes --file -` + +*Next, configure the Concierge for [JWT]({{< ref "configure-concierge-jwt.md" >}}) or [webhook]({{< ref "configure-concierge-webhook.md" >}}) authentication.* diff --git a/site/content/docs/howto/install-supervisor.md b/site/content/docs/howto/install-supervisor.md new file mode 100644 index 00000000..49267842 --- /dev/null +++ b/site/content/docs/howto/install-supervisor.md @@ -0,0 +1,59 @@ +--- +title: Install the Pinniped Supervisor +description: Install the Pinniped Supervisor service in a Kubernetes cluster. +cascade: + layout: docs +menu: + docs: + name: Install Supervisor + weight: 30 + parent: howtos +--- +This guide shows you how to install the Pinniped Supervisor, which allows seamless login across one or many Kubernetes clusters. +You should have a supported Kubernetes cluster with working HTTPS ingress capabilities. + + +## With default options + +1. Install the latest version of the Supervisor into the `pinniped-supervisor` namespace with default options: + + - `kubectl apply -f https://get.pinniped.dev/latest/install-pinniped-supervisor.yaml` + +## With specific version and default options + +1. Choose your preferred [release](https://github.com/vmware-tanzu/pinniped/releases) version number and use it to replace the version number in the URL below. + +1. Install theSupervisor into the `pinniped-supervisor` namespace with default options: + + - `kubectl apply -f https://get.pinniped.dev/v0.4.1/install-pinniped-concierge.yaml` + + *Replace v0.4.1 with your preferred version number.* + +## With custom options + +Pinniped uses [ytt](https://carvel.dev/ytt/) from [Carvel](https://carvel.dev/) as a templating system. + +1. Install the `ytt` command-line tool using the instructions from the [Carvel documentation](https://carvel.dev/#whole-suite). + +1. Clone the Pinniped GitHub repository and visit the `deploy/supervisor` directory: + + - `git clone git@github.com:vmware-tanzu/pinniped.git` + - `cd pinniped/deploy/supervisor` + +1. Customize configuration parameters: + + - Edit `values.yaml` with your custom values. + - See the [default values](http://github.com/vmware-tanzu/pinniped/tree/main/deploy/supervisor/values.yaml) for documentation about individual configuration parameters. + +1. Render templated YAML manifests: + + - `ytt --file .` + +1. Deploy the templated YAML manifests: + + - *If you're using `kubectl`:* + + `ytt --file . | kubectl apply -f -` + - *If you're using [`kapp` from Carvel](https://carvel.dev/kapp/):* + + `ytt --file . | kapp deploy --yes --app pinniped-supervisor --diff-changes --file -` diff --git a/site/content/docs/install.md b/site/content/docs/install.md deleted file mode 100644 index 4fffc9ef..00000000 --- a/site/content/docs/install.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -title: "Installing Pinniped" -cascade: - layout: docs -menu: - docs: - name: Install - weight: 10 ---- - -# Installing Pinniped - -## Install the CLI - -- Find the appropriate binary for your platform from the [latest release](https://github.com/vmware-tanzu/pinniped/releases/latest). - -- Use Homebrew on macOS: `brew install vmware-tanzu/pinniped/pinniped-cli`. - -## Install the Concierge - -- See the [concierge deployment guide](https://github.com/vmware-tanzu/pinniped/tree/main/deploy/concierge). - -## Install the Supervisor - -- See the [supervisor deployment guide](https://github.com/vmware-tanzu/pinniped/tree/main/deploy/supervisor). \ No newline at end of file diff --git a/site/content/docs/reference/_index.md b/site/content/docs/reference/_index.md new file mode 100644 index 00000000..052154c5 --- /dev/null +++ b/site/content/docs/reference/_index.md @@ -0,0 +1,13 @@ +--- +cascade: + layout: docs +menu: + docs: + name: Reference + identifier: reference + weight: 100 +--- + +# Pinniped reference + +{{< docsmenu "reference" >}} diff --git a/site/content/docs/reference/api.md b/site/content/docs/reference/api.md new file mode 100644 index 00000000..95f8fdf2 --- /dev/null +++ b/site/content/docs/reference/api.md @@ -0,0 +1,12 @@ +--- +title: API +description: Reference for the `*.pinniped.dev` Kubernetes API groups. +cascade: + layout: docs +menu: + docs: + name: Kubernetes API + weight: 35 + parent: reference +--- +Full API reference documentation for the Pinniped Kubernetes API is available [on GitHub](https://github.com/vmware-tanzu/pinniped/blob/main/generated/1.20/README.adoc). diff --git a/site/content/docs/reference/cli.md b/site/content/docs/reference/cli.md new file mode 100644 index 00000000..de1c4e34 --- /dev/null +++ b/site/content/docs/reference/cli.md @@ -0,0 +1,84 @@ +--- +title: Command-Line Options Reference +description: Reference for the `pinniped` command-line tool +cascade: + layout: docs +menu: + docs: + name: Command-Line Options + weight: 30 + parent: reference +--- + +## `pinniped version` + +Print the version of this Pinniped CLI. + +```sh +pinniped version [flags] +``` + +- `-h`, `--help`: + + help for kubeconfig + +## `pinniped get kubeconfig` + +Generate a Pinniped-based kubeconfig for a cluster. + +```sh +pinniped get kubeconfig [flags] +``` + +- `-h`, `--help`: + + help for kubeconfig + +- `--concierge-api-group-suffix string`: + + Concierge API group suffix (default "pinniped.dev") +- `--concierge-authenticator-name string`: + + Concierge authenticator name (default: autodiscover) +- `--concierge-authenticator-type string`: + + Concierge authenticator type (e.g., 'webhook', 'jwt') (default: autodiscover) +- `--kubeconfig string`: + + Path to kubeconfig file +- `--kubeconfig-context string`: + + Kubeconfig context name (default: current active context) +- `--no-concierge`: + + Generate a configuration which does not use the concierge, but sends the credential to the cluster directly +- `--oidc-ca-bundle strings`: + + Path to TLS certificate authority bundle (PEM format, optional, can be repeated) +- `--oidc-client-id string`: + + OpenID Connect client ID (default: autodiscover) (default "pinniped-cli") +- `--oidc-issuer string`: + + OpenID Connect issuer URL (default: autodiscover) +- `--oidc-listen-port uint16`: + + TCP port for localhost listener (authorization code flow only) +- `--oidc-request-audience string`: + + Request a token with an alternate audience using RFC8693 token exchange +- `--oidc-scopes strings`: + + OpenID Connect scopes to request during login (default [offline_access,openid,pinniped:request-audience]) +- `--oidc-session-cache string`: + + Path to OpenID Connect session cache file +- `--oidc-skip-browser`: + + During OpenID Connect login, skip opening the browser (just print the URL) +- `--static-token string`: + + Instead of doing an OIDC-based login, specify a static token +- `--static-token-env string`: + + Instead of doing an OIDC-based login, read a static token from the environment diff --git a/site/content/docs/reference/supported-clusters.md b/site/content/docs/reference/supported-clusters.md new file mode 100644 index 00000000..8ff538f2 --- /dev/null +++ b/site/content/docs/reference/supported-clusters.md @@ -0,0 +1,29 @@ +--- +title: Supported cluster types +description: See the supported cluster types for the Pinniped Concierge. +cascade: + layout: docs +menu: + docs: + name: Supported Cluster Types + weight: 10 + parent: reference +--- + +| **Cluster Type** | **Conciege Works?** | +|-|-| +| [VMware Tanzu Kubernetes Grid (TKG) clusters](https://tanzu.vmware.com/kubernetes-grid) | Yes | +| [Kind clusters](https://kind.sigs.k8s.io/) | Yes | +| [Kubeadm-based clusters](https://kubernetes.io/docs/reference/setup-tools/kubeadm/) | Yes | +| [Amazon Elastic Kubernetes Service (EKS)](https://aws.amazon.com/eks/) | No | +| [Google Kubernetes Engine (GKE)](https://cloud.google.com/kubernetes-engine) | No | +| [Azure Kubernetes Service (AKS)](https://azure.microsoft.com/en-us/overview/kubernetes-on-azure) | No | + +## Background + +The Pinniped Concierge currently supports clusters where a custom pod can be executed on the same node running `kube-controller-manager`. +This type of cluster is typically called "self-hosted" because the cluster's control plane is running on nodes that are part of the cluster itself. + +In practice, this means that many Kubernetes distributions are supported, but not most managed Kubernetes services + +Support for more cluster types, including managed Kubernetes environments, is planned. diff --git a/site/content/docs/tutorials/_index.md b/site/content/docs/tutorials/_index.md new file mode 100644 index 00000000..b95b06cd --- /dev/null +++ b/site/content/docs/tutorials/_index.md @@ -0,0 +1,15 @@ +--- +cascade: + layout: docs +menu: + docs: + name: Tutorials + identifier: tutorials + weight: 40 +--- + +# Pinniped tutorials + +These tutorials demonstrate how to use the Pinniped command-line tool, Concierge, and Supervisor: + +{{< docsmenu "tutorials" >}} diff --git a/site/content/docs/concierge-and-supervisor-demo.md b/site/content/docs/tutorials/concierge-and-supervisor-demo.md similarity index 72% rename from site/content/docs/concierge-and-supervisor-demo.md rename to site/content/docs/tutorials/concierge-and-supervisor-demo.md index ff38d188..382cdfc0 100644 --- a/site/content/docs/concierge-and-supervisor-demo.md +++ b/site/content/docs/tutorials/concierge-and-supervisor-demo.md @@ -1,15 +1,14 @@ --- -title: "Pinniped Concierge and Supervisor Demo" +title: Learn to use the Pinniped Supervisor alongside the Concierge +description: See how the Pinniped Supervisor streamlines login to multiple Kubernetes clusters. cascade: layout: docs menu: docs: name: Concierge with Supervisor - parent: demo + parent: tutorials --- -# Trying Pinniped Supervisor and Concierge - ## Prerequisites 1. A Kubernetes cluster of a type supported by Pinniped Concierge as described in [architecture](/docs/architecture). @@ -17,18 +16,18 @@ menu: Don't have a cluster handy? Consider using [kind](https://kind.sigs.k8s.io/) on your local machine. See below for an example of using kind. -1. A Kubernetes cluster of a type supported by Pinniped Supervisor (this can be the same cluster as the above, or different). +1. A Kubernetes cluster of a type supported by Pinniped Supervisor (this can be the same cluster as the first, or different). -1. A kubeconfig that has admin-like privileges on each cluster. +1. A kubeconfig that has administrator-like privileges on each cluster. 1. An external OIDC identity provider to use as the source of identity for Pinniped. ## Overview -Installing and trying Pinniped on any cluster will consist of the following general steps. See the next section below +Installing and trying Pinniped on any cluster consists of the following general steps. See the next section below for a more specific example, including the commands to use for that case. -1. Install the Pinniped Supervisor. See [deploy/supervisor/README.md](https://github.com/vmware-tanzu/pinniped/blob/main/deploy/supervisor/README.md). +1. [Install the Supervisor]({{< ref "../howto/install-supervisor" >}}). 1. Create a [`FederationDomain`](https://github.com/vmware-tanzu/pinniped/blob/main/generated/1.20/README.adoc#k8s-api-go-pinniped-dev-generated-1-19-apis-supervisor-config-v1alpha1-federationdomain) via the installed Pinniped Supervisor. @@ -39,31 +38,31 @@ for a more specific example, including the commands to use for that case. 1. Create a [`JWTAuthenticator`](https://github.com/vmware-tanzu/pinniped/blob/main/generated/1.20/README.adoc#k8s-api-go-pinniped-dev-generated-1-19-apis-concierge-authentication-v1alpha1-jwtauthenticator) via the installed Pinniped Concierge. -1. Download the Pinniped CLI from [Pinniped's github Releases page](https://github.com/vmware-tanzu/pinniped/releases/latest). -1. Generate a kubeconfig using the Pinniped CLI. Run `pinniped get kubeconfig --help` for more information. -1. Run `kubectl` commands using the generated kubeconfig. The Pinniped Supervisor and Concierge will automatically be used for authentication during those commands. +1. [Install the Pinniped command-line tool]({{< ref "../howto/install-cli" >}}). +1. Generate a kubeconfig using the Pinniped command-line tool. Run `pinniped get kubeconfig --help` for more information. +1. Run `kubectl` commands using the generated kubeconfig. The Pinniped Supervisor and Concierge are automatically used for authentication during those commands. -## Example of Deploying on Multiple kind Clusters +## Example of deploying on multiple kind clusters [kind](https://kind.sigs.k8s.io) is a tool for creating and managing Kubernetes clusters on your local machine -which uses Docker containers as the cluster's "nodes". This is a convenient way to try out Pinniped on local +which uses Docker containers as the cluster's nodes. This is a convenient way to try out Pinniped on local non-production clusters. -The following steps will deploy the latest release of Pinniped on kind. It will deploy the Pinniped +The following steps deploy the latest release of Pinniped on kind. They deploy the Pinniped Supervisor on one cluster, and the Pinniped Concierge on another cluster. A multi-cluster deployment -strategy is typical for Pinniped. The Pinniped Concierge will use a +strategy is typical for Pinniped. The Pinniped Concierge uses a [`JWTAuthenticator`](https://github.com/vmware-tanzu/pinniped/blob/main/generated/1.20/README.adoc#k8s-api-go-pinniped-dev-generated-1-19-apis-concierge-authentication-v1alpha1-jwtauthenticator) to authenticate federated identities from the Supervisor. 1. Install the tools required for the following steps. - - [Install kind](https://kind.sigs.k8s.io/docs/user/quick-start/), if not already installed. e.g. `brew install kind` on MacOS. + - [Install kind](https://kind.sigs.k8s.io/docs/user/quick-start/), if not already installed. For example, `brew install kind` on macOS. - - kind depends on Docker. If not already installed, [install Docker](https://docs.docker.com/get-docker/), e.g. `brew cask install docker` on MacOS. + - kind depends on Docker. If not already installed, [install Docker](https://docs.docker.com/get-docker/), for example `brew cask install docker` on macOS. - This demo requires `kubectl`, which comes with Docker, or can be [installed separately](https://kubernetes.io/docs/tasks/tools/install-kubectl/). - - This demo requires `openssl`, which is installed on MacOS by default, or can be [installed separately](https://www.openssl.org/). + - This demo requires `openssl`, which is installed on macOS by default, or can be [installed separately](https://www.openssl.org/). 1. Create a new Kubernetes cluster for the Pinniped Supervisor using `kind create cluster --name pinniped-supervisor`. @@ -72,10 +71,10 @@ to authenticate federated identities from the Supervisor. 1. Deploy the Pinniped Supervisor with a valid serving certificate and network path. See [deploy/supervisor/README.md](https://github.com/vmware-tanzu/pinniped/blob/main/deploy/supervisor/README.md). - For purposes of this demo, the following issuer will be used. This issuer is specific to DNS and - TLS infrastructure set up for this demo. + For purposes of this demo, the following issuer is used. This issuer is specific to DNS and + TLS infrastructure set up for this demo: - ```bash + ```sh issuer=https://my-supervisor.demo.pinniped.dev ``` @@ -92,7 +91,7 @@ to authenticate federated identities from the Supervisor. [`FederationDomain`](https://github.com/vmware-tanzu/pinniped/blob/main/generated/1.20/README.adoc#k8s-api-go-pinniped-dev-generated-1-19-apis-supervisor-config-v1alpha1-federationdomain) object to configure the Pinniped Supervisor to issue federated identities. - ```bash + ```sh cat <}}) for instructions on how to deploy using `ytt`. - If you prefer to install a specific version, replace `latest` in the above URL with the version number such as `v0.4.1`. - 1. Generate a random audience value for this cluster. - ```bash + ```sh audience="$(openssl rand -hex 8)" ``` @@ -166,7 +163,7 @@ to authenticate federated identities from the Supervisor. [`JWTAuthenticator`](https://github.com/vmware-tanzu/pinniped/blob/main/generated/1.20/README.adoc#k8s-api-go-pinniped-dev-generated-1-19-apis-concierge-authentication-v1alpha1-jwtauthenticator) object to configure the Pinniped Concierge to authenticate using the Pinniped Supervisor. - ```bash + ```sh cat <}}) for more details. 1. Generate a kubeconfig for the current cluster. - ```bash + + ```sh pinniped get kubeconfig \ --kubeconfig-context kind-pinniped-concierge \ > /tmp/pinniped-kubeconfig ``` - If you are using MacOS, you may get an error dialog that says - `“pinniped” cannot be opened because the developer cannot be verified`. Cancel this dialog, open System Preferences, - click on Security & Privacy, and click the Allow Anyway button next to the Pinniped message. - Run the above command again and another dialog will appear saying - `macOS cannot verify the developer of “pinniped”. Are you sure you want to open it?`. - Click Open to allow the command to proceed. +1. Try using the generated kubeconfig to issue arbitrary `kubectl` commands. The `pinniped` command-line tool + opens a browser page that can be used to login to the external OIDC identity provider configured earlier. -1. Try using the generated kubeconfig to issue arbitrary `kubectl` commands. The `pinniped` CLI will - open a browser page that can be used to login to the external OIDC identity provider configured earlier. - - ```bash + ```sh kubectl --kubeconfig /tmp/pinniped-kubeconfig get pods -n pinniped-concierge ``` @@ -213,30 +208,28 @@ to authenticate federated identities from the Supervisor. to the upstream OIDC identity provider. However, this does prove that you are authenticated and acting as the `pinny` user. -1. As the admin user, create RBAC rules for the test user to give them permissions to perform actions on the cluster. +1. As the administrator user, create RBAC rules for the test user to give them permissions to perform actions on the cluster. For example, grant the test user permission to view all cluster resources. - ```bash + ```sh kubectl --context kind-pinniped-concierge create clusterrolebinding pinny-can-read --clusterrole view --user pinny ``` 1. Use the generated kubeconfig to issue arbitrary `kubectl` commands as the `pinny` user. - ```bash + ```sh kubectl --kubeconfig /tmp/pinniped-kubeconfig get pods -n pinniped-concierge ``` The user has permission to list pods, so the command succeeds this time. - Pinniped has provided authentication into the cluster for your `kubectl` command! 🎉 + Pinniped has provided authentication into the cluster for your `kubectl` command. 🎉 1. Carry on issuing as many `kubectl` commands as you'd like as the `pinny` user. - Each invocation will use Pinniped for authentication. + Each invocation uses Pinniped for authentication. You may find it convenient to set the `KUBECONFIG` environment variable rather than passing `--kubeconfig` to each invocation. - ```bash + ```sh export KUBECONFIG=/tmp/pinniped-kubeconfig kubectl get namespaces kubectl get pods -A ``` - -1. Profit! 💰 diff --git a/site/content/docs/concierge-only-demo.md b/site/content/docs/tutorials/concierge-only-demo.md similarity index 62% rename from site/content/docs/concierge-only-demo.md rename to site/content/docs/tutorials/concierge-only-demo.md index deecfb0f..22943c84 100644 --- a/site/content/docs/concierge-only-demo.md +++ b/site/content/docs/tutorials/concierge-only-demo.md @@ -1,16 +1,15 @@ --- -title: "Pinniped Concierge Only Demo" +title: Learn to use the Pinniped Concierge +description: See how the Pinniped Concierge works to provide a uniform login flow across different Kubernetes clusters. cascade: layout: docs menu: docs: name: Concierge with Webhook - parent: demo + parent: tutorials weight: 100 --- -# Trying Pinniped Concierge - ## Prerequisites 1. A Kubernetes cluster of a type supported by Pinniped as described in [architecture](/docs/architecture). @@ -25,48 +24,53 @@ menu: by following the directions in [deploy/local-user-authenticator/README.md](https://github.com/vmware-tanzu/pinniped/blob/main/deploy/local-user-authenticator/README.md). See below for an example of deploying this on kind. -1. A kubeconfig where the current context points to the cluster and has admin-like +1. A kubeconfig where the current context points to the cluster and has administrator-like privileges on that cluster. ## Overview -Installing and trying Pinniped on any cluster will consist of the following general steps. See the next section below +Installing and trying the Pinniped Concierge on any cluster consists of the following general steps. See the next section below for a more specific example of installing onto a local kind cluster, including the exact commands to use for that case. -1. Install the Pinniped Concierge. See [deploy/concierge/README.md](https://github.com/vmware-tanzu/pinniped/blob/main/deploy/concierge/README.md). -1. Download the Pinniped CLI from [Pinniped's github Releases page](https://github.com/vmware-tanzu/pinniped/releases/latest). -1. Generate a kubeconfig using the Pinniped CLI. Run `pinniped get kubeconfig --help` for more information. -1. Run `kubectl` commands using the generated kubeconfig. The Pinniped Concierge will automatically be used for authentication during those commands. +1. [Install the Concierge]({{< ref "../howto/install-concierge" >}}). +1. [Install the Pinniped command-line tool]({{< ref "../howto/install-cli" >}}). +1. Configure the Concierge with a + [JWT]({{< ref "../howto/configure-concierge-jwt" >}}) or + [webhook]({{< ref "../howto/configure-concierge-webhook" >}}) authenticator. +1. Generate a kubeconfig using the Pinniped command-line tool (run `pinniped get kubeconfig --help` for more information). +1. Run `kubectl` commands using the generated kubeconfig. -## Example of Deploying on kind + The Pinniped Concierge is automatically be used for authentication during those commands. + +## Example of deploying on kind [kind](https://kind.sigs.k8s.io) is a tool for creating and managing Kubernetes clusters on your local machine -which uses Docker containers as the cluster's "nodes". This is a convenient way to try out Pinniped on a local +which uses Docker containers as the cluster's nodes. This is a convenient way to try out Pinniped on a local non-production cluster. -The following steps will deploy the latest release of Pinniped on kind using the local-user-authenticator component +The following steps deploy the latest release of Pinniped on kind using the local-user-authenticator component as the authenticator. 1. Install the tools required for the following steps. - - [Install kind](https://kind.sigs.k8s.io/docs/user/quick-start/), if not already installed. e.g. `brew install kind` on MacOS. + - [Install kind](https://kind.sigs.k8s.io/docs/user/quick-start/), if not already installed. For example, `brew install kind` on macOS. - - kind depends on Docker. If not already installed, [install Docker](https://docs.docker.com/get-docker/), e.g. `brew cask install docker` on MacOS. + - kind depends on Docker. If not already installed, [install Docker](https://docs.docker.com/get-docker/), for example `brew cask install docker` on macOS. - This demo requires `kubectl`, which comes with Docker, or can be [installed separately](https://kubernetes.io/docs/tasks/tools/install-kubectl/). - - This demo requires a tool capable of generating a `bcrypt` hash in order to interact with + - This demo requires a tool capable of generating a `bcrypt` hash to interact with the webhook. The example below uses `htpasswd`, which is installed on most macOS systems, and can be - installed on some Linux systems via the `apache2-utils` package (e.g., `apt-get install + installed on some Linux systems via the `apache2-utils` package (for example, `apt-get install apache2-utils`). 1. Create a new Kubernetes cluster using `kind create cluster`. Optionally provide a cluster name using the `--name` flag. - kind will automatically update your kubeconfig to point to the new cluster as a user with admin-like permissions. + kind automatically updates your kubeconfig to point to the new cluster as a user with administrator-like permissions. 1. Deploy the local-user-authenticator app. This is a demo authenticator. In production, you would configure an authenticator that works with your real identity provider, and therefore would not need to deploy or configure local-user-authenticator. - ```bash + ```sh kubectl apply -f https://get.pinniped.dev/latest/install-local-user-authenticator.yaml ``` @@ -75,11 +79,11 @@ as the authenticator. see [deploy/local-user-authenticator/README.md](https://github.com/vmware-tanzu/pinniped/blob/main/deploy/local-user-authenticator/README.md) for instructions on how to deploy using `ytt`. - If you prefer to install a specific version, replace `latest` in the above URL with the version number such as `v0.4.1`. + If you prefer to install a specific version, replace `latest` in the URL with the version number such as `v0.4.1`. 1. Create a test user named `pinny-the-seal` in the local-user-authenticator namespace. - ```bash + ```sh kubectl create secret generic pinny-the-seal \ --namespace local-user-authenticator \ --from-literal=groups=group1,group2 \ @@ -88,7 +92,7 @@ as the authenticator. 1. Fetch the auto-generated CA bundle for the local-user-authenticator's HTTP TLS endpoint. - ```bash + ```sh kubectl get secret local-user-authenticator-tls-serving-certificate --namespace local-user-authenticator \ -o jsonpath={.data.caCertificate} \ | tee /tmp/local-user-authenticator-ca-base64-encoded @@ -96,12 +100,12 @@ as the authenticator. 1. Deploy the Pinniped Concierge. - ```bash + ```sh kubectl apply -f https://get.pinniped.dev/latest/install-pinniped-concierge.yaml ``` The `install-pinniped-concierge.yaml` file includes the default deployment options. - If you would prefer to customize the available options, please see [deploy/concierge/README.md](https://github.com/vmware-tanzu/pinniped/blob/main/deploy/concierge/README.md) + If you would prefer to customize the available options, please see the [Concierge installation guide]({{< ref "../howto/install-concierge" >}}) for instructions on how to deploy using `ytt`. 1. Create a `WebhookAuthenticator` object to configure the Pinniped Concierge to authenticate using local-user-authenticator. @@ -119,61 +123,63 @@ as the authenticator. EOF ``` -1. Download the latest version of the Pinniped CLI binary for your platform - from Pinniped's [latest release](https://github.com/vmware-tanzu/pinniped/releases/latest). +1. Download the latest version of the Pinniped command-line tool for your platform. + On macOS or Linux, you can do this using Homebrew: -1. Move the Pinniped CLI binary to your preferred filename and directory. Add the executable bit, - e.g. `chmod +x /usr/local/bin/pinniped`. - -1. Generate a kubeconfig for the current cluster. Use `--static-token` to include a token which should - allow you to authenticate as the user that you created above. - - ```bash - pinniped get kubeconfig --static-token "pinny-the-seal:password123" --concierge-authenticator-type webhook --concierge-authenticator-name local-user-authenticator > /tmp/pinniped-kubeconfig + ```sh + brew install vmware-tanzu/pinniped/pinniped-cli ``` - If you are using MacOS, you may get an error dialog that says - `“pinniped” cannot be opened because the developer cannot be verified`. Cancel this dialog, open System Preferences, - click on Security & Privacy, and click the Allow Anyway button next to the Pinniped message. - Run the above command again and another dialog will appear saying - `macOS cannot verify the developer of “pinniped”. Are you sure you want to open it?`. - Click Open to allow the command to proceed. + On other platforms, see the [command-line installation guide]({{< ref "../howto/install-cli" >}}) for more details. + +1. Generate a kubeconfig for the current cluster. Use `--static-token` to include a token which should + allow you to authenticate as the user that you created previously. + + ```sh + pinniped get kubeconfig \ + --static-token "pinny-the-seal:password123" \ + --concierge-authenticator-type webhook \ + --concierge-authenticator-name local-user-authenticator \ + > /tmp/pinniped-kubeconfig + ``` 1. Try using the generated kubeconfig to issue arbitrary `kubectl` commands as the `pinny-the-seal` user. - ```bash - kubectl --kubeconfig /tmp/pinniped-kubeconfig get pods -n pinniped-concierge + ```sh + kubectl --kubeconfig /tmp/pinniped-kubeconfig \ + get pods -n pinniped-concierge ``` Because this user has no RBAC permissions on this cluster, the previous command - results in the error `Error from server (Forbidden): pods is forbidden: User "pinny-the-seal" cannot list resource "pods" in API group "" in the namespace "pinniped"`. + results in the error `Error from server (Forbidden): pods is forbidden: User "pinny-the-seal" cannot list resource "pods" in API group "" in the namespace "pinniped-concierge"`. However, this does prove that you are authenticated and acting as the `pinny-the-seal` user. -1. As the admin user, create RBAC rules for the test user to give them permissions to perform actions on the cluster. +1. As the administrator user, create RBAC rules for the test user to give them permissions to perform actions on the cluster. For example, grant the test user permission to view all cluster resources. - ```bash - kubectl create clusterrolebinding pinny-can-read --clusterrole view --user pinny-the-seal + ```sh + kubectl create clusterrolebinding pinny-can-read \ + --clusterrole view \ + --user pinny-the-seal ``` 1. Use the generated kubeconfig to issue arbitrary `kubectl` commands as the `pinny-the-seal` user. - ```bash - kubectl --kubeconfig /tmp/pinniped-kubeconfig get pods -n pinniped-concierge + ```sh + kubectl --kubeconfig /tmp/pinniped-kubeconfig \ + get pods -n pinniped-concierge ``` The user has permission to list pods, so the command succeeds this time. - Pinniped has provided authentication into the cluster for your `kubectl` command! 🎉 + Pinniped has provided authentication into the cluster for your `kubectl` command. 🎉 1. Carry on issuing as many `kubectl` commands as you'd like as the `pinny-the-seal` user. - Each invocation will use Pinniped for authentication. + Each invocation uses Pinniped for authentication. You may find it convenient to set the `KUBECONFIG` environment variable rather than passing `--kubeconfig` to each invocation. - ```bash + ```sh export KUBECONFIG=/tmp/pinniped-kubeconfig kubectl get namespaces kubectl get pods -A ``` - -1. Profit! 💰 diff --git a/site/netlify.toml b/site/netlify.toml index 75cbcf73..ba32a73e 100644 --- a/site/netlify.toml +++ b/site/netlify.toml @@ -28,3 +28,8 @@ HUGO_VERSION = "0.78.0" [context.next.environment] HUGO_ENABLEGITINFO = "true" + +[[headers]] + for = "/fonts/*" + [headers.values] + Access-Control-Allow-Origin = "*" diff --git a/site/resources/_gen/assets/scss/scss/site.scss_8967e03afb92eb0cac064520bf021ba2.content b/site/resources/_gen/assets/scss/scss/site.scss_8967e03afb92eb0cac064520bf021ba2.content index 96023260..25ab9b43 100644 --- a/site/resources/_gen/assets/scss/scss/site.scss_8967e03afb92eb0cac064520bf021ba2.content +++ b/site/resources/_gen/assets/scss/scss/site.scss_8967e03afb92eb0cac064520bf021ba2.content @@ -1,3 +1,3 @@ -body{font-family:"Metropolis-Light",Helvetica,sans-serif;margin:0px;line-height:1.25}.wrapper{max-width:980px;margin:0px auto;padding:20px}@media only screen and (max-width: 767px){.wrapper{max-width:100%}}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0}.clearfix:after{clear:both}h1,h2,h3,h4,h5,h6{font-weight:300}h1{font-size:36px}h2{font-size:28px}h3{font-size:22px}h4{font-size:18px}li{list-style-type:none;display:inline;padding-right:25px;font-size:14px;line-height:1.7em}li:last-of-type{padding-right:0px}p{line-height:1.7em;font-weight:300;font-size:16px;color:#333}a{font-size:16px;text-decoration:none;color:#0095D3;font-family:"Metropolis-Medium",Helvetica,sans-serif}button{background-color:unset;border:none}.button{color:#0095D3;font-size:12px;font-weight:600;background-color:#fff;border-radius:3px;padding:14px 10px;min-width:200px;text-transform:uppercase;border:1px solid #fff}.button.secondary{background-color:#0091DA;color:#fff}.button.tertiary{border:1px solid #0095D3}.buttons{margin-top:40px}.buttons .button:first-of-type{margin-right:30px}@media only screen and (max-width: 767px){.buttons .button:first-of-type{margin:0px 0px 20px 0px}}.strong{font-family:"Metropolis-Medium",Helvetica,sans-serif}.bg-grey{background-color:#F2F2F2}.grid.three{display:grid;grid-template-columns:1fr 1fr 1fr;row-gap:20px;column-gap:20px}@media only screen and (max-width: 767px){.grid.three{grid-template-columns:1fr}}.grid.two{display:grid;grid-template-columns:1fr 1fr}@media only screen and (max-width: 767px){.grid.two{grid-template-columns:1fr}}@font-face{font-family:"Metropolis-Bold";src:url("/fonts/Metropolis-Bold.eot");src:url("/fonts/Metropolis-Bold.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Bold.woff2") format("woff2"),url("/fonts/Metropolis-Bold.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-BoldItalic";src:url("/fonts/Metropolis-BoldItalic.eot");src:url("/fonts/Metropolis-BoldItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-BoldItalic.woff2") format("woff2"),url("/fonts/Metropolis-BoldItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Light";src:url("/fonts/Metropolis-Light.eot");src:url("/fonts/Metropolis-Light.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Light.woff2") format("woff2"),url("/fonts/Metropolis-Light.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-LightItalic";src:url("/fonts/Metropolis-LightItalic.eot");src:url("/fonts/Metropolis-LightItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-LightItalic.woff2") format("woff2"),url("/fonts/Metropolis-LightItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Regular";src:url("/fonts/Metropolis-Regular.eot");src:url("/fonts/Metropolis-Regular.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Regular.woff2") format("woff2"),url("/fonts/Metropolis-Regular.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-RegularItalic";src:url("/fonts/Metropolis-RegularItalic.eot");src:url("/fonts/Metropolis-RegularItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-RegularItalic.woff2") format("woff2"),url("/fonts/Metropolis-RegularItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Medium";src:url("/fonts/Metropolis-Medium.eot");src:url("/fonts/Metropolis-Medium.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Medium.woff2") format("woff2"),url("/fonts/Metropolis-Medium.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-MediumItalic";src:url("/fonts/Metropolis-MediumItalic.eot");src:url("/fonts/Metropolis-MediumItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-MediumItalic.woff2") format("woff2"),url("/fonts/Metropolis-MediumItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-SemiBold";src:url("/fonts/Metropolis-SemiBold.eot");src:url("/fonts/Metropolis-SemiBold.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-SemiBold.woff2") format("woff2"),url("/fonts/Metropolis-SemiBold.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-SemiBoldItalic";src:url("/fonts/Metropolis-SemiBoldItalic.eot");src:url("/fonts/Metropolis-SemiBoldItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-SemiBoldItalic.woff2") format("woff2"),url("/fonts/Metropolis-SemiBoldItalic.woff") format("woff");font-weight:normal;font-style:normal}header .wrapper{padding:10px 20px}header .desktop-links{float:right;margin:15px 0px 0px 0px;padding-left:0px}header a{color:#333;font-family:"Metropolis-Light",Helvetica,sans-serif}header a.active{font-family:"Metropolis-Medium",Helvetica,sans-serif}header li img{vertical-align:bottom;margin-right:10px}header .mobile{display:none}@media only screen and (min-width: 768px) and (max-width: 1279px){header .desktop-links li{padding-right:10px}}@media only screen and (max-width: 767px){header{position:relative}header .expanded-icon{display:none;padding:11px 3px 0px 0px}header .collapsed-icon{padding-top:12px}header .mobile-menu-visible .mobile{display:block}header .mobile-menu-visible .mobile .collapsed-icon{display:none}header .mobile-menu-visible .mobile .expanded-icon{display:block}header .desktop-links{display:none}header .mobile{display:block}header button{float:right}header button:focus{outline:none}header ul{padding-left:0px}header ul li{display:block;margin:20px 0px}header .mobile-menu{position:absolute;background-color:#fff;width:100%;top:70px;left:0px;padding-bottom:20px;display:none}header .mobile-menu .header-links{margin:0px 20px}header .mobile-menu .social{margin:0px 20px;padding-top:20px}header .mobile-menu .social img{vertical-align:middle;padding-right:10px}header .mobile-menu .social a{font-size:14px;padding-right:35px}header .mobile-menu .social a:last-of-type{padding-right:0px}}body{font-family:"Metropolis-Light",Helvetica,sans-serif;margin:0px;line-height:1.25}.wrapper{max-width:980px;margin:0px auto;padding:20px}@media only screen and (max-width: 767px){.wrapper{max-width:100%}}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0}.clearfix:after{clear:both}h1,h2,h3,h4,h5,h6{font-weight:300}h1{font-size:36px}h2{font-size:28px}h3{font-size:22px}h4{font-size:18px}li{list-style-type:none;display:inline;padding-right:25px;font-size:14px;line-height:1.7em}li:last-of-type{padding-right:0px}p{line-height:1.7em;font-weight:300;font-size:16px;color:#333}a{font-size:16px;text-decoration:none;color:#0095D3;font-family:"Metropolis-Medium",Helvetica,sans-serif}button{background-color:unset;border:none}.button{color:#0095D3;font-size:12px;font-weight:600;background-color:#fff;border-radius:3px;padding:14px 10px;min-width:200px;text-transform:uppercase;border:1px solid #fff}.button.secondary{background-color:#0091DA;color:#fff}.button.tertiary{border:1px solid #0095D3}.buttons{margin-top:40px}.buttons .button:first-of-type{margin-right:30px}@media only screen and (max-width: 767px){.buttons .button:first-of-type{margin:0px 0px 20px 0px}}.strong{font-family:"Metropolis-Medium",Helvetica,sans-serif}.bg-grey{background-color:#F2F2F2}.grid.three{display:grid;grid-template-columns:1fr 1fr 1fr;row-gap:20px;column-gap:20px}@media only screen and (max-width: 767px){.grid.three{grid-template-columns:1fr}}.grid.two{display:grid;grid-template-columns:1fr 1fr}@media only screen and (max-width: 767px){.grid.two{grid-template-columns:1fr}}@font-face{font-family:"Metropolis-Bold";src:url("/fonts/Metropolis-Bold.eot");src:url("/fonts/Metropolis-Bold.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Bold.woff2") format("woff2"),url("/fonts/Metropolis-Bold.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-BoldItalic";src:url("/fonts/Metropolis-BoldItalic.eot");src:url("/fonts/Metropolis-BoldItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-BoldItalic.woff2") format("woff2"),url("/fonts/Metropolis-BoldItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Light";src:url("/fonts/Metropolis-Light.eot");src:url("/fonts/Metropolis-Light.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Light.woff2") format("woff2"),url("/fonts/Metropolis-Light.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-LightItalic";src:url("/fonts/Metropolis-LightItalic.eot");src:url("/fonts/Metropolis-LightItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-LightItalic.woff2") format("woff2"),url("/fonts/Metropolis-LightItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Regular";src:url("/fonts/Metropolis-Regular.eot");src:url("/fonts/Metropolis-Regular.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Regular.woff2") format("woff2"),url("/fonts/Metropolis-Regular.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-RegularItalic";src:url("/fonts/Metropolis-RegularItalic.eot");src:url("/fonts/Metropolis-RegularItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-RegularItalic.woff2") format("woff2"),url("/fonts/Metropolis-RegularItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Medium";src:url("/fonts/Metropolis-Medium.eot");src:url("/fonts/Metropolis-Medium.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Medium.woff2") format("woff2"),url("/fonts/Metropolis-Medium.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-MediumItalic";src:url("/fonts/Metropolis-MediumItalic.eot");src:url("/fonts/Metropolis-MediumItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-MediumItalic.woff2") format("woff2"),url("/fonts/Metropolis-MediumItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-SemiBold";src:url("/fonts/Metropolis-SemiBold.eot");src:url("/fonts/Metropolis-SemiBold.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-SemiBold.woff2") format("woff2"),url("/fonts/Metropolis-SemiBold.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-SemiBoldItalic";src:url("/fonts/Metropolis-SemiBoldItalic.eot");src:url("/fonts/Metropolis-SemiBoldItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-SemiBoldItalic.woff2") format("woff2"),url("/fonts/Metropolis-SemiBoldItalic.woff") format("woff");font-weight:normal;font-style:normal}footer .left-links{padding:0px;float:left}footer .left-links li img{vertical-align:bottom;margin-right:10px}footer .left-links li a{color:#333;font-weight:300;font-size:12px;font-family:"Metropolis-Light",Helvetica,sans-serif}footer .right-links{float:right}footer .right-links p{margin:0px}footer .right-links .copywrite{font-size:12px;padding-right:10px}footer .right-links .copywrite a{font-size:12px;color:#333;font-family:"Metropolis-Light",Helvetica,sans-serif}footer .right-links a{vertical-align:middle}@media only screen and (max-width: 767px){footer .left-links{width:100%;float:none}footer .left-links li{display:block;width:33%;float:left;padding-right:0px}footer .right-links{width:100%;padding-top:20px}footer .right-links .image{display:none}}body{font-family:"Metropolis-Light",Helvetica,sans-serif;margin:0px;line-height:1.25}.wrapper{max-width:980px;margin:0px auto;padding:20px}@media only screen and (max-width: 767px){.wrapper{max-width:100%}}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0}.clearfix:after{clear:both}h1,h2,h3,h4,h5,h6{font-weight:300}h1{font-size:36px}h2{font-size:28px}h3{font-size:22px}h4{font-size:18px}li{list-style-type:none;display:inline;padding-right:25px;font-size:14px;line-height:1.7em}li:last-of-type{padding-right:0px}p{line-height:1.7em;font-weight:300;font-size:16px;color:#333}a{font-size:16px;text-decoration:none;color:#0095D3;font-family:"Metropolis-Medium",Helvetica,sans-serif}button{background-color:unset;border:none}.button{color:#0095D3;font-size:12px;font-weight:600;background-color:#fff;border-radius:3px;padding:14px 10px;min-width:200px;text-transform:uppercase;border:1px solid #fff}.button.secondary{background-color:#0091DA;color:#fff}.button.tertiary{border:1px solid #0095D3}.buttons{margin-top:40px}.buttons .button:first-of-type{margin-right:30px}@media only screen and (max-width: 767px){.buttons .button:first-of-type{margin:0px 0px 20px 0px}}.strong{font-family:"Metropolis-Medium",Helvetica,sans-serif}.bg-grey{background-color:#F2F2F2}.grid.three{display:grid;grid-template-columns:1fr 1fr 1fr;row-gap:20px;column-gap:20px}@media only screen and (max-width: 767px){.grid.three{grid-template-columns:1fr}}.grid.two{display:grid;grid-template-columns:1fr 1fr}@media only screen and (max-width: 767px){.grid.two{grid-template-columns:1fr}}@font-face{font-family:"Metropolis-Bold";src:url("/fonts/Metropolis-Bold.eot");src:url("/fonts/Metropolis-Bold.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Bold.woff2") format("woff2"),url("/fonts/Metropolis-Bold.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-BoldItalic";src:url("/fonts/Metropolis-BoldItalic.eot");src:url("/fonts/Metropolis-BoldItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-BoldItalic.woff2") format("woff2"),url("/fonts/Metropolis-BoldItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Light";src:url("/fonts/Metropolis-Light.eot");src:url("/fonts/Metropolis-Light.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Light.woff2") format("woff2"),url("/fonts/Metropolis-Light.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-LightItalic";src:url("/fonts/Metropolis-LightItalic.eot");src:url("/fonts/Metropolis-LightItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-LightItalic.woff2") format("woff2"),url("/fonts/Metropolis-LightItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Regular";src:url("/fonts/Metropolis-Regular.eot");src:url("/fonts/Metropolis-Regular.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Regular.woff2") format("woff2"),url("/fonts/Metropolis-Regular.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-RegularItalic";src:url("/fonts/Metropolis-RegularItalic.eot");src:url("/fonts/Metropolis-RegularItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-RegularItalic.woff2") format("woff2"),url("/fonts/Metropolis-RegularItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Medium";src:url("/fonts/Metropolis-Medium.eot");src:url("/fonts/Metropolis-Medium.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Medium.woff2") format("woff2"),url("/fonts/Metropolis-Medium.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-MediumItalic";src:url("/fonts/Metropolis-MediumItalic.eot");src:url("/fonts/Metropolis-MediumItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-MediumItalic.woff2") format("woff2"),url("/fonts/Metropolis-MediumItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-SemiBold";src:url("/fonts/Metropolis-SemiBold.eot");src:url("/fonts/Metropolis-SemiBold.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-SemiBold.woff2") format("woff2"),url("/fonts/Metropolis-SemiBold.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-SemiBoldItalic";src:url("/fonts/Metropolis-SemiBoldItalic.eot");src:url("/fonts/Metropolis-SemiBoldItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-SemiBoldItalic.woff2") format("woff2"),url("/fonts/Metropolis-SemiBoldItalic.woff") format("woff");font-weight:normal;font-style:normal}.hero{background-color:#0091DA;color:#fff}.hero .text-block{max-width:550px;padding:0px 0px 10px 0px}.hero .text-block p{margin-bottom:20px;font-size:18px;color:#fff}.hero h2{font-size:36px}.hero.homepage{background-image:url(/img/hero-image.png);background-position:center center;background-repeat:no-repeat;background-size:cover;padding-bottom:80px}@media only screen and (max-width: 767px){.hero .text-block{max-width:unset;margin-right:0px}.hero .button{display:block;text-align:center}.hero.homepage{background-image:none}}.grid-container{margin-top:-80px}.grid-container .grid.three{padding-bottom:20px}.grid-container .grid.three .card{position:relative;padding:30px 20px;background-color:#fff;text-align:center;box-shadow:0px 2px 10px rgba(0,0,0,0.2)}.grid-container .grid.three .card h3{color:#333;font-size:22px}.grid-container .grid.three .card p{color:#333}.introduction .grid.two{column-gap:140px;padding:35px 20px}.introduction .grid.two p{margin:0px;font-size:16px}.introduction .grid.two p.strong{color:#333}@media only screen and (max-width: 767px){.introduction{padding:0px 20px}.introduction .col:first-of-type{padding-bottom:50px}}.use-cases .grid{grid-template-columns:220px 1fr;margin-bottom:30px;grid-template-areas:"image text"}.use-cases .grid .image{background-color:#0091DA;text-align:center;display:flex;align-items:center;justify-content:center;grid-area:image}.use-cases .grid .image img{justify-self:center}.use-cases .grid .text{border:1px solid #F2F2F2;padding:30px;grid-area:text}.use-cases .grid .text a.button{display:block;max-width:138px;text-align:center;padding:5px 10px;min-width:unset}.use-cases .grid.image-right{grid-template-columns:1fr 220px;grid-template-areas:"text image"}@media only screen and (max-width: 767px){.use-cases .grid.image-right{grid-template-columns:1fr;grid-template-areas:"image" "text"}}@media only screen and (max-width: 767px){.use-cases .grid{grid-template-columns:1fr;grid-template-rows:minmax(160px, 1fr);grid-template-areas:"image" "text"}}.use-cases h2{color:#111}.use-cases p.strong{color:#1B3951;font-size:16px}.team{background-color:#1D428A}.team h2,.team h3,.team p{color:#fff}.team p{font-size:16px}.team a{color:#fff;font-weight:300;text-decoration:underline}.team .grid.three{row-gap:40px;margin:40px 0px}.team .bio{display:grid;grid-template-columns:120px 1fr;column-gap:20px}.team .bio .info{align-self:center}.team .bio .info p{margin:0px}.team .bio .info p.name{font-size:16px;font-family:"Metropolis-Medium",Helvetica,sans-serif}.team .bio .info p.position{font-size:14px}.hero.subpage{background-image:url(/img/blog-hero-image.png);background-position:center center;background-repeat:no-repeat;background-size:cover;padding-bottom:140px}.experimental .grid.three .col{padding:0px}.experimental .icon{background-color:#0091DA;padding:25px;min-height:95px;display:flex;align-items:center;justify-content:center}.experimental .content{padding:25px}.experimental .content .example{background-color:#F2F2F2}.blog{padding-bottom:50px}.blog .col{border:1px solid #F2F2F2}.blog .col img{width:100%}.blog .col .content{padding:0px 20px}.blog.landing{background-color:#fff;margin-top:-90px}.blog.landing h3 a{font-size:16px}.blog.landing .pagination{margin:30px auto 50px auto}.blog.landing .pagination ul{padding:0px;text-align:center}.blog.landing .pagination ul li{padding:0px}.blog.landing .pagination ul li a{padding:5px 10px}.blog.landing .pagination ul li a.active{background-color:#F2F2F2;border-radius:50%}.blog.landing .pagination ul li.left-arrow{margin-right:15px}.blog.landing .pagination ul li.right-arrow{margin-left:15px}.blog .blog-post{background-color:#fff;margin:-110px 0px 0px -30px;padding:30px 90px 30px 30px}.blog .blog-post .author{color:#0095D3;margin:0px}.blog .blog-post .date{color:#111;margin:0px;font-weight:600}.blog .blog-post .header,.blog .blog-post h4{color:#111;font-weight:600}.blog .blog-post a{font-size:16px}.blog .blog-post ul{list-style-type:disc;padding-left:20px}.blog .blog-post ul li:first-child{margin-top:10px}.blog .blog-post ul li{list-style-type:unset;display:list-item;margin-bottom:10px;font-size:14px;color:#333;line-height:1.6em;list-style-image:url(/img/arrow.svg)}.blog .blog-post ol li:first-child{margin-top:10px}.blog .blog-post ol li{list-style-type:decimal;display:list-item;margin-bottom:10px;font-size:16px;color:#333}.blog .blog-post code{background-color:#fff;color:#333;border:2px solid #EFEFEF;padding:2px 8px}.blog .blog-post code .c1{color:#0095D3;font-style:italic}.blog .blog-post code .se{color:#ff0000}.blog .blog-post pre{white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word}.blog .blog-post pre code{display:block;border:15px solid #EFEFEF;padding:15px;margin-bottom:30px}.blog .blog-post img{max-width:100%}.blog .blog-post strong{font-family:"Metropolis-Medium",Helvetica,sans-serif}.getting-started{background-color:#F2F2F2;color:#111}.getting-started p{color:#111;font-size:16px}.getting-started .left-side{width:50%;float:left}.getting-started .right-side{width:25%;float:right}.getting-started h2{font-size:30px;margin-bottom:0px}.getting-started a{display:block;max-width:138px;text-align:center;padding:10px;min-width:unset}.getting-started .button{margin-top:50px;border:1px solid #0095D3}@media only screen and (max-width: 767px){.getting-started .wrapper{padding-bottom:40px}.getting-started .left-side{width:100%;float:none}.getting-started .right-side{width:100%;float:none}.getting-started .button{display:block;text-align:center;max-width:unset;margin-top:20px}}.community{background-color:#fff;margin-top:-90px;padding:30px 30px 50px 30px}.community .grid .col{border:1px solid #F2F2F2}.community .grid .col .icon{display:flex;align-items:center;justify-content:center;min-height:140px}.community .grid .col .content{padding:0px 20px 20px 20px;text-align:center}.community .grid .col .content h3{margin-top:0px}.docs{background-color:#fff;margin-top:-90px;padding:30px 30px 50px 30px}.docs .side-nav{width:25%;float:left}.docs .side-nav ul{padding-left:0px;margin-bottom:35px}.docs .side-nav ul ul{padding-left:15px;margin-top:10px;margin-bottom:15px}.docs .side-nav ul li{display:list-item;margin-bottom:15px}.docs .side-nav ul li a{color:#333;font-size:14px}.docs .side-nav ul li a.active{color:#0095D3}.docs .side-nav ul li.heading{color:#111;font-size:14px}.docs .docs-content{width:75%;float:right}.docs .docs-content a{font-size:14px}.docs .docs-content ul{list-style-type:disc;padding-left:20px}.docs .docs-content ul li:first-child{margin-top:10px}.docs .docs-content ul li{list-style-type:unset;display:list-item;margin-bottom:10px;font-size:16px;color:#333;line-height:1.6em;list-style-image:url(/img/arrow.svg)}.docs .docs-content ol li:first-child{margin-top:10px}.docs .docs-content ol li{list-style-type:decimal;display:list-item;margin-bottom:10px;font-size:16px;color:#333}.docs .docs-content code{background-color:#fff;color:#333;border:2px solid #EFEFEF;padding:2px 8px}.docs .docs-content code .c1{color:#0095D3;font-style:italic}.docs .docs-content code .se{color:#ff0000}.docs .docs-content pre{white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word}.docs .docs-content pre code{display:block;border:15px solid #EFEFEF;padding:15px;margin-bottom:30px}.docs .docs-content img{max-width:100%}.chroma{color:#272822;background-color:#fafafa}.chroma .err{color:#960050;background-color:#1e0010}.chroma .lntd{vertical-align:top;padding:0;margin:0;border:0}.chroma .lntable{border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block}.chroma .hl{display:block;width:100%;background-color:#ffffcc}.chroma .lnt{margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f}.chroma .ln{margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f}.chroma .k{color:#00a8c8}.chroma .kc{color:#00a8c8}.chroma .kd{color:#00a8c8}.chroma .kn{color:#f92672}.chroma .kp{color:#00a8c8}.chroma .kr{color:#00a8c8}.chroma .kt{color:#00a8c8}.chroma .n{color:#111111}.chroma .na{color:#75af00}.chroma .nb{color:#111111}.chroma .bp{color:#111111}.chroma .nc{color:#75af00}.chroma .no{color:#00a8c8}.chroma .nd{color:#75af00}.chroma .ni{color:#111111}.chroma .ne{color:#75af00}.chroma .nf{color:#75af00}.chroma .fm{color:#111111}.chroma .nl{color:#111111}.chroma .nn{color:#111111}.chroma .nx{color:#75af00}.chroma .py{color:#111111}.chroma .nt{color:#f92672}.chroma .nv{color:#111111}.chroma .vc{color:#111111}.chroma .vg{color:#111111}.chroma .vi{color:#111111}.chroma .vm{color:#111111}.chroma .l{color:#ae81ff}.chroma .ld{color:#d88200}.chroma .s{color:#d88200}.chroma .sa{color:#d88200}.chroma .sb{color:#d88200}.chroma .sc{color:#d88200}.chroma .dl{color:#d88200}.chroma .sd{color:#d88200}.chroma .s2{color:#d88200}.chroma .se{color:#8045ff}.chroma .sh{color:#d88200}.chroma .si{color:#d88200}.chroma .sx{color:#d88200}.chroma .sr{color:#d88200}.chroma .s1{color:#d88200}.chroma .ss{color:#d88200}.chroma .m{color:#ae81ff}.chroma .mb{color:#ae81ff}.chroma .mf{color:#ae81ff}.chroma .mh{color:#ae81ff}.chroma .mi{color:#ae81ff}.chroma .il{color:#ae81ff}.chroma .mo{color:#ae81ff}.chroma .o{color:#f92672}.chroma .ow{color:#f92672}.chroma .p{color:#111111}.chroma .c{color:#75715e}.chroma .ch{color:#75715e}.chroma .cm{color:#75715e}.chroma .c1{color:#75715e}.chroma .cs{color:#75715e}.chroma .cp{color:#75715e}.chroma .cpf{color:#75715e}.chroma .ge{font-style:italic}.chroma .gs{font-weight:bold} +body{font-family:"Metropolis-Light",Helvetica,sans-serif;margin:0px;line-height:1.25}.wrapper{max-width:980px;margin:0px auto;padding:20px}@media only screen and (max-width: 767px){.wrapper{max-width:100%}}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0}.clearfix:after{clear:both}h1,h2,h3,h4,h5,h6{font-weight:300}h1{font-size:36px}h2{font-size:28px}h3{font-size:22px}h4{font-size:18px}li{list-style-type:none;display:inline;padding-right:25px;font-size:14px;line-height:1.7em}li:last-of-type{padding-right:0px}p{line-height:1.7em;font-weight:300;font-size:16px;color:#333}a{font-size:16px;text-decoration:none;color:#0095D3;font-family:"Metropolis-Medium",Helvetica,sans-serif}button{background-color:unset;border:none}.button{color:#0095D3;font-size:12px;font-weight:600;background-color:#fff;border-radius:3px;padding:14px 10px;min-width:200px;text-transform:uppercase;border:1px solid #fff}.button.secondary{background-color:#0091DA;color:#fff}.button.tertiary{border:1px solid #0095D3}.button img.button-icon{margin-left:5px;margin-right:5px;margin-bottom:-8px;width:24px;height:24px}.buttons{margin-top:40px}.buttons .button:first-of-type{margin-right:30px}@media only screen and (max-width: 767px){.buttons .button:first-of-type{margin:0px 0px 20px 0px}}.strong{font-family:"Metropolis-Medium",Helvetica,sans-serif}.bg-grey{background-color:#F2F2F2}.grid.three{display:grid;grid-template-columns:1fr 1fr 1fr;row-gap:20px;column-gap:20px}@media only screen and (max-width: 767px){.grid.three{grid-template-columns:1fr}}.grid.two{display:grid;grid-template-columns:1fr 1fr}@media only screen and (max-width: 767px){.grid.two{grid-template-columns:1fr}}@font-face{font-family:"Metropolis-Bold";src:url("/fonts/Metropolis-Bold.eot");src:url("/fonts/Metropolis-Bold.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Bold.woff2") format("woff2"),url("/fonts/Metropolis-Bold.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-BoldItalic";src:url("/fonts/Metropolis-BoldItalic.eot");src:url("/fonts/Metropolis-BoldItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-BoldItalic.woff2") format("woff2"),url("/fonts/Metropolis-BoldItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Light";src:url("/fonts/Metropolis-Light.eot");src:url("/fonts/Metropolis-Light.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Light.woff2") format("woff2"),url("/fonts/Metropolis-Light.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-LightItalic";src:url("/fonts/Metropolis-LightItalic.eot");src:url("/fonts/Metropolis-LightItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-LightItalic.woff2") format("woff2"),url("/fonts/Metropolis-LightItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Regular";src:url("/fonts/Metropolis-Regular.eot");src:url("/fonts/Metropolis-Regular.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Regular.woff2") format("woff2"),url("/fonts/Metropolis-Regular.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-RegularItalic";src:url("/fonts/Metropolis-RegularItalic.eot");src:url("/fonts/Metropolis-RegularItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-RegularItalic.woff2") format("woff2"),url("/fonts/Metropolis-RegularItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Medium";src:url("/fonts/Metropolis-Medium.eot");src:url("/fonts/Metropolis-Medium.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Medium.woff2") format("woff2"),url("/fonts/Metropolis-Medium.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-MediumItalic";src:url("/fonts/Metropolis-MediumItalic.eot");src:url("/fonts/Metropolis-MediumItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-MediumItalic.woff2") format("woff2"),url("/fonts/Metropolis-MediumItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-SemiBold";src:url("/fonts/Metropolis-SemiBold.eot");src:url("/fonts/Metropolis-SemiBold.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-SemiBold.woff2") format("woff2"),url("/fonts/Metropolis-SemiBold.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-SemiBoldItalic";src:url("/fonts/Metropolis-SemiBoldItalic.eot");src:url("/fonts/Metropolis-SemiBoldItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-SemiBoldItalic.woff2") format("woff2"),url("/fonts/Metropolis-SemiBoldItalic.woff") format("woff");font-weight:normal;font-style:normal}header .wrapper{padding:10px 20px}header .desktop-links{float:right;margin:15px 0px 0px 0px;padding-left:0px}header a{color:#333;font-family:"Metropolis-Light",Helvetica,sans-serif}header a.active{font-family:"Metropolis-Medium",Helvetica,sans-serif}header li img{vertical-align:bottom;margin-right:10px}header .mobile{display:none}@media only screen and (min-width: 768px) and (max-width: 1279px){header .desktop-links li{padding-right:10px}}@media only screen and (max-width: 767px){header{position:relative}header .expanded-icon{display:none;padding:11px 3px 0px 0px}header .collapsed-icon{padding-top:12px}header .mobile-menu-visible .mobile{display:block}header .mobile-menu-visible .mobile .collapsed-icon{display:none}header .mobile-menu-visible .mobile .expanded-icon{display:block}header .desktop-links{display:none}header .mobile{display:block}header button{float:right}header button:focus{outline:none}header ul{padding-left:0px}header ul li{display:block;margin:20px 0px}header .mobile-menu{position:absolute;background-color:#fff;width:100%;top:70px;left:0px;padding-bottom:20px;display:none}header .mobile-menu .header-links{margin:0px 20px}header .mobile-menu .social{margin:0px 20px;padding-top:20px}header .mobile-menu .social img{vertical-align:middle;padding-right:10px}header .mobile-menu .social a{font-size:14px;padding-right:35px}header .mobile-menu .social a:last-of-type{padding-right:0px}}body{font-family:"Metropolis-Light",Helvetica,sans-serif;margin:0px;line-height:1.25}.wrapper{max-width:980px;margin:0px auto;padding:20px}@media only screen and (max-width: 767px){.wrapper{max-width:100%}}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0}.clearfix:after{clear:both}h1,h2,h3,h4,h5,h6{font-weight:300}h1{font-size:36px}h2{font-size:28px}h3{font-size:22px}h4{font-size:18px}li{list-style-type:none;display:inline;padding-right:25px;font-size:14px;line-height:1.7em}li:last-of-type{padding-right:0px}p{line-height:1.7em;font-weight:300;font-size:16px;color:#333}a{font-size:16px;text-decoration:none;color:#0095D3;font-family:"Metropolis-Medium",Helvetica,sans-serif}button{background-color:unset;border:none}.button{color:#0095D3;font-size:12px;font-weight:600;background-color:#fff;border-radius:3px;padding:14px 10px;min-width:200px;text-transform:uppercase;border:1px solid #fff}.button.secondary{background-color:#0091DA;color:#fff}.button.tertiary{border:1px solid #0095D3}.button img.button-icon{margin-left:5px;margin-right:5px;margin-bottom:-8px;width:24px;height:24px}.buttons{margin-top:40px}.buttons .button:first-of-type{margin-right:30px}@media only screen and (max-width: 767px){.buttons .button:first-of-type{margin:0px 0px 20px 0px}}.strong{font-family:"Metropolis-Medium",Helvetica,sans-serif}.bg-grey{background-color:#F2F2F2}.grid.three{display:grid;grid-template-columns:1fr 1fr 1fr;row-gap:20px;column-gap:20px}@media only screen and (max-width: 767px){.grid.three{grid-template-columns:1fr}}.grid.two{display:grid;grid-template-columns:1fr 1fr}@media only screen and (max-width: 767px){.grid.two{grid-template-columns:1fr}}@font-face{font-family:"Metropolis-Bold";src:url("/fonts/Metropolis-Bold.eot");src:url("/fonts/Metropolis-Bold.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Bold.woff2") format("woff2"),url("/fonts/Metropolis-Bold.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-BoldItalic";src:url("/fonts/Metropolis-BoldItalic.eot");src:url("/fonts/Metropolis-BoldItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-BoldItalic.woff2") format("woff2"),url("/fonts/Metropolis-BoldItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Light";src:url("/fonts/Metropolis-Light.eot");src:url("/fonts/Metropolis-Light.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Light.woff2") format("woff2"),url("/fonts/Metropolis-Light.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-LightItalic";src:url("/fonts/Metropolis-LightItalic.eot");src:url("/fonts/Metropolis-LightItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-LightItalic.woff2") format("woff2"),url("/fonts/Metropolis-LightItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Regular";src:url("/fonts/Metropolis-Regular.eot");src:url("/fonts/Metropolis-Regular.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Regular.woff2") format("woff2"),url("/fonts/Metropolis-Regular.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-RegularItalic";src:url("/fonts/Metropolis-RegularItalic.eot");src:url("/fonts/Metropolis-RegularItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-RegularItalic.woff2") format("woff2"),url("/fonts/Metropolis-RegularItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Medium";src:url("/fonts/Metropolis-Medium.eot");src:url("/fonts/Metropolis-Medium.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Medium.woff2") format("woff2"),url("/fonts/Metropolis-Medium.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-MediumItalic";src:url("/fonts/Metropolis-MediumItalic.eot");src:url("/fonts/Metropolis-MediumItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-MediumItalic.woff2") format("woff2"),url("/fonts/Metropolis-MediumItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-SemiBold";src:url("/fonts/Metropolis-SemiBold.eot");src:url("/fonts/Metropolis-SemiBold.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-SemiBold.woff2") format("woff2"),url("/fonts/Metropolis-SemiBold.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-SemiBoldItalic";src:url("/fonts/Metropolis-SemiBoldItalic.eot");src:url("/fonts/Metropolis-SemiBoldItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-SemiBoldItalic.woff2") format("woff2"),url("/fonts/Metropolis-SemiBoldItalic.woff") format("woff");font-weight:normal;font-style:normal}footer .left-links{padding:0px;float:left}footer .left-links li img{vertical-align:bottom;margin-right:10px}footer .left-links li a{color:#333;font-weight:300;font-size:12px;font-family:"Metropolis-Light",Helvetica,sans-serif}footer .right-links{float:right}footer .right-links p{margin:0px}footer .right-links .copywrite{font-size:12px;padding-right:10px}footer .right-links .copywrite a{font-size:12px;color:#333;font-family:"Metropolis-Light",Helvetica,sans-serif}footer .right-links a{vertical-align:middle}@media only screen and (max-width: 767px){footer .left-links{width:100%;float:none}footer .left-links li{display:block;width:33%;float:left;padding-right:0px}footer .right-links{width:100%;padding-top:20px}footer .right-links .image{display:none}}body{font-family:"Metropolis-Light",Helvetica,sans-serif;margin:0px;line-height:1.25}.wrapper{max-width:980px;margin:0px auto;padding:20px}@media only screen and (max-width: 767px){.wrapper{max-width:100%}}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0}.clearfix:after{clear:both}h1,h2,h3,h4,h5,h6{font-weight:300}h1{font-size:36px}h2{font-size:28px}h3{font-size:22px}h4{font-size:18px}li{list-style-type:none;display:inline;padding-right:25px;font-size:14px;line-height:1.7em}li:last-of-type{padding-right:0px}p{line-height:1.7em;font-weight:300;font-size:16px;color:#333}a{font-size:16px;text-decoration:none;color:#0095D3;font-family:"Metropolis-Medium",Helvetica,sans-serif}button{background-color:unset;border:none}.button{color:#0095D3;font-size:12px;font-weight:600;background-color:#fff;border-radius:3px;padding:14px 10px;min-width:200px;text-transform:uppercase;border:1px solid #fff}.button.secondary{background-color:#0091DA;color:#fff}.button.tertiary{border:1px solid #0095D3}.button img.button-icon{margin-left:5px;margin-right:5px;margin-bottom:-8px;width:24px;height:24px}.buttons{margin-top:40px}.buttons .button:first-of-type{margin-right:30px}@media only screen and (max-width: 767px){.buttons .button:first-of-type{margin:0px 0px 20px 0px}}.strong{font-family:"Metropolis-Medium",Helvetica,sans-serif}.bg-grey{background-color:#F2F2F2}.grid.three{display:grid;grid-template-columns:1fr 1fr 1fr;row-gap:20px;column-gap:20px}@media only screen and (max-width: 767px){.grid.three{grid-template-columns:1fr}}.grid.two{display:grid;grid-template-columns:1fr 1fr}@media only screen and (max-width: 767px){.grid.two{grid-template-columns:1fr}}@font-face{font-family:"Metropolis-Bold";src:url("/fonts/Metropolis-Bold.eot");src:url("/fonts/Metropolis-Bold.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Bold.woff2") format("woff2"),url("/fonts/Metropolis-Bold.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-BoldItalic";src:url("/fonts/Metropolis-BoldItalic.eot");src:url("/fonts/Metropolis-BoldItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-BoldItalic.woff2") format("woff2"),url("/fonts/Metropolis-BoldItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Light";src:url("/fonts/Metropolis-Light.eot");src:url("/fonts/Metropolis-Light.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Light.woff2") format("woff2"),url("/fonts/Metropolis-Light.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-LightItalic";src:url("/fonts/Metropolis-LightItalic.eot");src:url("/fonts/Metropolis-LightItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-LightItalic.woff2") format("woff2"),url("/fonts/Metropolis-LightItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Regular";src:url("/fonts/Metropolis-Regular.eot");src:url("/fonts/Metropolis-Regular.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Regular.woff2") format("woff2"),url("/fonts/Metropolis-Regular.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-RegularItalic";src:url("/fonts/Metropolis-RegularItalic.eot");src:url("/fonts/Metropolis-RegularItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-RegularItalic.woff2") format("woff2"),url("/fonts/Metropolis-RegularItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Medium";src:url("/fonts/Metropolis-Medium.eot");src:url("/fonts/Metropolis-Medium.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Medium.woff2") format("woff2"),url("/fonts/Metropolis-Medium.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-MediumItalic";src:url("/fonts/Metropolis-MediumItalic.eot");src:url("/fonts/Metropolis-MediumItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-MediumItalic.woff2") format("woff2"),url("/fonts/Metropolis-MediumItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-SemiBold";src:url("/fonts/Metropolis-SemiBold.eot");src:url("/fonts/Metropolis-SemiBold.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-SemiBold.woff2") format("woff2"),url("/fonts/Metropolis-SemiBold.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-SemiBoldItalic";src:url("/fonts/Metropolis-SemiBoldItalic.eot");src:url("/fonts/Metropolis-SemiBoldItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-SemiBoldItalic.woff2") format("woff2"),url("/fonts/Metropolis-SemiBoldItalic.woff") format("woff");font-weight:normal;font-style:normal}.hero{background-color:#0091DA;color:#fff}.hero .text-block{max-width:550px;padding:0px 0px 10px 0px}.hero .text-block p{margin-bottom:20px;font-size:18px;color:#fff}.hero h2{font-size:36px}.hero.homepage{background-image:url(/img/hero-image.png);background-position:center center;background-repeat:no-repeat;background-size:cover;padding-bottom:80px}@media only screen and (max-width: 767px){.hero .text-block{max-width:unset;margin-right:0px}.hero .button{display:block;text-align:center}.hero.homepage{background-image:none}}.grid-container{margin-top:-80px}.grid-container .grid.three{padding-bottom:20px}.grid-container .grid.three .card{position:relative;padding:30px 20px;background-color:#fff;text-align:center;box-shadow:0px 2px 10px rgba(0,0,0,0.2)}.grid-container .grid.three .card h3{color:#333;font-size:22px}.grid-container .grid.three .card p{color:#333}.introduction .grid.two{column-gap:140px;padding:35px 20px}.introduction .grid.two p{margin:0px;font-size:16px}.introduction .grid.two p.strong{color:#333}@media only screen and (max-width: 767px){.introduction{padding:0px 20px}.introduction .col:first-of-type{padding-bottom:50px}}.use-cases .grid{grid-template-columns:220px 1fr;margin-bottom:30px;grid-template-areas:"image text"}.use-cases .grid .image{background-color:#0091DA;text-align:center;display:flex;align-items:center;justify-content:center;grid-area:image}.use-cases .grid .image img{justify-self:center}.use-cases .grid .text{border:1px solid #F2F2F2;padding:30px;grid-area:text}.use-cases .grid .text a.button{display:block;max-width:138px;text-align:center;padding:5px 10px;min-width:unset}.use-cases .grid.image-right{grid-template-columns:1fr 220px;grid-template-areas:"text image"}@media only screen and (max-width: 767px){.use-cases .grid.image-right{grid-template-columns:1fr;grid-template-areas:"image" "text"}}@media only screen and (max-width: 767px){.use-cases .grid{grid-template-columns:1fr;grid-template-rows:minmax(160px, 1fr);grid-template-areas:"image" "text"}}.use-cases h2{color:#111}.use-cases p.strong{color:#1B3951;font-size:16px}.team{background-color:#1D428A}.team h2,.team h3,.team p{color:#fff}.team p{font-size:16px}.team a{color:#fff;font-weight:300;text-decoration:underline}.team .grid.three{row-gap:40px;margin:40px 0px}.team .bio{display:grid;grid-template-columns:120px 1fr;column-gap:20px}.team .bio .info{align-self:center}.team .bio .info p{margin:0px}.team .bio .info p.name{font-size:16px;font-family:"Metropolis-Medium",Helvetica,sans-serif}.team .bio .info p.position{font-size:14px}.hero.subpage{background-image:url(/img/blog-hero-image.png);background-position:center center;background-repeat:no-repeat;background-size:cover;padding-bottom:140px}.experimental .grid.three .col{padding:0px}.experimental .icon{background-color:#0091DA;padding:25px;min-height:95px;display:flex;align-items:center;justify-content:center}.experimental .content{padding:25px}.experimental .content .example{background-color:#F2F2F2}.blog{padding-bottom:50px}.blog .col{border:1px solid #F2F2F2}.blog .col img{width:100%}.blog .col .content{padding:0px 20px}.blog.landing{background-color:#fff;margin-top:-90px}.blog.landing h3 a{font-size:16px}.blog.landing .pagination{margin:30px auto 50px auto}.blog.landing .pagination ul{padding:0px;text-align:center}.blog.landing .pagination ul li{padding:0px}.blog.landing .pagination ul li a{padding:5px 10px}.blog.landing .pagination ul li a.active{background-color:#F2F2F2;border-radius:50%}.blog.landing .pagination ul li.left-arrow{margin-right:15px}.blog.landing .pagination ul li.right-arrow{margin-left:15px}.blog .blog-post{background-color:#fff;margin:-110px 0px 0px -30px;padding:30px 90px 30px 30px}.blog .blog-post .author{color:#0095D3;margin:0px}.blog .blog-post .date{color:#111;margin:0px;font-weight:600}.blog .blog-post .header,.blog .blog-post h4{color:#111;font-weight:600}.blog .blog-post a{font-size:16px}.blog .blog-post ul{list-style-type:disc;padding-left:20px}.blog .blog-post ul li:first-child{margin-top:10px}.blog .blog-post ul li{list-style-type:unset;display:list-item;margin-bottom:10px;font-size:16px;color:#333;list-style-image:url(/img/arrow.svg)}.blog .blog-post ol li:first-child{margin-top:10px}.blog .blog-post ol li{list-style-type:decimal;display:list-item;margin-bottom:10px;font-size:16px;color:#333}.blog .blog-post code{background-color:#fff;color:#333;border:2px solid #EFEFEF;padding:2px 8px}.blog .blog-post code .c1{color:#0095D3;font-style:italic}.blog .blog-post code .se{color:#ff0000}.blog .blog-post pre{white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word}.blog .blog-post pre code{display:block;border:15px solid #EFEFEF;padding:15px;margin-bottom:30px}.blog .blog-post img{max-width:100%}.blog .blog-post strong{font-family:"Metropolis-Medium",Helvetica,sans-serif}.getting-started{background-color:#F2F2F2;color:#111}.getting-started p{color:#111;font-size:16px}.getting-started .left-side{width:50%;float:left}.getting-started .right-side{width:25%;float:right}.getting-started h2{font-size:30px;margin-bottom:0px}.getting-started a{display:block;max-width:138px;text-align:center;padding:10px;min-width:unset}.getting-started .button{margin-top:50px;border:1px solid #0095D3}@media only screen and (max-width: 767px){.getting-started .wrapper{padding-bottom:40px}.getting-started .left-side{width:100%;float:none}.getting-started .right-side{width:100%;float:none}.getting-started .button{display:block;text-align:center;max-width:unset;margin-top:20px}}.community{background-color:#fff;margin-top:-90px;padding:30px 30px 50px 30px}.community .grid .col{border:1px solid #F2F2F2}.community .grid .col .icon{display:flex;align-items:center;justify-content:center;min-height:140px}.community .grid .col .content{padding:0px 20px 20px 20px;text-align:center}.community .grid .col .content h3{margin-top:0px}.docs{background-color:#fff;margin-top:-90px;padding:30px 30px 50px 30px}.docs .side-nav{width:25%;float:left}.docs .side-nav ul{padding-left:0px;margin-bottom:35px}.docs .side-nav ul ul{padding-left:15px;margin-top:10px;margin-bottom:15px}.docs .side-nav ul li{display:list-item;margin-bottom:15px}.docs .side-nav ul li a{color:#333;font-size:14px}.docs .side-nav ul li a.active{color:#0095D3}.docs .side-nav ul li.heading{color:#111;font-size:14px}.docs .docs-content{width:75%;float:right}.docs .docs-content a{font-size:16px}.docs .docs-content ul{list-style-type:disc;padding-left:20px}.docs .docs-content ul li:first-child{margin-top:10px}.docs .docs-content ul li{list-style-type:unset;display:list-item;margin-bottom:10px;font-size:16px;color:#333;line-height:1.6em;list-style-image:url(/img/arrow.svg)}.docs .docs-content ol li:first-child{margin-top:10px}.docs .docs-content ol li{list-style-type:decimal;display:list-item;margin-bottom:10px;font-size:16px;color:#333}.docs .docs-content code{background-color:#fff;color:#333;border:2px solid #EFEFEF;padding:2px 8px}.docs .docs-content code .c1{color:#0095D3;font-style:italic}.docs .docs-content code .se{color:#ff0000}.docs .docs-content pre{white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word}.docs .docs-content pre code{display:block;border:15px solid #EFEFEF;padding:15px;margin-bottom:30px;font-size:14px}.docs .docs-content img{max-width:100%}.docs .docs-content strong{font-family:"Metropolis-Medium",Helvetica,sans-serif}.docs .danger{padding:10px;font-family:"Metropolis-LightItalic",Helvetica,sans-serif}.docs .danger .danger-icon{float:left;padding:40px;width:24px;height:24px}.docs .button a{font-size:14px}.docs table td{padding:10px 30px}.chroma{color:#272822;background-color:#fafafa}.chroma .err{color:#960050;background-color:#1e0010}.chroma .lntd{vertical-align:top;padding:0;margin:0;border:0}.chroma .lntable{border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block}.chroma .hl{display:block;width:100%;background-color:#ffffcc}.chroma .lnt{margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f}.chroma .ln{margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f}.chroma .k{color:#00a8c8}.chroma .kc{color:#00a8c8}.chroma .kd{color:#00a8c8}.chroma .kn{color:#f92672}.chroma .kp{color:#00a8c8}.chroma .kr{color:#00a8c8}.chroma .kt{color:#00a8c8}.chroma .n{color:#111111}.chroma .na{color:#75af00}.chroma .nb{color:#111111}.chroma .bp{color:#111111}.chroma .nc{color:#75af00}.chroma .no{color:#00a8c8}.chroma .nd{color:#75af00}.chroma .ni{color:#111111}.chroma .ne{color:#75af00}.chroma .nf{color:#75af00}.chroma .fm{color:#111111}.chroma .nl{color:#111111}.chroma .nn{color:#111111}.chroma .nx{color:#75af00}.chroma .py{color:#111111}.chroma .nt{color:#f92672}.chroma .nv{color:#111111}.chroma .vc{color:#111111}.chroma .vg{color:#111111}.chroma .vi{color:#111111}.chroma .vm{color:#111111}.chroma .l{color:#ae81ff}.chroma .ld{color:#d88200}.chroma .s{color:#d88200}.chroma .sa{color:#d88200}.chroma .sb{color:#d88200}.chroma .sc{color:#d88200}.chroma .dl{color:#d88200}.chroma .sd{color:#d88200}.chroma .s2{color:#d88200}.chroma .se{color:#8045ff}.chroma .sh{color:#d88200}.chroma .si{color:#d88200}.chroma .sx{color:#d88200}.chroma .sr{color:#d88200}.chroma .s1{color:#d88200}.chroma .ss{color:#d88200}.chroma .m{color:#ae81ff}.chroma .mb{color:#ae81ff}.chroma .mf{color:#ae81ff}.chroma .mh{color:#ae81ff}.chroma .mi{color:#ae81ff}.chroma .il{color:#ae81ff}.chroma .mo{color:#ae81ff}.chroma .o{color:#f92672}.chroma .ow{color:#f92672}.chroma .p{color:#111111}.chroma .c{color:#75715e}.chroma .ch{color:#75715e}.chroma .cm{color:#75715e}.chroma .c1{color:#75715e}.chroma .cs{color:#75715e}.chroma .cp{color:#75715e}.chroma .cpf{color:#75715e}.chroma .ge{font-style:italic}.chroma .gs{font-weight:bold} /*# sourceMappingURL=style.css.map */ \ No newline at end of file diff --git a/site/themes/pinniped/assets/scss/_base.scss b/site/themes/pinniped/assets/scss/_base.scss index f10c3d71..2b329929 100644 --- a/site/themes/pinniped/assets/scss/_base.scss +++ b/site/themes/pinniped/assets/scss/_base.scss @@ -97,6 +97,13 @@ button { &.tertiary { border: 1px solid $blue; } + img.button-icon { + margin-left: 5px; + margin-right: 5px; + margin-bottom: -8px; + width: 24px; + height: 24px; + } } .buttons { margin-top: 40px; diff --git a/site/themes/pinniped/assets/scss/_components.scss b/site/themes/pinniped/assets/scss/_components.scss index b62de86d..60b65d28 100644 --- a/site/themes/pinniped/assets/scss/_components.scss +++ b/site/themes/pinniped/assets/scss/_components.scss @@ -273,9 +273,8 @@ list-style-type: unset; display: list-item; margin-bottom: 10px; - font-size: 14px; + font-size: 16px; color: $darkgrey; - line-height: 1.6em; list-style-image: url(/img/arrow.svg); } } @@ -437,7 +436,7 @@ width: 75%; float: right; a { - font-size: 14px; + font-size: 16px; } ul { list-style-type: disc; @@ -491,10 +490,36 @@ border: 15px solid #EFEFEF; padding: 15px; margin-bottom: 30px; + font-size: 14px; } } img { max-width: 100%; } + strong { + font-family: $metropolis-medium; + } + } + .danger { + .danger-icon { + float: left; + padding: 40px; + width: 24px; + height: 24px; + } + padding: 10px; + font-family: $metropolis-light-italic; + } + + .button { + a { + font-size: 14px; + } + } + + table { + td { + padding: 10px 30px; + } } } \ No newline at end of file diff --git a/site/themes/pinniped/layouts/_default/docs.html b/site/themes/pinniped/layouts/_default/docs.html index 818bc2e5..c223ff91 100644 --- a/site/themes/pinniped/layouts/_default/docs.html +++ b/site/themes/pinniped/layouts/_default/docs.html @@ -7,8 +7,10 @@
{{ partial "docs-sidebar.html" . }} -
+ {{- with .Title -}} +

{{.}}

+ {{- end -}} {{ .Content }}
diff --git a/site/themes/pinniped/layouts/shortcodes/buttonicon.html b/site/themes/pinniped/layouts/shortcodes/buttonicon.html new file mode 100644 index 00000000..14458a77 --- /dev/null +++ b/site/themes/pinniped/layouts/shortcodes/buttonicon.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/site/themes/pinniped/layouts/shortcodes/buttonlink.html b/site/themes/pinniped/layouts/shortcodes/buttonlink.html new file mode 100644 index 00000000..7895fc5e --- /dev/null +++ b/site/themes/pinniped/layouts/shortcodes/buttonlink.html @@ -0,0 +1,2 @@ +{{- $href := .Get "href" -}} + \ No newline at end of file diff --git a/site/themes/pinniped/layouts/shortcodes/dangernote.html b/site/themes/pinniped/layouts/shortcodes/dangernote.html new file mode 100644 index 00000000..a97ae3df --- /dev/null +++ b/site/themes/pinniped/layouts/shortcodes/dangernote.html @@ -0,0 +1,4 @@ +
+ +

{{ .Inner | markdownify }}

+
diff --git a/site/themes/pinniped/layouts/shortcodes/docsmenu.html b/site/themes/pinniped/layouts/shortcodes/docsmenu.html new file mode 100644 index 00000000..13878b6b --- /dev/null +++ b/site/themes/pinniped/layouts/shortcodes/docsmenu.html @@ -0,0 +1,15 @@ +{{- $subsection := .Get 0 -}} +
    + {{- range .Site.Menus.docs -}} + {{- range .Children }} + {{- if eq $subsection .Parent -}} +
  • + {{- .Page.Title -}} + {{- with .Page.Description }} +

    {{ . | markdownify }}

    + {{- end -}} +
  • + {{- end -}} + {{- end -}} + {{- end }} +
diff --git a/site/themes/pinniped/static/img/alert-circle-outline.svg b/site/themes/pinniped/static/img/alert-circle-outline.svg new file mode 100644 index 00000000..de22ac8f --- /dev/null +++ b/site/themes/pinniped/static/img/alert-circle-outline.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/site/themes/pinniped/static/img/download.png b/site/themes/pinniped/static/img/download.png new file mode 100644 index 0000000000000000000000000000000000000000..c755780462831806550210b338c048e6b006a362 GIT binary patch literal 354 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjEa{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8ZKG?d}4kf#9d}?s_1_ zS>O>_45Sml_(QhSc_1Uj)5S5wW=Tc0|AxGQd9$jg%#&g2&Hm@IWr zJkP_}aoTeA@AmK9N*gj6EHYo{7C$$dI$w}=_8o~z_4z$DleH(Be)3CMyQfoR!HyH# zU2V26K5sgO^ZD(+AuRuc8FzJ`khcGuvkPdSYKdz^NlIc#s#S7PDv)9@GB7gKH89dO yv Date: Tue, 23 Feb 2021 13:55:42 -0600 Subject: [PATCH 05/11] More website tweaks. These are some more changes that came up when Pablo and I were reviewing the previous docs PR. In no particular order: - Fix "related posts" on the blog section, and hide the section if there are none. - Minor style changes to several pages (guided by various style guides). - Redirect the root of get.pinniped.dev to our main page (shouldn't really be hit, but it's nice to do something). - Add more mobile-friendly CSS for our docs. - Reword the "getting started" CTA, and hide it on the docs pages (you're already there). - Fix the "Learn how Pinniped provides identity services to Kubernetes" link on the landing page. - Add a date to our blog post cards. - Rewrite the hero text on the landing page. - Fix the docs link for the "Get Started with Pinniped" button on the landing page. - Rework the landing page grid text. - Add Margo and Nanci to the team section and sort it alphabetically. Signed-off-by: Matt Moyer --- site/config.yaml | 10 ++++++ site/content/community/_index.html | 2 +- site/content/posts/a-seal-of-approval.md | 2 +- site/redirects/get.pinniped.dev/netlify.toml | 5 +++ ...s_8967e03afb92eb0cac064520bf021ba2.content | 2 +- .../pinniped/assets/scss/_components.scss | 10 ++++++ .../pinniped/layouts/_default/baseof.html | 1 - .../pinniped/layouts/_default/posts.html | 3 +- .../pinniped/layouts/_default/section.html | 1 + .../pinniped/layouts/_default/single.html | 15 ++++---- .../themes/pinniped/layouts/_default/tag.html | 1 + site/themes/pinniped/layouts/index.html | 3 +- .../layouts/partials/blog-post-card.html | 1 + .../layouts/partials/getting-started.html | 4 +-- .../pinniped/layouts/partials/hero.html | 6 ++-- .../layouts/partials/homepage-grid.html | 6 ++-- .../pinniped/layouts/partials/team.html | 34 ++++++++++++------ .../pinniped/layouts/partials/use-cases.html | 12 +++---- .../pinniped/static/img/margo-crawford.png | Bin 0 -> 37975 bytes .../pinniped/static/img/nanci-lancaster.png | Bin 0 -> 31548 bytes 20 files changed, 81 insertions(+), 37 deletions(-) create mode 100644 site/themes/pinniped/static/img/margo-crawford.png create mode 100644 site/themes/pinniped/static/img/nanci-lancaster.png diff --git a/site/config.yaml b/site/config.yaml index 3e9754d5..406a5703 100644 --- a/site/config.yaml +++ b/site/config.yaml @@ -22,3 +22,13 @@ markup: noClasses: false style: monokailight tabWidth: 4 + +related: + includeNewer: true + indices: + - name: tags + weight: 50 + - name: date + weight: 50 + threshold: 0 + toLower: true \ No newline at end of file diff --git a/site/content/community/_index.html b/site/content/community/_index.html index d4c9aa60..04bc61c7 100644 --- a/site/content/community/_index.html +++ b/site/content/community/_index.html @@ -35,7 +35,7 @@ layout: section

}}">Community Meetings

-

Pinniped Community Meetings are held every 1st and 3rd Thursday of the month at 9AM PT / 12PM ET

+

Pinniped Community Meetings are held every first and third Thursday of the month at 9 AM PT / 12 PM ET

Join our Google Group to receive invites to the meeting

Watch previous community meetings on our YouTube playlist

diff --git a/site/content/posts/a-seal-of-approval.md b/site/content/posts/a-seal-of-approval.md index 5e9bb170..de93e6fd 100644 --- a/site/content/posts/a-seal-of-approval.md +++ b/site/content/posts/a-seal-of-approval.md @@ -5,7 +5,7 @@ date: 2020-11-12 author: Pablo Schuhmacher image: /img/logo.svg excerpt: "Pinniped intends to bring that dream state — log in once and you’re done — to reality." -tags: ['Pablo Schuhmacher'] +tags: ['Pablo Schuhmacher', 'release'] --- Kubernetes, containers, microservices: They’ve all turned conventional application development wisdom inside out. But for all the wonders introduced and new technologies released, there are still a few things that remain difficult, cumbersome, or just really really frustrating when it comes to Kubernetes. We have set out to make one of those things easier and more understandable: authentication. diff --git a/site/redirects/get.pinniped.dev/netlify.toml b/site/redirects/get.pinniped.dev/netlify.toml index 2618e31f..2e7d89ac 100644 --- a/site/redirects/get.pinniped.dev/netlify.toml +++ b/site/redirects/get.pinniped.dev/netlify.toml @@ -1,3 +1,8 @@ +[[redirects]] + from = "/" + to = "https://pinniped.dev" + status = 302 + force = true [[redirects]] from = "/latest/*" diff --git a/site/resources/_gen/assets/scss/scss/site.scss_8967e03afb92eb0cac064520bf021ba2.content b/site/resources/_gen/assets/scss/scss/site.scss_8967e03afb92eb0cac064520bf021ba2.content index 25ab9b43..7e34aa0e 100644 --- a/site/resources/_gen/assets/scss/scss/site.scss_8967e03afb92eb0cac064520bf021ba2.content +++ b/site/resources/_gen/assets/scss/scss/site.scss_8967e03afb92eb0cac064520bf021ba2.content @@ -1,3 +1,3 @@ -body{font-family:"Metropolis-Light",Helvetica,sans-serif;margin:0px;line-height:1.25}.wrapper{max-width:980px;margin:0px auto;padding:20px}@media only screen and (max-width: 767px){.wrapper{max-width:100%}}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0}.clearfix:after{clear:both}h1,h2,h3,h4,h5,h6{font-weight:300}h1{font-size:36px}h2{font-size:28px}h3{font-size:22px}h4{font-size:18px}li{list-style-type:none;display:inline;padding-right:25px;font-size:14px;line-height:1.7em}li:last-of-type{padding-right:0px}p{line-height:1.7em;font-weight:300;font-size:16px;color:#333}a{font-size:16px;text-decoration:none;color:#0095D3;font-family:"Metropolis-Medium",Helvetica,sans-serif}button{background-color:unset;border:none}.button{color:#0095D3;font-size:12px;font-weight:600;background-color:#fff;border-radius:3px;padding:14px 10px;min-width:200px;text-transform:uppercase;border:1px solid #fff}.button.secondary{background-color:#0091DA;color:#fff}.button.tertiary{border:1px solid #0095D3}.button img.button-icon{margin-left:5px;margin-right:5px;margin-bottom:-8px;width:24px;height:24px}.buttons{margin-top:40px}.buttons .button:first-of-type{margin-right:30px}@media only screen and (max-width: 767px){.buttons .button:first-of-type{margin:0px 0px 20px 0px}}.strong{font-family:"Metropolis-Medium",Helvetica,sans-serif}.bg-grey{background-color:#F2F2F2}.grid.three{display:grid;grid-template-columns:1fr 1fr 1fr;row-gap:20px;column-gap:20px}@media only screen and (max-width: 767px){.grid.three{grid-template-columns:1fr}}.grid.two{display:grid;grid-template-columns:1fr 1fr}@media only screen and (max-width: 767px){.grid.two{grid-template-columns:1fr}}@font-face{font-family:"Metropolis-Bold";src:url("/fonts/Metropolis-Bold.eot");src:url("/fonts/Metropolis-Bold.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Bold.woff2") format("woff2"),url("/fonts/Metropolis-Bold.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-BoldItalic";src:url("/fonts/Metropolis-BoldItalic.eot");src:url("/fonts/Metropolis-BoldItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-BoldItalic.woff2") format("woff2"),url("/fonts/Metropolis-BoldItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Light";src:url("/fonts/Metropolis-Light.eot");src:url("/fonts/Metropolis-Light.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Light.woff2") format("woff2"),url("/fonts/Metropolis-Light.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-LightItalic";src:url("/fonts/Metropolis-LightItalic.eot");src:url("/fonts/Metropolis-LightItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-LightItalic.woff2") format("woff2"),url("/fonts/Metropolis-LightItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Regular";src:url("/fonts/Metropolis-Regular.eot");src:url("/fonts/Metropolis-Regular.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Regular.woff2") format("woff2"),url("/fonts/Metropolis-Regular.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-RegularItalic";src:url("/fonts/Metropolis-RegularItalic.eot");src:url("/fonts/Metropolis-RegularItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-RegularItalic.woff2") format("woff2"),url("/fonts/Metropolis-RegularItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Medium";src:url("/fonts/Metropolis-Medium.eot");src:url("/fonts/Metropolis-Medium.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Medium.woff2") format("woff2"),url("/fonts/Metropolis-Medium.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-MediumItalic";src:url("/fonts/Metropolis-MediumItalic.eot");src:url("/fonts/Metropolis-MediumItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-MediumItalic.woff2") format("woff2"),url("/fonts/Metropolis-MediumItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-SemiBold";src:url("/fonts/Metropolis-SemiBold.eot");src:url("/fonts/Metropolis-SemiBold.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-SemiBold.woff2") format("woff2"),url("/fonts/Metropolis-SemiBold.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-SemiBoldItalic";src:url("/fonts/Metropolis-SemiBoldItalic.eot");src:url("/fonts/Metropolis-SemiBoldItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-SemiBoldItalic.woff2") format("woff2"),url("/fonts/Metropolis-SemiBoldItalic.woff") format("woff");font-weight:normal;font-style:normal}header .wrapper{padding:10px 20px}header .desktop-links{float:right;margin:15px 0px 0px 0px;padding-left:0px}header a{color:#333;font-family:"Metropolis-Light",Helvetica,sans-serif}header a.active{font-family:"Metropolis-Medium",Helvetica,sans-serif}header li img{vertical-align:bottom;margin-right:10px}header .mobile{display:none}@media only screen and (min-width: 768px) and (max-width: 1279px){header .desktop-links li{padding-right:10px}}@media only screen and (max-width: 767px){header{position:relative}header .expanded-icon{display:none;padding:11px 3px 0px 0px}header .collapsed-icon{padding-top:12px}header .mobile-menu-visible .mobile{display:block}header .mobile-menu-visible .mobile .collapsed-icon{display:none}header .mobile-menu-visible .mobile .expanded-icon{display:block}header .desktop-links{display:none}header .mobile{display:block}header button{float:right}header button:focus{outline:none}header ul{padding-left:0px}header ul li{display:block;margin:20px 0px}header .mobile-menu{position:absolute;background-color:#fff;width:100%;top:70px;left:0px;padding-bottom:20px;display:none}header .mobile-menu .header-links{margin:0px 20px}header .mobile-menu .social{margin:0px 20px;padding-top:20px}header .mobile-menu .social img{vertical-align:middle;padding-right:10px}header .mobile-menu .social a{font-size:14px;padding-right:35px}header .mobile-menu .social a:last-of-type{padding-right:0px}}body{font-family:"Metropolis-Light",Helvetica,sans-serif;margin:0px;line-height:1.25}.wrapper{max-width:980px;margin:0px auto;padding:20px}@media only screen and (max-width: 767px){.wrapper{max-width:100%}}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0}.clearfix:after{clear:both}h1,h2,h3,h4,h5,h6{font-weight:300}h1{font-size:36px}h2{font-size:28px}h3{font-size:22px}h4{font-size:18px}li{list-style-type:none;display:inline;padding-right:25px;font-size:14px;line-height:1.7em}li:last-of-type{padding-right:0px}p{line-height:1.7em;font-weight:300;font-size:16px;color:#333}a{font-size:16px;text-decoration:none;color:#0095D3;font-family:"Metropolis-Medium",Helvetica,sans-serif}button{background-color:unset;border:none}.button{color:#0095D3;font-size:12px;font-weight:600;background-color:#fff;border-radius:3px;padding:14px 10px;min-width:200px;text-transform:uppercase;border:1px solid #fff}.button.secondary{background-color:#0091DA;color:#fff}.button.tertiary{border:1px solid #0095D3}.button img.button-icon{margin-left:5px;margin-right:5px;margin-bottom:-8px;width:24px;height:24px}.buttons{margin-top:40px}.buttons .button:first-of-type{margin-right:30px}@media only screen and (max-width: 767px){.buttons .button:first-of-type{margin:0px 0px 20px 0px}}.strong{font-family:"Metropolis-Medium",Helvetica,sans-serif}.bg-grey{background-color:#F2F2F2}.grid.three{display:grid;grid-template-columns:1fr 1fr 1fr;row-gap:20px;column-gap:20px}@media only screen and (max-width: 767px){.grid.three{grid-template-columns:1fr}}.grid.two{display:grid;grid-template-columns:1fr 1fr}@media only screen and (max-width: 767px){.grid.two{grid-template-columns:1fr}}@font-face{font-family:"Metropolis-Bold";src:url("/fonts/Metropolis-Bold.eot");src:url("/fonts/Metropolis-Bold.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Bold.woff2") format("woff2"),url("/fonts/Metropolis-Bold.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-BoldItalic";src:url("/fonts/Metropolis-BoldItalic.eot");src:url("/fonts/Metropolis-BoldItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-BoldItalic.woff2") format("woff2"),url("/fonts/Metropolis-BoldItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Light";src:url("/fonts/Metropolis-Light.eot");src:url("/fonts/Metropolis-Light.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Light.woff2") format("woff2"),url("/fonts/Metropolis-Light.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-LightItalic";src:url("/fonts/Metropolis-LightItalic.eot");src:url("/fonts/Metropolis-LightItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-LightItalic.woff2") format("woff2"),url("/fonts/Metropolis-LightItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Regular";src:url("/fonts/Metropolis-Regular.eot");src:url("/fonts/Metropolis-Regular.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Regular.woff2") format("woff2"),url("/fonts/Metropolis-Regular.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-RegularItalic";src:url("/fonts/Metropolis-RegularItalic.eot");src:url("/fonts/Metropolis-RegularItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-RegularItalic.woff2") format("woff2"),url("/fonts/Metropolis-RegularItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Medium";src:url("/fonts/Metropolis-Medium.eot");src:url("/fonts/Metropolis-Medium.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Medium.woff2") format("woff2"),url("/fonts/Metropolis-Medium.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-MediumItalic";src:url("/fonts/Metropolis-MediumItalic.eot");src:url("/fonts/Metropolis-MediumItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-MediumItalic.woff2") format("woff2"),url("/fonts/Metropolis-MediumItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-SemiBold";src:url("/fonts/Metropolis-SemiBold.eot");src:url("/fonts/Metropolis-SemiBold.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-SemiBold.woff2") format("woff2"),url("/fonts/Metropolis-SemiBold.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-SemiBoldItalic";src:url("/fonts/Metropolis-SemiBoldItalic.eot");src:url("/fonts/Metropolis-SemiBoldItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-SemiBoldItalic.woff2") format("woff2"),url("/fonts/Metropolis-SemiBoldItalic.woff") format("woff");font-weight:normal;font-style:normal}footer .left-links{padding:0px;float:left}footer .left-links li img{vertical-align:bottom;margin-right:10px}footer .left-links li a{color:#333;font-weight:300;font-size:12px;font-family:"Metropolis-Light",Helvetica,sans-serif}footer .right-links{float:right}footer .right-links p{margin:0px}footer .right-links .copywrite{font-size:12px;padding-right:10px}footer .right-links .copywrite a{font-size:12px;color:#333;font-family:"Metropolis-Light",Helvetica,sans-serif}footer .right-links a{vertical-align:middle}@media only screen and (max-width: 767px){footer .left-links{width:100%;float:none}footer .left-links li{display:block;width:33%;float:left;padding-right:0px}footer .right-links{width:100%;padding-top:20px}footer .right-links .image{display:none}}body{font-family:"Metropolis-Light",Helvetica,sans-serif;margin:0px;line-height:1.25}.wrapper{max-width:980px;margin:0px auto;padding:20px}@media only screen and (max-width: 767px){.wrapper{max-width:100%}}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0}.clearfix:after{clear:both}h1,h2,h3,h4,h5,h6{font-weight:300}h1{font-size:36px}h2{font-size:28px}h3{font-size:22px}h4{font-size:18px}li{list-style-type:none;display:inline;padding-right:25px;font-size:14px;line-height:1.7em}li:last-of-type{padding-right:0px}p{line-height:1.7em;font-weight:300;font-size:16px;color:#333}a{font-size:16px;text-decoration:none;color:#0095D3;font-family:"Metropolis-Medium",Helvetica,sans-serif}button{background-color:unset;border:none}.button{color:#0095D3;font-size:12px;font-weight:600;background-color:#fff;border-radius:3px;padding:14px 10px;min-width:200px;text-transform:uppercase;border:1px solid #fff}.button.secondary{background-color:#0091DA;color:#fff}.button.tertiary{border:1px solid #0095D3}.button img.button-icon{margin-left:5px;margin-right:5px;margin-bottom:-8px;width:24px;height:24px}.buttons{margin-top:40px}.buttons .button:first-of-type{margin-right:30px}@media only screen and (max-width: 767px){.buttons .button:first-of-type{margin:0px 0px 20px 0px}}.strong{font-family:"Metropolis-Medium",Helvetica,sans-serif}.bg-grey{background-color:#F2F2F2}.grid.three{display:grid;grid-template-columns:1fr 1fr 1fr;row-gap:20px;column-gap:20px}@media only screen and (max-width: 767px){.grid.three{grid-template-columns:1fr}}.grid.two{display:grid;grid-template-columns:1fr 1fr}@media only screen and (max-width: 767px){.grid.two{grid-template-columns:1fr}}@font-face{font-family:"Metropolis-Bold";src:url("/fonts/Metropolis-Bold.eot");src:url("/fonts/Metropolis-Bold.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Bold.woff2") format("woff2"),url("/fonts/Metropolis-Bold.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-BoldItalic";src:url("/fonts/Metropolis-BoldItalic.eot");src:url("/fonts/Metropolis-BoldItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-BoldItalic.woff2") format("woff2"),url("/fonts/Metropolis-BoldItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Light";src:url("/fonts/Metropolis-Light.eot");src:url("/fonts/Metropolis-Light.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Light.woff2") format("woff2"),url("/fonts/Metropolis-Light.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-LightItalic";src:url("/fonts/Metropolis-LightItalic.eot");src:url("/fonts/Metropolis-LightItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-LightItalic.woff2") format("woff2"),url("/fonts/Metropolis-LightItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Regular";src:url("/fonts/Metropolis-Regular.eot");src:url("/fonts/Metropolis-Regular.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Regular.woff2") format("woff2"),url("/fonts/Metropolis-Regular.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-RegularItalic";src:url("/fonts/Metropolis-RegularItalic.eot");src:url("/fonts/Metropolis-RegularItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-RegularItalic.woff2") format("woff2"),url("/fonts/Metropolis-RegularItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Medium";src:url("/fonts/Metropolis-Medium.eot");src:url("/fonts/Metropolis-Medium.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Medium.woff2") format("woff2"),url("/fonts/Metropolis-Medium.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-MediumItalic";src:url("/fonts/Metropolis-MediumItalic.eot");src:url("/fonts/Metropolis-MediumItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-MediumItalic.woff2") format("woff2"),url("/fonts/Metropolis-MediumItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-SemiBold";src:url("/fonts/Metropolis-SemiBold.eot");src:url("/fonts/Metropolis-SemiBold.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-SemiBold.woff2") format("woff2"),url("/fonts/Metropolis-SemiBold.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-SemiBoldItalic";src:url("/fonts/Metropolis-SemiBoldItalic.eot");src:url("/fonts/Metropolis-SemiBoldItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-SemiBoldItalic.woff2") format("woff2"),url("/fonts/Metropolis-SemiBoldItalic.woff") format("woff");font-weight:normal;font-style:normal}.hero{background-color:#0091DA;color:#fff}.hero .text-block{max-width:550px;padding:0px 0px 10px 0px}.hero .text-block p{margin-bottom:20px;font-size:18px;color:#fff}.hero h2{font-size:36px}.hero.homepage{background-image:url(/img/hero-image.png);background-position:center center;background-repeat:no-repeat;background-size:cover;padding-bottom:80px}@media only screen and (max-width: 767px){.hero .text-block{max-width:unset;margin-right:0px}.hero .button{display:block;text-align:center}.hero.homepage{background-image:none}}.grid-container{margin-top:-80px}.grid-container .grid.three{padding-bottom:20px}.grid-container .grid.three .card{position:relative;padding:30px 20px;background-color:#fff;text-align:center;box-shadow:0px 2px 10px rgba(0,0,0,0.2)}.grid-container .grid.three .card h3{color:#333;font-size:22px}.grid-container .grid.three .card p{color:#333}.introduction .grid.two{column-gap:140px;padding:35px 20px}.introduction .grid.two p{margin:0px;font-size:16px}.introduction .grid.two p.strong{color:#333}@media only screen and (max-width: 767px){.introduction{padding:0px 20px}.introduction .col:first-of-type{padding-bottom:50px}}.use-cases .grid{grid-template-columns:220px 1fr;margin-bottom:30px;grid-template-areas:"image text"}.use-cases .grid .image{background-color:#0091DA;text-align:center;display:flex;align-items:center;justify-content:center;grid-area:image}.use-cases .grid .image img{justify-self:center}.use-cases .grid .text{border:1px solid #F2F2F2;padding:30px;grid-area:text}.use-cases .grid .text a.button{display:block;max-width:138px;text-align:center;padding:5px 10px;min-width:unset}.use-cases .grid.image-right{grid-template-columns:1fr 220px;grid-template-areas:"text image"}@media only screen and (max-width: 767px){.use-cases .grid.image-right{grid-template-columns:1fr;grid-template-areas:"image" "text"}}@media only screen and (max-width: 767px){.use-cases .grid{grid-template-columns:1fr;grid-template-rows:minmax(160px, 1fr);grid-template-areas:"image" "text"}}.use-cases h2{color:#111}.use-cases p.strong{color:#1B3951;font-size:16px}.team{background-color:#1D428A}.team h2,.team h3,.team p{color:#fff}.team p{font-size:16px}.team a{color:#fff;font-weight:300;text-decoration:underline}.team .grid.three{row-gap:40px;margin:40px 0px}.team .bio{display:grid;grid-template-columns:120px 1fr;column-gap:20px}.team .bio .info{align-self:center}.team .bio .info p{margin:0px}.team .bio .info p.name{font-size:16px;font-family:"Metropolis-Medium",Helvetica,sans-serif}.team .bio .info p.position{font-size:14px}.hero.subpage{background-image:url(/img/blog-hero-image.png);background-position:center center;background-repeat:no-repeat;background-size:cover;padding-bottom:140px}.experimental .grid.three .col{padding:0px}.experimental .icon{background-color:#0091DA;padding:25px;min-height:95px;display:flex;align-items:center;justify-content:center}.experimental .content{padding:25px}.experimental .content .example{background-color:#F2F2F2}.blog{padding-bottom:50px}.blog .col{border:1px solid #F2F2F2}.blog .col img{width:100%}.blog .col .content{padding:0px 20px}.blog.landing{background-color:#fff;margin-top:-90px}.blog.landing h3 a{font-size:16px}.blog.landing .pagination{margin:30px auto 50px auto}.blog.landing .pagination ul{padding:0px;text-align:center}.blog.landing .pagination ul li{padding:0px}.blog.landing .pagination ul li a{padding:5px 10px}.blog.landing .pagination ul li a.active{background-color:#F2F2F2;border-radius:50%}.blog.landing .pagination ul li.left-arrow{margin-right:15px}.blog.landing .pagination ul li.right-arrow{margin-left:15px}.blog .blog-post{background-color:#fff;margin:-110px 0px 0px -30px;padding:30px 90px 30px 30px}.blog .blog-post .author{color:#0095D3;margin:0px}.blog .blog-post .date{color:#111;margin:0px;font-weight:600}.blog .blog-post .header,.blog .blog-post h4{color:#111;font-weight:600}.blog .blog-post a{font-size:16px}.blog .blog-post ul{list-style-type:disc;padding-left:20px}.blog .blog-post ul li:first-child{margin-top:10px}.blog .blog-post ul li{list-style-type:unset;display:list-item;margin-bottom:10px;font-size:16px;color:#333;list-style-image:url(/img/arrow.svg)}.blog .blog-post ol li:first-child{margin-top:10px}.blog .blog-post ol li{list-style-type:decimal;display:list-item;margin-bottom:10px;font-size:16px;color:#333}.blog .blog-post code{background-color:#fff;color:#333;border:2px solid #EFEFEF;padding:2px 8px}.blog .blog-post code .c1{color:#0095D3;font-style:italic}.blog .blog-post code .se{color:#ff0000}.blog .blog-post pre{white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word}.blog .blog-post pre code{display:block;border:15px solid #EFEFEF;padding:15px;margin-bottom:30px}.blog .blog-post img{max-width:100%}.blog .blog-post strong{font-family:"Metropolis-Medium",Helvetica,sans-serif}.getting-started{background-color:#F2F2F2;color:#111}.getting-started p{color:#111;font-size:16px}.getting-started .left-side{width:50%;float:left}.getting-started .right-side{width:25%;float:right}.getting-started h2{font-size:30px;margin-bottom:0px}.getting-started a{display:block;max-width:138px;text-align:center;padding:10px;min-width:unset}.getting-started .button{margin-top:50px;border:1px solid #0095D3}@media only screen and (max-width: 767px){.getting-started .wrapper{padding-bottom:40px}.getting-started .left-side{width:100%;float:none}.getting-started .right-side{width:100%;float:none}.getting-started .button{display:block;text-align:center;max-width:unset;margin-top:20px}}.community{background-color:#fff;margin-top:-90px;padding:30px 30px 50px 30px}.community .grid .col{border:1px solid #F2F2F2}.community .grid .col .icon{display:flex;align-items:center;justify-content:center;min-height:140px}.community .grid .col .content{padding:0px 20px 20px 20px;text-align:center}.community .grid .col .content h3{margin-top:0px}.docs{background-color:#fff;margin-top:-90px;padding:30px 30px 50px 30px}.docs .side-nav{width:25%;float:left}.docs .side-nav ul{padding-left:0px;margin-bottom:35px}.docs .side-nav ul ul{padding-left:15px;margin-top:10px;margin-bottom:15px}.docs .side-nav ul li{display:list-item;margin-bottom:15px}.docs .side-nav ul li a{color:#333;font-size:14px}.docs .side-nav ul li a.active{color:#0095D3}.docs .side-nav ul li.heading{color:#111;font-size:14px}.docs .docs-content{width:75%;float:right}.docs .docs-content a{font-size:16px}.docs .docs-content ul{list-style-type:disc;padding-left:20px}.docs .docs-content ul li:first-child{margin-top:10px}.docs .docs-content ul li{list-style-type:unset;display:list-item;margin-bottom:10px;font-size:16px;color:#333;line-height:1.6em;list-style-image:url(/img/arrow.svg)}.docs .docs-content ol li:first-child{margin-top:10px}.docs .docs-content ol li{list-style-type:decimal;display:list-item;margin-bottom:10px;font-size:16px;color:#333}.docs .docs-content code{background-color:#fff;color:#333;border:2px solid #EFEFEF;padding:2px 8px}.docs .docs-content code .c1{color:#0095D3;font-style:italic}.docs .docs-content code .se{color:#ff0000}.docs .docs-content pre{white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word}.docs .docs-content pre code{display:block;border:15px solid #EFEFEF;padding:15px;margin-bottom:30px;font-size:14px}.docs .docs-content img{max-width:100%}.docs .docs-content strong{font-family:"Metropolis-Medium",Helvetica,sans-serif}.docs .danger{padding:10px;font-family:"Metropolis-LightItalic",Helvetica,sans-serif}.docs .danger .danger-icon{float:left;padding:40px;width:24px;height:24px}.docs .button a{font-size:14px}.docs table td{padding:10px 30px}.chroma{color:#272822;background-color:#fafafa}.chroma .err{color:#960050;background-color:#1e0010}.chroma .lntd{vertical-align:top;padding:0;margin:0;border:0}.chroma .lntable{border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block}.chroma .hl{display:block;width:100%;background-color:#ffffcc}.chroma .lnt{margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f}.chroma .ln{margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f}.chroma .k{color:#00a8c8}.chroma .kc{color:#00a8c8}.chroma .kd{color:#00a8c8}.chroma .kn{color:#f92672}.chroma .kp{color:#00a8c8}.chroma .kr{color:#00a8c8}.chroma .kt{color:#00a8c8}.chroma .n{color:#111111}.chroma .na{color:#75af00}.chroma .nb{color:#111111}.chroma .bp{color:#111111}.chroma .nc{color:#75af00}.chroma .no{color:#00a8c8}.chroma .nd{color:#75af00}.chroma .ni{color:#111111}.chroma .ne{color:#75af00}.chroma .nf{color:#75af00}.chroma .fm{color:#111111}.chroma .nl{color:#111111}.chroma .nn{color:#111111}.chroma .nx{color:#75af00}.chroma .py{color:#111111}.chroma .nt{color:#f92672}.chroma .nv{color:#111111}.chroma .vc{color:#111111}.chroma .vg{color:#111111}.chroma .vi{color:#111111}.chroma .vm{color:#111111}.chroma .l{color:#ae81ff}.chroma .ld{color:#d88200}.chroma .s{color:#d88200}.chroma .sa{color:#d88200}.chroma .sb{color:#d88200}.chroma .sc{color:#d88200}.chroma .dl{color:#d88200}.chroma .sd{color:#d88200}.chroma .s2{color:#d88200}.chroma .se{color:#8045ff}.chroma .sh{color:#d88200}.chroma .si{color:#d88200}.chroma .sx{color:#d88200}.chroma .sr{color:#d88200}.chroma .s1{color:#d88200}.chroma .ss{color:#d88200}.chroma .m{color:#ae81ff}.chroma .mb{color:#ae81ff}.chroma .mf{color:#ae81ff}.chroma .mh{color:#ae81ff}.chroma .mi{color:#ae81ff}.chroma .il{color:#ae81ff}.chroma .mo{color:#ae81ff}.chroma .o{color:#f92672}.chroma .ow{color:#f92672}.chroma .p{color:#111111}.chroma .c{color:#75715e}.chroma .ch{color:#75715e}.chroma .cm{color:#75715e}.chroma .c1{color:#75715e}.chroma .cs{color:#75715e}.chroma .cp{color:#75715e}.chroma .cpf{color:#75715e}.chroma .ge{font-style:italic}.chroma .gs{font-weight:bold} +body{font-family:"Metropolis-Light",Helvetica,sans-serif;margin:0px;line-height:1.25}.wrapper{max-width:980px;margin:0px auto;padding:20px}@media only screen and (max-width: 767px){.wrapper{max-width:100%}}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0}.clearfix:after{clear:both}h1,h2,h3,h4,h5,h6{font-weight:300}h1{font-size:36px}h2{font-size:28px}h3{font-size:22px}h4{font-size:18px}li{list-style-type:none;display:inline;padding-right:25px;font-size:14px;line-height:1.7em}li:last-of-type{padding-right:0px}p{line-height:1.7em;font-weight:300;font-size:16px;color:#333}a{font-size:16px;text-decoration:none;color:#0095D3;font-family:"Metropolis-Medium",Helvetica,sans-serif}button{background-color:unset;border:none}.button{color:#0095D3;font-size:12px;font-weight:600;background-color:#fff;border-radius:3px;padding:14px 10px;min-width:200px;text-transform:uppercase;border:1px solid #fff}.button.secondary{background-color:#0091DA;color:#fff}.button.tertiary{border:1px solid #0095D3}.button img.button-icon{margin-left:5px;margin-right:5px;margin-bottom:-8px;width:24px;height:24px}.buttons{margin-top:40px}.buttons .button:first-of-type{margin-right:30px}@media only screen and (max-width: 767px){.buttons .button:first-of-type{margin:0px 0px 20px 0px}}.strong{font-family:"Metropolis-Medium",Helvetica,sans-serif}.bg-grey{background-color:#F2F2F2}.grid.three{display:grid;grid-template-columns:1fr 1fr 1fr;row-gap:20px;column-gap:20px}@media only screen and (max-width: 767px){.grid.three{grid-template-columns:1fr}}.grid.two{display:grid;grid-template-columns:1fr 1fr}@media only screen and (max-width: 767px){.grid.two{grid-template-columns:1fr}}@font-face{font-family:"Metropolis-Bold";src:url("/fonts/Metropolis-Bold.eot");src:url("/fonts/Metropolis-Bold.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Bold.woff2") format("woff2"),url("/fonts/Metropolis-Bold.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-BoldItalic";src:url("/fonts/Metropolis-BoldItalic.eot");src:url("/fonts/Metropolis-BoldItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-BoldItalic.woff2") format("woff2"),url("/fonts/Metropolis-BoldItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Light";src:url("/fonts/Metropolis-Light.eot");src:url("/fonts/Metropolis-Light.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Light.woff2") format("woff2"),url("/fonts/Metropolis-Light.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-LightItalic";src:url("/fonts/Metropolis-LightItalic.eot");src:url("/fonts/Metropolis-LightItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-LightItalic.woff2") format("woff2"),url("/fonts/Metropolis-LightItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Regular";src:url("/fonts/Metropolis-Regular.eot");src:url("/fonts/Metropolis-Regular.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Regular.woff2") format("woff2"),url("/fonts/Metropolis-Regular.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-RegularItalic";src:url("/fonts/Metropolis-RegularItalic.eot");src:url("/fonts/Metropolis-RegularItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-RegularItalic.woff2") format("woff2"),url("/fonts/Metropolis-RegularItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Medium";src:url("/fonts/Metropolis-Medium.eot");src:url("/fonts/Metropolis-Medium.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Medium.woff2") format("woff2"),url("/fonts/Metropolis-Medium.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-MediumItalic";src:url("/fonts/Metropolis-MediumItalic.eot");src:url("/fonts/Metropolis-MediumItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-MediumItalic.woff2") format("woff2"),url("/fonts/Metropolis-MediumItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-SemiBold";src:url("/fonts/Metropolis-SemiBold.eot");src:url("/fonts/Metropolis-SemiBold.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-SemiBold.woff2") format("woff2"),url("/fonts/Metropolis-SemiBold.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-SemiBoldItalic";src:url("/fonts/Metropolis-SemiBoldItalic.eot");src:url("/fonts/Metropolis-SemiBoldItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-SemiBoldItalic.woff2") format("woff2"),url("/fonts/Metropolis-SemiBoldItalic.woff") format("woff");font-weight:normal;font-style:normal}header .wrapper{padding:10px 20px}header .desktop-links{float:right;margin:15px 0px 0px 0px;padding-left:0px}header a{color:#333;font-family:"Metropolis-Light",Helvetica,sans-serif}header a.active{font-family:"Metropolis-Medium",Helvetica,sans-serif}header li img{vertical-align:bottom;margin-right:10px}header .mobile{display:none}@media only screen and (min-width: 768px) and (max-width: 1279px){header .desktop-links li{padding-right:10px}}@media only screen and (max-width: 767px){header{position:relative}header .expanded-icon{display:none;padding:11px 3px 0px 0px}header .collapsed-icon{padding-top:12px}header .mobile-menu-visible .mobile{display:block}header .mobile-menu-visible .mobile .collapsed-icon{display:none}header .mobile-menu-visible .mobile .expanded-icon{display:block}header .desktop-links{display:none}header .mobile{display:block}header button{float:right}header button:focus{outline:none}header ul{padding-left:0px}header ul li{display:block;margin:20px 0px}header .mobile-menu{position:absolute;background-color:#fff;width:100%;top:70px;left:0px;padding-bottom:20px;display:none}header .mobile-menu .header-links{margin:0px 20px}header .mobile-menu .social{margin:0px 20px;padding-top:20px}header .mobile-menu .social img{vertical-align:middle;padding-right:10px}header .mobile-menu .social a{font-size:14px;padding-right:35px}header .mobile-menu .social a:last-of-type{padding-right:0px}}body{font-family:"Metropolis-Light",Helvetica,sans-serif;margin:0px;line-height:1.25}.wrapper{max-width:980px;margin:0px auto;padding:20px}@media only screen and (max-width: 767px){.wrapper{max-width:100%}}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0}.clearfix:after{clear:both}h1,h2,h3,h4,h5,h6{font-weight:300}h1{font-size:36px}h2{font-size:28px}h3{font-size:22px}h4{font-size:18px}li{list-style-type:none;display:inline;padding-right:25px;font-size:14px;line-height:1.7em}li:last-of-type{padding-right:0px}p{line-height:1.7em;font-weight:300;font-size:16px;color:#333}a{font-size:16px;text-decoration:none;color:#0095D3;font-family:"Metropolis-Medium",Helvetica,sans-serif}button{background-color:unset;border:none}.button{color:#0095D3;font-size:12px;font-weight:600;background-color:#fff;border-radius:3px;padding:14px 10px;min-width:200px;text-transform:uppercase;border:1px solid #fff}.button.secondary{background-color:#0091DA;color:#fff}.button.tertiary{border:1px solid #0095D3}.button img.button-icon{margin-left:5px;margin-right:5px;margin-bottom:-8px;width:24px;height:24px}.buttons{margin-top:40px}.buttons .button:first-of-type{margin-right:30px}@media only screen and (max-width: 767px){.buttons .button:first-of-type{margin:0px 0px 20px 0px}}.strong{font-family:"Metropolis-Medium",Helvetica,sans-serif}.bg-grey{background-color:#F2F2F2}.grid.three{display:grid;grid-template-columns:1fr 1fr 1fr;row-gap:20px;column-gap:20px}@media only screen and (max-width: 767px){.grid.three{grid-template-columns:1fr}}.grid.two{display:grid;grid-template-columns:1fr 1fr}@media only screen and (max-width: 767px){.grid.two{grid-template-columns:1fr}}@font-face{font-family:"Metropolis-Bold";src:url("/fonts/Metropolis-Bold.eot");src:url("/fonts/Metropolis-Bold.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Bold.woff2") format("woff2"),url("/fonts/Metropolis-Bold.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-BoldItalic";src:url("/fonts/Metropolis-BoldItalic.eot");src:url("/fonts/Metropolis-BoldItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-BoldItalic.woff2") format("woff2"),url("/fonts/Metropolis-BoldItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Light";src:url("/fonts/Metropolis-Light.eot");src:url("/fonts/Metropolis-Light.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Light.woff2") format("woff2"),url("/fonts/Metropolis-Light.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-LightItalic";src:url("/fonts/Metropolis-LightItalic.eot");src:url("/fonts/Metropolis-LightItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-LightItalic.woff2") format("woff2"),url("/fonts/Metropolis-LightItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Regular";src:url("/fonts/Metropolis-Regular.eot");src:url("/fonts/Metropolis-Regular.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Regular.woff2") format("woff2"),url("/fonts/Metropolis-Regular.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-RegularItalic";src:url("/fonts/Metropolis-RegularItalic.eot");src:url("/fonts/Metropolis-RegularItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-RegularItalic.woff2") format("woff2"),url("/fonts/Metropolis-RegularItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Medium";src:url("/fonts/Metropolis-Medium.eot");src:url("/fonts/Metropolis-Medium.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Medium.woff2") format("woff2"),url("/fonts/Metropolis-Medium.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-MediumItalic";src:url("/fonts/Metropolis-MediumItalic.eot");src:url("/fonts/Metropolis-MediumItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-MediumItalic.woff2") format("woff2"),url("/fonts/Metropolis-MediumItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-SemiBold";src:url("/fonts/Metropolis-SemiBold.eot");src:url("/fonts/Metropolis-SemiBold.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-SemiBold.woff2") format("woff2"),url("/fonts/Metropolis-SemiBold.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-SemiBoldItalic";src:url("/fonts/Metropolis-SemiBoldItalic.eot");src:url("/fonts/Metropolis-SemiBoldItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-SemiBoldItalic.woff2") format("woff2"),url("/fonts/Metropolis-SemiBoldItalic.woff") format("woff");font-weight:normal;font-style:normal}footer .left-links{padding:0px;float:left}footer .left-links li img{vertical-align:bottom;margin-right:10px}footer .left-links li a{color:#333;font-weight:300;font-size:12px;font-family:"Metropolis-Light",Helvetica,sans-serif}footer .right-links{float:right}footer .right-links p{margin:0px}footer .right-links .copywrite{font-size:12px;padding-right:10px}footer .right-links .copywrite a{font-size:12px;color:#333;font-family:"Metropolis-Light",Helvetica,sans-serif}footer .right-links a{vertical-align:middle}@media only screen and (max-width: 767px){footer .left-links{width:100%;float:none}footer .left-links li{display:block;width:33%;float:left;padding-right:0px}footer .right-links{width:100%;padding-top:20px}footer .right-links .image{display:none}}body{font-family:"Metropolis-Light",Helvetica,sans-serif;margin:0px;line-height:1.25}.wrapper{max-width:980px;margin:0px auto;padding:20px}@media only screen and (max-width: 767px){.wrapper{max-width:100%}}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0}.clearfix:after{clear:both}h1,h2,h3,h4,h5,h6{font-weight:300}h1{font-size:36px}h2{font-size:28px}h3{font-size:22px}h4{font-size:18px}li{list-style-type:none;display:inline;padding-right:25px;font-size:14px;line-height:1.7em}li:last-of-type{padding-right:0px}p{line-height:1.7em;font-weight:300;font-size:16px;color:#333}a{font-size:16px;text-decoration:none;color:#0095D3;font-family:"Metropolis-Medium",Helvetica,sans-serif}button{background-color:unset;border:none}.button{color:#0095D3;font-size:12px;font-weight:600;background-color:#fff;border-radius:3px;padding:14px 10px;min-width:200px;text-transform:uppercase;border:1px solid #fff}.button.secondary{background-color:#0091DA;color:#fff}.button.tertiary{border:1px solid #0095D3}.button img.button-icon{margin-left:5px;margin-right:5px;margin-bottom:-8px;width:24px;height:24px}.buttons{margin-top:40px}.buttons .button:first-of-type{margin-right:30px}@media only screen and (max-width: 767px){.buttons .button:first-of-type{margin:0px 0px 20px 0px}}.strong{font-family:"Metropolis-Medium",Helvetica,sans-serif}.bg-grey{background-color:#F2F2F2}.grid.three{display:grid;grid-template-columns:1fr 1fr 1fr;row-gap:20px;column-gap:20px}@media only screen and (max-width: 767px){.grid.three{grid-template-columns:1fr}}.grid.two{display:grid;grid-template-columns:1fr 1fr}@media only screen and (max-width: 767px){.grid.two{grid-template-columns:1fr}}@font-face{font-family:"Metropolis-Bold";src:url("/fonts/Metropolis-Bold.eot");src:url("/fonts/Metropolis-Bold.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Bold.woff2") format("woff2"),url("/fonts/Metropolis-Bold.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-BoldItalic";src:url("/fonts/Metropolis-BoldItalic.eot");src:url("/fonts/Metropolis-BoldItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-BoldItalic.woff2") format("woff2"),url("/fonts/Metropolis-BoldItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Light";src:url("/fonts/Metropolis-Light.eot");src:url("/fonts/Metropolis-Light.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Light.woff2") format("woff2"),url("/fonts/Metropolis-Light.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-LightItalic";src:url("/fonts/Metropolis-LightItalic.eot");src:url("/fonts/Metropolis-LightItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-LightItalic.woff2") format("woff2"),url("/fonts/Metropolis-LightItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Regular";src:url("/fonts/Metropolis-Regular.eot");src:url("/fonts/Metropolis-Regular.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Regular.woff2") format("woff2"),url("/fonts/Metropolis-Regular.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-RegularItalic";src:url("/fonts/Metropolis-RegularItalic.eot");src:url("/fonts/Metropolis-RegularItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-RegularItalic.woff2") format("woff2"),url("/fonts/Metropolis-RegularItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-Medium";src:url("/fonts/Metropolis-Medium.eot");src:url("/fonts/Metropolis-Medium.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-Medium.woff2") format("woff2"),url("/fonts/Metropolis-Medium.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-MediumItalic";src:url("/fonts/Metropolis-MediumItalic.eot");src:url("/fonts/Metropolis-MediumItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-MediumItalic.woff2") format("woff2"),url("/fonts/Metropolis-MediumItalic.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-SemiBold";src:url("/fonts/Metropolis-SemiBold.eot");src:url("/fonts/Metropolis-SemiBold.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-SemiBold.woff2") format("woff2"),url("/fonts/Metropolis-SemiBold.woff") format("woff");font-weight:normal;font-style:normal}@font-face{font-family:"Metropolis-SemiBoldItalic";src:url("/fonts/Metropolis-SemiBoldItalic.eot");src:url("/fonts/Metropolis-SemiBoldItalic.eot?#iefix") format("embedded-opentype"),url("/fonts/Metropolis-SemiBoldItalic.woff2") format("woff2"),url("/fonts/Metropolis-SemiBoldItalic.woff") format("woff");font-weight:normal;font-style:normal}.hero{background-color:#0091DA;color:#fff}.hero .text-block{max-width:550px;padding:0px 0px 10px 0px}.hero .text-block p{margin-bottom:20px;font-size:18px;color:#fff}.hero h2{font-size:36px}.hero.homepage{background-image:url(/img/hero-image.png);background-position:center center;background-repeat:no-repeat;background-size:cover;padding-bottom:80px}@media only screen and (max-width: 767px){.hero .text-block{max-width:unset;margin-right:0px}.hero .button{display:block;text-align:center}.hero.homepage{background-image:none}}.grid-container{margin-top:-80px}.grid-container .grid.three{padding-bottom:20px}.grid-container .grid.three .card{position:relative;padding:30px 20px;background-color:#fff;text-align:center;box-shadow:0px 2px 10px rgba(0,0,0,0.2)}.grid-container .grid.three .card h3{color:#333;font-size:22px}.grid-container .grid.three .card p{color:#333}.introduction .grid.two{column-gap:140px;padding:35px 20px}.introduction .grid.two p{margin:0px;font-size:16px}.introduction .grid.two p.strong{color:#333}@media only screen and (max-width: 767px){.introduction{padding:0px 20px}.introduction .col:first-of-type{padding-bottom:50px}}.use-cases .grid{grid-template-columns:220px 1fr;margin-bottom:30px;grid-template-areas:"image text"}.use-cases .grid .image{background-color:#0091DA;text-align:center;display:flex;align-items:center;justify-content:center;grid-area:image}.use-cases .grid .image img{justify-self:center}.use-cases .grid .text{border:1px solid #F2F2F2;padding:30px;grid-area:text}.use-cases .grid .text a.button{display:block;max-width:138px;text-align:center;padding:5px 10px;min-width:unset}.use-cases .grid.image-right{grid-template-columns:1fr 220px;grid-template-areas:"text image"}@media only screen and (max-width: 767px){.use-cases .grid.image-right{grid-template-columns:1fr;grid-template-areas:"image" "text"}}@media only screen and (max-width: 767px){.use-cases .grid{grid-template-columns:1fr;grid-template-rows:minmax(160px, 1fr);grid-template-areas:"image" "text"}}.use-cases h2{color:#111}.use-cases p.strong{color:#1B3951;font-size:16px}.team{background-color:#1D428A}.team h2,.team h3,.team p{color:#fff}.team p{font-size:16px}.team a{color:#fff;font-weight:300;text-decoration:underline}.team .grid.three{row-gap:40px;margin:40px 0px}.team .bio{display:grid;grid-template-columns:120px 1fr;column-gap:20px}.team .bio .info{align-self:center}.team .bio .info p{margin:0px}.team .bio .info p.name{font-size:16px;font-family:"Metropolis-Medium",Helvetica,sans-serif}.team .bio .info p.position{font-size:14px}.hero.subpage{background-image:url(/img/blog-hero-image.png);background-position:center center;background-repeat:no-repeat;background-size:cover;padding-bottom:140px}.experimental .grid.three .col{padding:0px}.experimental .icon{background-color:#0091DA;padding:25px;min-height:95px;display:flex;align-items:center;justify-content:center}.experimental .content{padding:25px}.experimental .content .example{background-color:#F2F2F2}.blog{padding-bottom:50px}.blog .col{border:1px solid #F2F2F2}.blog .col img{width:100%}.blog .col .content{padding:0px 20px}.blog.landing{background-color:#fff;margin-top:-90px}.blog.landing h3 a{font-size:16px}.blog.landing .pagination{margin:30px auto 50px auto}.blog.landing .pagination ul{padding:0px;text-align:center}.blog.landing .pagination ul li{padding:0px}.blog.landing .pagination ul li a{padding:5px 10px}.blog.landing .pagination ul li a.active{background-color:#F2F2F2;border-radius:50%}.blog.landing .pagination ul li.left-arrow{margin-right:15px}.blog.landing .pagination ul li.right-arrow{margin-left:15px}.blog .blog-post{background-color:#fff;margin:-110px 0px 0px -30px;padding:30px 90px 30px 30px}.blog .blog-post .author{color:#0095D3;margin:0px}.blog .blog-post .date{color:#111;margin:0px;font-weight:600}.blog .blog-post .header,.blog .blog-post h4{color:#111;font-weight:600}.blog .blog-post a{font-size:16px}.blog .blog-post ul{list-style-type:disc;padding-left:20px}.blog .blog-post ul li:first-child{margin-top:10px}.blog .blog-post ul li{list-style-type:unset;display:list-item;margin-bottom:10px;font-size:16px;color:#333;list-style-image:url(/img/arrow.svg)}.blog .blog-post ol li:first-child{margin-top:10px}.blog .blog-post ol li{list-style-type:decimal;display:list-item;margin-bottom:10px;font-size:16px;color:#333}.blog .blog-post code{background-color:#fff;color:#333;border:2px solid #EFEFEF;padding:2px 8px}.blog .blog-post code .c1{color:#0095D3;font-style:italic}.blog .blog-post code .se{color:#ff0000}.blog .blog-post pre{white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word}.blog .blog-post pre code{display:block;border:15px solid #EFEFEF;padding:15px;margin-bottom:30px}.blog .blog-post img{max-width:100%}.blog .blog-post strong{font-family:"Metropolis-Medium",Helvetica,sans-serif}.getting-started{background-color:#F2F2F2;color:#111}.getting-started p{color:#111;font-size:16px}.getting-started .left-side{width:50%;float:left}.getting-started .right-side{width:25%;float:right}.getting-started h2{font-size:30px;margin-bottom:0px}.getting-started a{display:block;max-width:138px;text-align:center;padding:10px;min-width:unset}.getting-started .button{margin-top:50px;border:1px solid #0095D3}@media only screen and (max-width: 767px){.getting-started .wrapper{padding-bottom:40px}.getting-started .left-side{width:100%;float:none}.getting-started .right-side{width:100%;float:none}.getting-started .button{display:block;text-align:center;max-width:unset;margin-top:20px}}.community{background-color:#fff;margin-top:-90px;padding:30px 30px 50px 30px}.community .grid .col{border:1px solid #F2F2F2}.community .grid .col .icon{display:flex;align-items:center;justify-content:center;min-height:140px}.community .grid .col .content{padding:0px 20px 20px 20px;text-align:center}.community .grid .col .content h3{margin-top:0px}.docs{background-color:#fff;margin-top:-90px;padding:30px 30px 50px 30px}.docs .side-nav{width:25%;float:left}@media only screen and (max-width: 1279px){.docs .side-nav{width:100%;float:none}}.docs .side-nav ul{padding-left:0px;margin-bottom:35px}.docs .side-nav ul ul{padding-left:15px;margin-top:10px;margin-bottom:15px}.docs .side-nav ul li{display:list-item;margin-bottom:15px}.docs .side-nav ul li a{color:#333;font-size:14px}.docs .side-nav ul li a.active{color:#0095D3}.docs .side-nav ul li.heading{color:#111;font-size:14px}.docs .docs-content{width:75%;float:right}@media only screen and (max-width: 1279px){.docs .docs-content{width:100%;float:none}}.docs .docs-content a{font-size:16px}.docs .docs-content ul{list-style-type:disc;padding-left:20px}.docs .docs-content ul li:first-child{margin-top:10px}.docs .docs-content ul li{list-style-type:unset;display:list-item;margin-bottom:10px;font-size:16px;color:#333;line-height:1.6em;list-style-image:url(/img/arrow.svg)}.docs .docs-content ol li:first-child{margin-top:10px}.docs .docs-content ol li{list-style-type:decimal;display:list-item;margin-bottom:10px;font-size:16px;color:#333}.docs .docs-content code{background-color:#fff;color:#333;border:2px solid #EFEFEF;padding:2px 8px}.docs .docs-content code .c1{color:#0095D3;font-style:italic}.docs .docs-content code .se{color:#ff0000}.docs .docs-content pre{white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word}.docs .docs-content pre code{display:block;border:15px solid #EFEFEF;padding:15px;margin-bottom:30px;font-size:14px}.docs .docs-content img{max-width:100%}.docs .docs-content strong{font-family:"Metropolis-Medium",Helvetica,sans-serif}.docs .danger{padding:10px;font-family:"Metropolis-LightItalic",Helvetica,sans-serif}.docs .danger .danger-icon{float:left;padding:40px;width:24px;height:24px}.docs .button{white-space:nowrap}.docs .button a{font-size:14px}.docs table td{padding:10px 30px}.chroma{color:#272822;background-color:#fafafa}.chroma .err{color:#960050;background-color:#1e0010}.chroma .lntd{vertical-align:top;padding:0;margin:0;border:0}.chroma .lntable{border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block}.chroma .hl{display:block;width:100%;background-color:#ffffcc}.chroma .lnt{margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f}.chroma .ln{margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f}.chroma .k{color:#00a8c8}.chroma .kc{color:#00a8c8}.chroma .kd{color:#00a8c8}.chroma .kn{color:#f92672}.chroma .kp{color:#00a8c8}.chroma .kr{color:#00a8c8}.chroma .kt{color:#00a8c8}.chroma .n{color:#111111}.chroma .na{color:#75af00}.chroma .nb{color:#111111}.chroma .bp{color:#111111}.chroma .nc{color:#75af00}.chroma .no{color:#00a8c8}.chroma .nd{color:#75af00}.chroma .ni{color:#111111}.chroma .ne{color:#75af00}.chroma .nf{color:#75af00}.chroma .fm{color:#111111}.chroma .nl{color:#111111}.chroma .nn{color:#111111}.chroma .nx{color:#75af00}.chroma .py{color:#111111}.chroma .nt{color:#f92672}.chroma .nv{color:#111111}.chroma .vc{color:#111111}.chroma .vg{color:#111111}.chroma .vi{color:#111111}.chroma .vm{color:#111111}.chroma .l{color:#ae81ff}.chroma .ld{color:#d88200}.chroma .s{color:#d88200}.chroma .sa{color:#d88200}.chroma .sb{color:#d88200}.chroma .sc{color:#d88200}.chroma .dl{color:#d88200}.chroma .sd{color:#d88200}.chroma .s2{color:#d88200}.chroma .se{color:#8045ff}.chroma .sh{color:#d88200}.chroma .si{color:#d88200}.chroma .sx{color:#d88200}.chroma .sr{color:#d88200}.chroma .s1{color:#d88200}.chroma .ss{color:#d88200}.chroma .m{color:#ae81ff}.chroma .mb{color:#ae81ff}.chroma .mf{color:#ae81ff}.chroma .mh{color:#ae81ff}.chroma .mi{color:#ae81ff}.chroma .il{color:#ae81ff}.chroma .mo{color:#ae81ff}.chroma .o{color:#f92672}.chroma .ow{color:#f92672}.chroma .p{color:#111111}.chroma .c{color:#75715e}.chroma .ch{color:#75715e}.chroma .cm{color:#75715e}.chroma .c1{color:#75715e}.chroma .cs{color:#75715e}.chroma .cp{color:#75715e}.chroma .cpf{color:#75715e}.chroma .ge{font-style:italic}.chroma .gs{font-weight:bold} /*# sourceMappingURL=style.css.map */ \ No newline at end of file diff --git a/site/themes/pinniped/assets/scss/_components.scss b/site/themes/pinniped/assets/scss/_components.scss index 60b65d28..f6a48cca 100644 --- a/site/themes/pinniped/assets/scss/_components.scss +++ b/site/themes/pinniped/assets/scss/_components.scss @@ -407,6 +407,11 @@ .side-nav { width: 25%; float: left; + @include breakpoint(small-medium) { + width: 100%; + float: none; + } + ul { padding-left: 0px; margin-bottom: 35px; @@ -435,6 +440,10 @@ .docs-content { width: 75%; float: right; + @include breakpoint(small-medium) { + width: 100%; + float: none; + } a { font-size: 16px; } @@ -512,6 +521,7 @@ } .button { + white-space: nowrap; a { font-size: 14px; } diff --git a/site/themes/pinniped/layouts/_default/baseof.html b/site/themes/pinniped/layouts/_default/baseof.html index b68a0f83..2977d22e 100644 --- a/site/themes/pinniped/layouts/_default/baseof.html +++ b/site/themes/pinniped/layouts/_default/baseof.html @@ -19,7 +19,6 @@ {{ partial "header" . }} {{ block "main" . }}{{ end }} - {{ partial "getting-started" . }} {{ partial "footer" . }} diff --git a/site/themes/pinniped/layouts/_default/posts.html b/site/themes/pinniped/layouts/_default/posts.html index 5d022201..5a8b3c38 100644 --- a/site/themes/pinniped/layouts/_default/posts.html +++ b/site/themes/pinniped/layouts/_default/posts.html @@ -2,7 +2,7 @@
-

Pinniped Blog

+

Pinniped blog

@@ -14,4 +14,5 @@ {{ partial "pagination.html" . }}
+ {{ partial "getting-started" . }} {{ end }} diff --git a/site/themes/pinniped/layouts/_default/section.html b/site/themes/pinniped/layouts/_default/section.html index 560a0253..28b36420 100644 --- a/site/themes/pinniped/layouts/_default/section.html +++ b/site/themes/pinniped/layouts/_default/section.html @@ -2,6 +2,7 @@
{{ .Content }}
+ {{ partial "getting-started" . }} {{ end }} diff --git a/site/themes/pinniped/layouts/_default/single.html b/site/themes/pinniped/layouts/_default/single.html index 5a987c4e..71b66d04 100644 --- a/site/themes/pinniped/layouts/_default/single.html +++ b/site/themes/pinniped/layouts/_default/single.html @@ -3,7 +3,7 @@
-

Pinniped Blog

+

Pinniped blog

@@ -15,18 +15,19 @@

{{ dateFormat "Jan 2, 2006" .Date }}

{{ .Content }}
-

Related Content

-
- {{ $related := (where (.Site.RegularPages.Related .) "Type" "posts") | first 3 }} - {{ with $related }} + {{ $related := (where (.Site.RegularPages.Related .) "Type" "posts") | first 3 }} + {{ with $related }} +

Related content

+
{{ range . }} {{ partial "blog-post-card.html" . }} {{ end }} - {{ end }} -
+
+ {{ end }}
+ {{ partial "getting-started" . }} {{ end }} diff --git a/site/themes/pinniped/layouts/_default/tag.html b/site/themes/pinniped/layouts/_default/tag.html index ad0873ed..a7ea9a97 100644 --- a/site/themes/pinniped/layouts/_default/tag.html +++ b/site/themes/pinniped/layouts/_default/tag.html @@ -13,4 +13,5 @@ + {{ partial "getting-started" . }} {{ end }} \ No newline at end of file diff --git a/site/themes/pinniped/layouts/index.html b/site/themes/pinniped/layouts/index.html index 2f24197e..b65d0d60 100644 --- a/site/themes/pinniped/layouts/index.html +++ b/site/themes/pinniped/layouts/index.html @@ -6,7 +6,7 @@

Introduction to Pinniped

-

Learn how Pinniped provides identity services to Kubernetes

+

Learn how Pinniped provides identity services to Kubernetes

How do you use Pinniped?

@@ -17,4 +17,5 @@ {{ partial "use-cases.html" . }} {{ partial "team.html" . }} + {{ partial "getting-started" . }} {{ end }} diff --git a/site/themes/pinniped/layouts/partials/blog-post-card.html b/site/themes/pinniped/layouts/partials/blog-post-card.html index bdda6613..c4b240f2 100644 --- a/site/themes/pinniped/layouts/partials/blog-post-card.html +++ b/site/themes/pinniped/layouts/partials/blog-post-card.html @@ -4,6 +4,7 @@

{{ .Title }}

+

{{ .Params.Excerpt }}

\ No newline at end of file diff --git a/site/themes/pinniped/layouts/partials/getting-started.html b/site/themes/pinniped/layouts/partials/getting-started.html index 8ba96386..1988320e 100644 --- a/site/themes/pinniped/layouts/partials/getting-started.html +++ b/site/themes/pinniped/layouts/partials/getting-started.html @@ -2,10 +2,10 @@

Getting started

-

To help you get started, see the documentation.

+

Learn how Pinniped works, see how to use it on your clusters, and dive into internals of Pinniped's APIs and architecture.

\ No newline at end of file diff --git a/site/themes/pinniped/layouts/partials/hero.html b/site/themes/pinniped/layouts/partials/hero.html index c82058eb..201f5692 100644 --- a/site/themes/pinniped/layouts/partials/hero.html +++ b/site/themes/pinniped/layouts/partials/hero.html @@ -1,10 +1,10 @@
-

Pinniped - Simplify user authentication for any Kubernetes cluster: log in once and you’re done.

-

Pinniped delivers a consistent Kubernetes user authentication experience while prioritizing security, interoperability and low-effort management at scale.

+

Batteries-included for Kubernetes authentication

+

Pinniped is the easy, secure way to login to your Kubernetes clusters.

diff --git a/site/themes/pinniped/layouts/partials/homepage-grid.html b/site/themes/pinniped/layouts/partials/homepage-grid.html index 1d3a87db..71a7fd2b 100644 --- a/site/themes/pinniped/layouts/partials/homepage-grid.html +++ b/site/themes/pinniped/layouts/partials/homepage-grid.html @@ -4,17 +4,17 @@

Simple

-

Install and integrate with nearly any cluster in one step

+

Easily install on almost any Kubernetes cluster

Frictionless

-

Log in once to safely access many clusters

+

Use native command-line tools like kubectl

Seamless

-

Leverage first class integration with Kubernetes and kubectl CLI

+

Log in once to safely access all your clusters

diff --git a/site/themes/pinniped/layouts/partials/team.html b/site/themes/pinniped/layouts/partials/team.html index 552f4bac..a7ee4661 100644 --- a/site/themes/pinniped/layouts/partials/team.html +++ b/site/themes/pinniped/layouts/partials/team.html @@ -2,13 +2,6 @@

The Pinniped Project Team:

-
-
-
-

Matt Moyer

-

Engineer

-
-
@@ -17,9 +10,16 @@
-
+
-

Ryan Richard

+

Margo Crawford

+

Engineer

+
+
+
+
+
+

Matt Moyer

Engineer

@@ -30,6 +30,13 @@

Engineer

+
+
+
+

Nanci Lancaster

+

Community Manager

+
+
@@ -37,8 +44,15 @@

Product Manager

+
+
+
+

Ryan Richard

+

Engineer

+
+

Contributing:

-

The Pinniped project team welcomes contributions from the community, please see our contributor’s guide for more information.

+

The Pinniped project team welcomes contributions from the community, please see the contributor’s guide for more information.

\ No newline at end of file diff --git a/site/themes/pinniped/layouts/partials/use-cases.html b/site/themes/pinniped/layouts/partials/use-cases.html index 740956b3..583dae76 100644 --- a/site/themes/pinniped/layouts/partials/use-cases.html +++ b/site/themes/pinniped/layouts/partials/use-cases.html @@ -1,18 +1,18 @@
-

Use Cases

+

Use cases

-

Cluster Administration

-

Easily plug in external IDPs into Kubernetes clusters while offering a simple install and configuration experience. Leverage first class integration with Kubernetes and kubectl CLI.

+

Cluster administration

+

Easily plug in external identity providers into Kubernetes clusters while offering a simple install and configuration experience. Leverage first class integration with Kubernetes and kubectl command-line.

-

Seamless Authentication

+

Seamless authentication

Give users a consistent, unified login experience across all your clusters, including on-premises and managed cloud environments.

@@ -25,8 +25,8 @@
-

Security for Enterprises & Teams Alike

-

Securely integrate with an enterprise IDP using standard protocols or use secure, externally-managed identities instead of relying on simple, shared credentials.

+

Security for enterprises & teams alike

+

Securely integrate with an enterprise IDP using standard protocols or use secure, externally managed identities instead of relying on simple, shared credentials.

diff --git a/site/themes/pinniped/static/img/margo-crawford.png b/site/themes/pinniped/static/img/margo-crawford.png new file mode 100644 index 0000000000000000000000000000000000000000..6268f764a9a2e3125b471fb4fb37767bf9596c51 GIT binary patch literal 37975 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 literal 0 HcmV?d00001 diff --git a/site/themes/pinniped/static/img/nanci-lancaster.png b/site/themes/pinniped/static/img/nanci-lancaster.png new file mode 100644 index 0000000000000000000000000000000000000000..acf03758ade4a1eda6552574f2ea4847584ed2f4 GIT binary patch literal 31548 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 literal 0 HcmV?d00001 From 60034b39a3fa3c1f7abe90ac26f9803708eb40b4 Mon Sep 17 00:00:00 2001 From: Matt Moyer Date: Tue, 23 Feb 2021 12:17:26 -0800 Subject: [PATCH 06/11] Fix wording on website hero text. Requested by @pabloschuhmacher as a small fix. --- site/themes/pinniped/layouts/partials/hero.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/site/themes/pinniped/layouts/partials/hero.html b/site/themes/pinniped/layouts/partials/hero.html index 201f5692..7e4990f4 100644 --- a/site/themes/pinniped/layouts/partials/hero.html +++ b/site/themes/pinniped/layouts/partials/hero.html @@ -2,11 +2,11 @@

Batteries-included for Kubernetes authentication

-

Pinniped is the easy, secure way to login to your Kubernetes clusters.

+

Pinniped is the easy, secure way to log in to your Kubernetes clusters.

- \ No newline at end of file + From a4089fcc72c40575c2572ca34be953b680d2ce90 Mon Sep 17 00:00:00 2001 From: Matt Moyer Date: Tue, 23 Feb 2021 14:26:58 -0600 Subject: [PATCH 07/11] Add security headers to the website. The one bit of JS we have for the mobile menu needed some tweaking. Signed-off-by: Matt Moyer --- site/netlify.toml | 8 ++++++++ site/themes/pinniped/layouts/partials/header.html | 2 +- site/themes/pinniped/static/js/main.js | 5 ++++- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/site/netlify.toml b/site/netlify.toml index ba32a73e..3118ada5 100644 --- a/site/netlify.toml +++ b/site/netlify.toml @@ -33,3 +33,11 @@ HUGO_ENABLEGITINFO = "true" for = "/fonts/*" [headers.values] Access-Control-Allow-Origin = "*" + +[[headers]] + for = "/*" + [headers.values] + Content-Security-Policy = "default-src 'self'; img-src *" + X-Content-Type-Options = "nosniff" + X-Frame-Options = "DENY" + X-XSS-Protection = "1; mode=block" \ No newline at end of file diff --git a/site/themes/pinniped/layouts/partials/header.html b/site/themes/pinniped/layouts/partials/header.html index a1c9b005..9c6cf038 100644 --- a/site/themes/pinniped/layouts/partials/header.html +++ b/site/themes/pinniped/layouts/partials/header.html @@ -7,7 +7,7 @@
  • Blog
  • Docs
  • - diff --git a/site/themes/pinniped/static/js/main.js b/site/themes/pinniped/static/js/main.js index 8429fd75..8a96e2b7 100644 --- a/site/themes/pinniped/static/js/main.js +++ b/site/themes/pinniped/static/js/main.js @@ -3,4 +3,7 @@ function mobileNavToggle() { var menu = document.getElementById("mobile-menu").parentElement; menu.classList.toggle('mobile-menu-visible'); -} \ No newline at end of file +} +document.addEventListener('DOMContentLoaded', function () { + document.getElementById('mobile-menu-button').addEventListener('click', mobileNavToggle); +}); \ No newline at end of file From 852c1b7a27491b602ed33f7c9b31410be2200540 Mon Sep 17 00:00:00 2001 From: Matt Moyer Date: Tue, 23 Feb 2021 16:01:40 -0600 Subject: [PATCH 08/11] Fix some copy-paste errors on install-supervisor.md. Signed-off-by: Matt Moyer --- site/content/docs/howto/install-supervisor.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/site/content/docs/howto/install-supervisor.md b/site/content/docs/howto/install-supervisor.md index 49267842..a9cea70e 100644 --- a/site/content/docs/howto/install-supervisor.md +++ b/site/content/docs/howto/install-supervisor.md @@ -23,9 +23,9 @@ You should have a supported Kubernetes cluster with working HTTPS ingress capabi 1. Choose your preferred [release](https://github.com/vmware-tanzu/pinniped/releases) version number and use it to replace the version number in the URL below. -1. Install theSupervisor into the `pinniped-supervisor` namespace with default options: +1. Install the Supervisor into the `pinniped-supervisor` namespace with default options: - - `kubectl apply -f https://get.pinniped.dev/v0.4.1/install-pinniped-concierge.yaml` + - `kubectl apply -f https://get.pinniped.dev/v0.4.1/install-pinniped-supervisor.yaml` *Replace v0.4.1 with your preferred version number.* From 2254f76b30d1f1dfb858295cf994a60d5f15455d Mon Sep 17 00:00:00 2001 From: Matt Moyer Date: Wed, 24 Feb 2021 09:23:21 -0600 Subject: [PATCH 09/11] Fix a broken link, a typo, and tweak menu text. Signed-off-by: Matt Moyer --- site/content/docs/background/_index.md | 2 +- site/content/docs/howto/install-cli.md | 2 +- site/content/docs/reference/api.md | 4 ++-- site/content/docs/reference/supported-clusters.md | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/site/content/docs/background/_index.md b/site/content/docs/background/_index.md index 5916ea0e..74240e8e 100644 --- a/site/content/docs/background/_index.md +++ b/site/content/docs/background/_index.md @@ -5,7 +5,7 @@ menu: docs: name: Background identifier: background - weight: 80 + weight: 110 --- # Pinniped background diff --git a/site/content/docs/howto/install-cli.md b/site/content/docs/howto/install-cli.md index 353d8f43..8bd71893 100644 --- a/site/content/docs/howto/install-cli.md +++ b/site/content/docs/howto/install-cli.md @@ -27,7 +27,7 @@ Find the appropriate binary for your platform from the [latest release](https:// {{< buttonlink href="https://get.pinniped.dev/latest/pinniped-cli-linux-amd64" >}}Download for Linux/amd64{{< buttonicon "download.png" >}}{{< /buttonlink >}} -{{< buttonlink href="https://get.pinniped.dev/latest/pinniped-cli-windows-amd64" >}}Download for Windows/amd64{{< buttonicon "download.png" >}}{{< /buttonlink >}} +{{< buttonlink href="https://get.pinniped.dev/latest/pinniped-cli-windows-amd64.exe" >}}Download for Windows/amd64{{< buttonicon "download.png" >}}{{< /buttonlink >}} You should put the command-line tool somewhere on your `$PATH`, such as `/usr/local/bin` on macOS/Linux. You'll also need to mark the file as executable. diff --git a/site/content/docs/reference/api.md b/site/content/docs/reference/api.md index 95f8fdf2..a27b71a0 100644 --- a/site/content/docs/reference/api.md +++ b/site/content/docs/reference/api.md @@ -1,11 +1,11 @@ --- -title: API +title: API Types description: Reference for the `*.pinniped.dev` Kubernetes API groups. cascade: layout: docs menu: docs: - name: Kubernetes API + name: API Types weight: 35 parent: reference --- diff --git a/site/content/docs/reference/supported-clusters.md b/site/content/docs/reference/supported-clusters.md index 8ff538f2..62ff07fe 100644 --- a/site/content/docs/reference/supported-clusters.md +++ b/site/content/docs/reference/supported-clusters.md @@ -10,7 +10,7 @@ menu: parent: reference --- -| **Cluster Type** | **Conciege Works?** | +| **Cluster Type** | **Concierge Works?** | |-|-| | [VMware Tanzu Kubernetes Grid (TKG) clusters](https://tanzu.vmware.com/kubernetes-grid) | Yes | | [Kind clusters](https://kind.sigs.k8s.io/) | Yes | From a31c24e5a0538efcf646f7a07fcde26887070b17 Mon Sep 17 00:00:00 2001 From: Matt Moyer Date: Wed, 24 Feb 2021 22:37:31 +0000 Subject: [PATCH 10/11] Bump a bunch of minor dependencies. Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.6.1 to 1.7.0. - [Release notes](https://github.com/stretchr/testify/releases) - [Commits](https://github.com/stretchr/testify/compare/v1.6.1...v1.7.0) Bumps [github.com/go-logr/logr](https://github.com/go-logr/logr) from 0.3.0 to 0.4.0. - [Release notes](https://github.com/go-logr/logr/releases) - [Commits](https://github.com/go-logr/logr/compare/v0.3.0...v0.4.0) Bumps [k8s.io/klog/v2](https://github.com/kubernetes/klog) from 2.4.0 to 2.5.0. - [Release notes](https://github.com/kubernetes/klog/releases) - [Changelog](https://github.com/kubernetes/klog/blob/master/RELEASE.md) - [Commits](https://github.com/kubernetes/klog/compare/v2.4.0...v2.5.0) Bumps [github.com/go-logr/stdr](https://github.com/go-logr/stdr) from 0.2.0 to 0.4.0. - [Release notes](https://github.com/go-logr/stdr/releases) - [Commits](https://github.com/go-logr/stdr/compare/v0.2.0...v0.4.0) Bumps [github.com/spf13/cobra](https://github.com/spf13/cobra) from 1.1.1 to 1.1.3. - [Release notes](https://github.com/spf13/cobra/releases) - [Changelog](https://github.com/spf13/cobra/blob/master/CHANGELOG.md) - [Commits](https://github.com/spf13/cobra/compare/v1.1.1...v1.1.3) Signed-off-by: Matt Moyer --- go.mod | 11 +++++------ go.sum | 17 ++++++++++------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/go.mod b/go.mod index 35c4f83d..7547f3cb 100644 --- a/go.mod +++ b/go.mod @@ -7,8 +7,8 @@ require ( github.com/MakeNowJust/heredoc/v2 v2.0.1 github.com/coreos/go-oidc/v3 v3.0.0 github.com/davecgh/go-spew v1.1.1 - github.com/go-logr/logr v0.3.0 - github.com/go-logr/stdr v0.2.0 + github.com/go-logr/logr v0.4.0 + github.com/go-logr/stdr v0.4.0 github.com/go-openapi/spec v0.19.9 github.com/gofrs/flock v0.8.0 github.com/golang/mock v1.4.4 @@ -24,16 +24,15 @@ require ( github.com/pkg/errors v0.9.1 github.com/sclevine/agouti v3.0.0+incompatible github.com/sclevine/spec v1.4.0 - github.com/spf13/cobra v1.1.1 + github.com/spf13/cobra v1.1.3 github.com/spf13/pflag v1.0.5 - github.com/stretchr/testify v1.6.1 + github.com/stretchr/testify v1.7.0 golang.org/x/crypto v0.0.0-20201217014255-9d1352758620 golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d golang.org/x/sync v0.0.0-20201207232520-09787c993a3a golang.org/x/tools v0.0.0-20200825202427-b303f430e36d // indirect gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect gopkg.in/square/go-jose.v2 v2.5.1 - gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 // indirect k8s.io/api v0.20.4 k8s.io/apimachinery v0.20.4 @@ -41,7 +40,7 @@ require ( k8s.io/client-go v0.20.4 k8s.io/component-base v0.20.4 k8s.io/gengo v0.0.0-20201113003025-83324d819ded - k8s.io/klog/v2 v2.4.0 + k8s.io/klog/v2 v2.5.0 k8s.io/kube-aggregator v0.20.4 k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd k8s.io/utils v0.0.0-20201110183641-67b214c5f920 diff --git a/go.sum b/go.sum index cae1b25a..a8bc54aa 100644 --- a/go.sum +++ b/go.sum @@ -209,10 +209,10 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= -github.com/go-logr/logr v0.3.0 h1:q4c+kbcR0d5rSurhBR8dIgieOaYpXtsdTYfx22Cu6rs= -github.com/go-logr/logr v0.3.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= -github.com/go-logr/stdr v0.2.0 h1:EuTFw3BCZ6H/+1VNFlOLVK/sPKwmGMLx8/FTOFWuXpU= -github.com/go-logr/stdr v0.2.0/go.mod h1:NO1vneyJDqKVgJYnxhwXWWmQPOvNM391IG3H8ql3jiA= +github.com/go-logr/logr v0.4.0 h1:K7/B1jt6fIBQVd4Owv2MqGQClcgf0R266+7C/QjRcLc= +github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-logr/stdr v0.4.0 h1:ijk9G/xzDRZdMU1QRhLYdHuWvNZWqte+NZMOGsiKWbc= +github.com/go-logr/stdr v0.4.0/go.mod h1:NO1vneyJDqKVgJYnxhwXWWmQPOvNM391IG3H8ql3jiA= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= @@ -961,8 +961,9 @@ github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3 github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v0.0.7/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= -github.com/spf13/cobra v1.1.1 h1:KfztREH0tPxJJ+geloSLaAkaPkr4ki2Er5quFV1TDo4= github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= +github.com/spf13/cobra v1.1.3 h1:xghbfqPkxzxP3C/f3n5DdpAbdKLj4ZE4BWQI362l53M= +github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= @@ -987,8 +988,9 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.1.1/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= @@ -1515,8 +1517,9 @@ k8s.io/gengo v0.0.0-20201113003025-83324d819ded h1:JApXBKYyB7l9xx+DK7/+mFjC7A9Bt k8s.io/gengo v0.0.0-20201113003025-83324d819ded/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/klog/v2 v2.4.0 h1:7+X0fUguPyrKEC4WjH8iGDg3laWgMo5tMnRTIGTTxGQ= k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/klog/v2 v2.5.0 h1:8mOnjf1RmUPW6KRqQCfYSZq/K20Unmp3IhuZUhxl8KI= +k8s.io/klog/v2 v2.5.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= k8s.io/kube-aggregator v0.20.4 h1:j/SUwPy1eO+ud3XOUGmH18gISPyerqhXOoNRZDbv3fs= k8s.io/kube-aggregator v0.20.4/go.mod h1:0ixQ9De7KXyHteXizS6nVtrnKqGa4kiuxl9rEBsNccw= k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd h1:sOHNzJIkytDF6qadMNKhhDRpc6ODik8lVC6nOur7B2c= From c8fc8a0b655344513a50e1560059b4ef676fc86b Mon Sep 17 00:00:00 2001 From: Matt Moyer Date: Thu, 25 Feb 2021 08:11:37 -0600 Subject: [PATCH 11/11] Reformat some log-based test assertions. These are prone to breaking when stdr is upgraded because they rely on the exact ordering of keys in the log message. If we have more problems we can rewrite the assertions to be more robust, but for this time I'm just fixing them to match the new output. Signed-off-by: Matt Moyer --- .../upstreamwatcher/upstreamwatcher_test.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/internal/controller/supervisorconfig/upstreamwatcher/upstreamwatcher_test.go b/internal/controller/supervisorconfig/upstreamwatcher/upstreamwatcher_test.go index 32ccf198..cba27c39 100644 --- a/internal/controller/supervisorconfig/upstreamwatcher/upstreamwatcher_test.go +++ b/internal/controller/supervisorconfig/upstreamwatcher/upstreamwatcher_test.go @@ -152,7 +152,7 @@ func TestController(t *testing.T) { wantLogs: []string{ `upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="secret \"test-client-secret\" not found" "reason"="SecretNotFound" "status"="False" "type"="ClientCredentialsValid"`, `upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="discovered issuer configuration" "reason"="Success" "status"="True" "type"="OIDCDiscoverySucceeded"`, - `upstream-observer "error"="OIDCIdentityProvider has a failing condition" "msg"="found failing condition" "message"="secret \"test-client-secret\" not found" "name"="test-name" "namespace"="test-namespace" "reason"="SecretNotFound" "type"="ClientCredentialsValid"`, + `upstream-observer "msg"="found failing condition" "error"="OIDCIdentityProvider has a failing condition" "message"="secret \"test-client-secret\" not found" "name"="test-name" "namespace"="test-namespace" "reason"="SecretNotFound" "type"="ClientCredentialsValid"`, }, wantResultingCache: []provider.UpstreamOIDCIdentityProviderI{}, wantResultingUpstreams: []v1alpha1.OIDCIdentityProvider{{ @@ -198,7 +198,7 @@ func TestController(t *testing.T) { wantLogs: []string{ `upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="referenced Secret \"test-client-secret\" has wrong type \"some-other-type\" (should be \"secrets.pinniped.dev/oidc-client\")" "reason"="SecretWrongType" "status"="False" "type"="ClientCredentialsValid"`, `upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="discovered issuer configuration" "reason"="Success" "status"="True" "type"="OIDCDiscoverySucceeded"`, - `upstream-observer "error"="OIDCIdentityProvider has a failing condition" "msg"="found failing condition" "message"="referenced Secret \"test-client-secret\" has wrong type \"some-other-type\" (should be \"secrets.pinniped.dev/oidc-client\")" "name"="test-name" "namespace"="test-namespace" "reason"="SecretWrongType" "type"="ClientCredentialsValid"`, + `upstream-observer "msg"="found failing condition" "error"="OIDCIdentityProvider has a failing condition" "message"="referenced Secret \"test-client-secret\" has wrong type \"some-other-type\" (should be \"secrets.pinniped.dev/oidc-client\")" "name"="test-name" "namespace"="test-namespace" "reason"="SecretWrongType" "type"="ClientCredentialsValid"`, }, wantResultingCache: []provider.UpstreamOIDCIdentityProviderI{}, wantResultingUpstreams: []v1alpha1.OIDCIdentityProvider{{ @@ -243,7 +243,7 @@ func TestController(t *testing.T) { wantLogs: []string{ `upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="referenced Secret \"test-client-secret\" is missing required keys [\"clientID\" \"clientSecret\"]" "reason"="SecretMissingKeys" "status"="False" "type"="ClientCredentialsValid"`, `upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="discovered issuer configuration" "reason"="Success" "status"="True" "type"="OIDCDiscoverySucceeded"`, - `upstream-observer "error"="OIDCIdentityProvider has a failing condition" "msg"="found failing condition" "message"="referenced Secret \"test-client-secret\" is missing required keys [\"clientID\" \"clientSecret\"]" "name"="test-name" "namespace"="test-namespace" "reason"="SecretMissingKeys" "type"="ClientCredentialsValid"`, + `upstream-observer "msg"="found failing condition" "error"="OIDCIdentityProvider has a failing condition" "message"="referenced Secret \"test-client-secret\" is missing required keys [\"clientID\" \"clientSecret\"]" "name"="test-name" "namespace"="test-namespace" "reason"="SecretMissingKeys" "type"="ClientCredentialsValid"`, }, wantResultingCache: []provider.UpstreamOIDCIdentityProviderI{}, wantResultingUpstreams: []v1alpha1.OIDCIdentityProvider{{ @@ -291,7 +291,7 @@ func TestController(t *testing.T) { wantLogs: []string{ `upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="loaded client credentials" "reason"="Success" "status"="True" "type"="ClientCredentialsValid"`, `upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="spec.certificateAuthorityData is invalid: illegal base64 data at input byte 7" "reason"="InvalidTLSConfig" "status"="False" "type"="OIDCDiscoverySucceeded"`, - `upstream-observer "error"="OIDCIdentityProvider has a failing condition" "msg"="found failing condition" "message"="spec.certificateAuthorityData is invalid: illegal base64 data at input byte 7" "name"="test-name" "namespace"="test-namespace" "reason"="InvalidTLSConfig" "type"="OIDCDiscoverySucceeded"`, + `upstream-observer "msg"="found failing condition" "error"="OIDCIdentityProvider has a failing condition" "message"="spec.certificateAuthorityData is invalid: illegal base64 data at input byte 7" "name"="test-name" "namespace"="test-namespace" "reason"="InvalidTLSConfig" "type"="OIDCDiscoverySucceeded"`, }, wantResultingCache: []provider.UpstreamOIDCIdentityProviderI{}, wantResultingUpstreams: []v1alpha1.OIDCIdentityProvider{{ @@ -339,7 +339,7 @@ func TestController(t *testing.T) { wantLogs: []string{ `upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="loaded client credentials" "reason"="Success" "status"="True" "type"="ClientCredentialsValid"`, `upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="spec.certificateAuthorityData is invalid: no certificates found" "reason"="InvalidTLSConfig" "status"="False" "type"="OIDCDiscoverySucceeded"`, - `upstream-observer "error"="OIDCIdentityProvider has a failing condition" "msg"="found failing condition" "message"="spec.certificateAuthorityData is invalid: no certificates found" "name"="test-name" "namespace"="test-namespace" "reason"="InvalidTLSConfig" "type"="OIDCDiscoverySucceeded"`, + `upstream-observer "msg"="found failing condition" "error"="OIDCIdentityProvider has a failing condition" "message"="spec.certificateAuthorityData is invalid: no certificates found" "name"="test-name" "namespace"="test-namespace" "reason"="InvalidTLSConfig" "type"="OIDCDiscoverySucceeded"`, }, wantResultingCache: []provider.UpstreamOIDCIdentityProviderI{}, wantResultingUpstreams: []v1alpha1.OIDCIdentityProvider{{ @@ -384,7 +384,7 @@ func TestController(t *testing.T) { wantLogs: []string{ `upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="loaded client credentials" "reason"="Success" "status"="True" "type"="ClientCredentialsValid"`, `upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="failed to perform OIDC discovery against \"invalid-url\"" "reason"="Unreachable" "status"="False" "type"="OIDCDiscoverySucceeded"`, - `upstream-observer "error"="OIDCIdentityProvider has a failing condition" "msg"="found failing condition" "message"="failed to perform OIDC discovery against \"invalid-url\"" "name"="test-name" "namespace"="test-namespace" "reason"="Unreachable" "type"="OIDCDiscoverySucceeded"`, + `upstream-observer "msg"="found failing condition" "error"="OIDCIdentityProvider has a failing condition" "message"="failed to perform OIDC discovery against \"invalid-url\"" "name"="test-name" "namespace"="test-namespace" "reason"="Unreachable" "type"="OIDCDiscoverySucceeded"`, }, wantResultingCache: []provider.UpstreamOIDCIdentityProviderI{}, wantResultingUpstreams: []v1alpha1.OIDCIdentityProvider{{ @@ -430,7 +430,7 @@ func TestController(t *testing.T) { wantLogs: []string{ `upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="loaded client credentials" "reason"="Success" "status"="True" "type"="ClientCredentialsValid"`, `upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="failed to parse authorization endpoint URL: parse \"%\": invalid URL escape \"%\"" "reason"="InvalidResponse" "status"="False" "type"="OIDCDiscoverySucceeded"`, - `upstream-observer "error"="OIDCIdentityProvider has a failing condition" "msg"="found failing condition" "message"="failed to parse authorization endpoint URL: parse \"%\": invalid URL escape \"%\"" "name"="test-name" "namespace"="test-namespace" "reason"="InvalidResponse" "type"="OIDCDiscoverySucceeded"`, + `upstream-observer "msg"="found failing condition" "error"="OIDCIdentityProvider has a failing condition" "message"="failed to parse authorization endpoint URL: parse \"%\": invalid URL escape \"%\"" "name"="test-name" "namespace"="test-namespace" "reason"="InvalidResponse" "type"="OIDCDiscoverySucceeded"`, }, wantResultingCache: []provider.UpstreamOIDCIdentityProviderI{}, wantResultingUpstreams: []v1alpha1.OIDCIdentityProvider{{ @@ -476,7 +476,7 @@ func TestController(t *testing.T) { wantLogs: []string{ `upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="loaded client credentials" "reason"="Success" "status"="True" "type"="ClientCredentialsValid"`, `upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="authorization endpoint URL scheme must be \"https\", not \"http\"" "reason"="InvalidResponse" "status"="False" "type"="OIDCDiscoverySucceeded"`, - `upstream-observer "error"="OIDCIdentityProvider has a failing condition" "msg"="found failing condition" "message"="authorization endpoint URL scheme must be \"https\", not \"http\"" "name"="test-name" "namespace"="test-namespace" "reason"="InvalidResponse" "type"="OIDCDiscoverySucceeded"`, + `upstream-observer "msg"="found failing condition" "error"="OIDCIdentityProvider has a failing condition" "message"="authorization endpoint URL scheme must be \"https\", not \"http\"" "name"="test-name" "namespace"="test-namespace" "reason"="InvalidResponse" "type"="OIDCDiscoverySucceeded"`, }, wantResultingCache: []provider.UpstreamOIDCIdentityProviderI{}, wantResultingUpstreams: []v1alpha1.OIDCIdentityProvider{{