| index 412ca779a..007eedd41 100644 |
| --- a/implementation/carloku-paid-launch/copy-review/billing-page/preview/index.html |
| +++ b/implementation/carloku-paid-launch/copy-review/billing-page/preview/index.html |
| @@ -40,19 +40,19 @@ |
| overflow-x: auto; font-family: var(--mono); font-size: 0.85rem; line-height: 1.6; |
| } |
| pre code { background: none; padding: 0; } |
| - |
| + |
| .changelog { white-space: pre-wrap; } |
| select, input[type=text], input[type=search] { |
| font: inherit; font-family: var(--sans); font-size: 0.9rem; color: var(--ink); background: var(--bg); |
| border: 1px solid var(--rule); border-radius: 0.4rem; padding: 0.3rem 0.5rem; |
| } |
| td form { display: flex; gap: 0.4rem; align-items: center; flex-wrap: wrap; margin: 0; } |
| - |
| + |
| form.inline { display: inline; margin: 0; } |
| form.inline button { vertical-align: baseline; } |
| - |
| + |
| form.listctl { display: flex; gap: 0.6rem; flex-wrap: wrap; margin: 0 0 0.6rem; } |
| - |
| + |
| .icon { width: 1em; height: 1em; flex: none; vertical-align: -0.125em; } |
| header { |
| max-width: 64rem; margin: 0 auto; padding: 1.4rem 0; |
| @@ -65,7 +65,7 @@ |
| font-size: 0.9rem; |
| } |
| header .addr { color: var(--muted); } |
| - |
| + |
| header .switcher { |
| position: relative; |
| } |
| @@ -76,12 +76,12 @@ |
| } |
| header .switcher > summary::-webkit-details-marker { display: none; } |
| header .switcher > summary:hover { background: var(--accent-soft); } |
| - |
| + |
| header .switcher .current-name { |
| font-weight: 700; min-width: 0; max-width: 14rem; |
| overflow: hidden; text-overflow: ellipsis; white-space: nowrap; |
| } |
| - |
| + |
| header .switcher > summary > .icon { color: var(--muted); align-self: center; width: 0.9em; } |
| header .switcher[open] > summary > .icon { transform: rotate(180deg); } |
| header .switcher-menu { |
| @@ -99,7 +99,7 @@ |
| } |
| header .switcher-menu a:hover, header .switcher-menu a:focus { background: var(--accent-soft); } |
| header .switcher-menu .current { font-weight: 600; background: var(--accent-soft); } |
| - |
| + |
| header .switcher-menu .mark { |
| color: var(--accent); width: 0.9rem; flex: none; |
| display: flex; align-self: center; |
| @@ -112,7 +112,7 @@ |
| h1 { font-size: 1.9rem; line-height: 1.15; margin: 0 0 1rem; } |
| h2 { font-size: 1.25rem; margin: 2rem 0 0.75rem; } |
| h3 { font-size: 1rem; margin: 1.5rem 0 0.5rem; } |
| - |
| + |
| .settings-row { display: flex; gap: 0.6rem; flex-wrap: wrap; align-items: center; margin: 0 0 0.75rem; } |
| .settings-layout { |
| display: grid; grid-template-columns: minmax(10rem, 13rem) minmax(0, 1fr); |
| @@ -133,7 +133,7 @@ |
| p { max-width: 40rem; margin: 0 0 1rem; } |
| .lede { font-size: 1.15rem; color: var(--muted); } |
| .small { font-size: 0.9rem; color: var(--muted); } |
| - |
| + |
| .visually-hidden { |
| position: absolute; width: 1px; height: 1px; overflow: hidden; |
| clip-path: inset(50%); white-space: nowrap; |
| @@ -154,7 +154,7 @@ |
| .instance-facts dt { color: var(--muted); } |
| .instance-facts dd { margin: 0; overflow-wrap: anywhere; } |
| .instance-facts .cellspark { max-width: 24rem; } |
| - |
| + |
| #logs-filter { display: flex; flex-wrap: wrap; align-items: end; gap: 0.65rem; margin-bottom: 1rem; } |
| #logs-filter label { display: flex; flex-direction: column; gap: 0.25rem; max-width: 100%; } |
| #logs-filter select, #logs-filter input { max-width: 100%; margin: 0; } |
| @@ -165,21 +165,21 @@ |
| min-height: 16rem; max-height: 70vh; overflow: auto; |
| font-family: var(--mono); font-size: 0.8rem; line-height: 1.55; |
| } |
| - |
| + |
| .tl { white-space: pre; width: max-content; min-width: 100%; padding-right: 1rem; } |
| - |
| + |
| .tl-t, .tl-h, .tl-f { color: var(--muted); } |
| .tl-s { color: var(--accent); } |
| - |
| + |
| .tl-warn .tl-m { color: var(--warn, #a6790f); } |
| .tl-error .tl-m { color: var(--bad); font-weight: 600; } |
| table { border-collapse: collapse; width: 100%; margin: 0 0 1rem; font-size: 0.95rem; } |
| .tiles { display: flex; flex-wrap: wrap; gap: 1rem; margin: 0 0 1.5rem; } |
| .tile { flex: 1 1 10rem; background: var(--accent-soft); border-radius: 0.6rem; padding: 1rem 1.1rem; } |
| - |
| + |
| a.tile { color: var(--ink); text-decoration: none; } |
| a.tile:hover { outline: 1px solid var(--accent); } |
| - |
| + |
| .stat-tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr)); } |
| .tile h2 { |
| margin: 0 0 0.35rem; font-family: var(--mono); font-size: 0.78rem; text-transform: uppercase; |
| @@ -187,30 +187,30 @@ |
| } |
| .tile-value { font-size: 1.6rem; font-weight: 600; margin: 0; } |
| .tile-detail { color: var(--muted); font-size: 0.8rem; margin: 0.25rem 0 0; } |
| - |
| + |
| .chip { |
| display: inline-block; font-family: var(--mono); font-size: 0.78rem; font-weight: 500; |
| padding: 0.15rem 0.55rem; border-radius: 999px; margin: 0.15rem 0.3rem 0.15rem 0; |
| } |
| .chip-stale { border: 1px solid var(--warn, #a6790f); color: var(--warn, #a6790f); } |
| - |
| + |
| .chip-canary { border: 1px solid var(--accent); color: var(--accent); } |
| .chip-prod { background: var(--bad); color: var(--bg); } |
| - |
| + |
| .chip-expired { border: 1px solid var(--warn, #a6790f); color: var(--warn, #a6790f); } |
| - |
| + |
| .chip-env { border: 1px solid var(--rule); color: var(--muted); } |
| - |
| + |
| .chip-health-ok { border: 1px solid var(--good); color: var(--good); } |
| .chip-health-attention { background: var(--warn, #a6790f); color: var(--bg); } |
| .chip-health-notdeployed { border: 1px solid var(--rule); color: var(--muted); } |
| .chip-health-unknown { border: 1px solid var(--warn, #a6790f); color: var(--warn, #a6790f); } |
| - |
| + |
| .chip-freetier-inside { border: 1px solid var(--warn, #a6790f); color: var(--warn, #a6790f); } |
| .chip-freetier-partial { border: 1px solid var(--accent); color: var(--accent); } |
| .chip-freetier-paying { border: 1px solid var(--good); color: var(--good); } |
| .chip-freetier-pooled { border: 1px solid var(--rule); color: var(--muted); } |
| - |
| + |
| .chip-tier-unassigned { border: 1px solid var(--rule); color: var(--muted); } |
| .chip-tier-try { border: 1px solid var(--rule); color: var(--muted); } |
| .chip-tier-pool { border: 1px solid var(--rule); color: var(--muted); } |
| @@ -221,15 +221,15 @@ |
| .chip-up { background: var(--accent-soft); color: #2f7a4f; } |
| .chip-down { background: var(--accent-soft); color: var(--bad); } |
| .chips { display: flex; flex-wrap: wrap; margin: 0 0 1rem; } |
| - |
| + |
| .bar { display: inline-block; width: 6rem; height: 0.5rem; border-radius: 999px; background: var(--accent-soft); vertical-align: middle; overflow: hidden; } |
| .bar-fill { display: block; height: 100%; background: var(--accent); } |
| - |
| + |
| .knob-row { display: flex; gap: 0.6rem; align-items: center; margin: 0 0 0.5rem; flex-wrap: wrap; } |
| .knob-row label { min-width: 12rem; color: var(--muted); font-size: 0.9rem; } |
| .knob-row input[type=number], .knob-row input[type=text] { width: 8rem; } |
| .knob-row input[type=range] { width: 12rem; } |
| - |
| + |
| .flow { margin: 0 0 1.75rem; } |
| .flow-line { |
| --flow-y: 0.52rem; |
| @@ -254,7 +254,7 @@ |
| letter-spacing: 0.05em; color: var(--muted); font-weight: 600; |
| } |
| .flow-version { margin: 0.3rem 0 0; font-size: 0.95rem; } |
| - |
| + |
| .flow-stage:not(.is-held) .flow-version { color: var(--muted); } |
| .flow-note { margin: 0.25rem 0 0; font-size: 0.78rem; color: var(--muted); } |
| .flow-addrs { |
| @@ -270,7 +270,7 @@ |
| .flow-tone-bad .flow-health { color: var(--bad); font-weight: 600; } |
| .flow-band { margin: 1.4rem 0 0.7rem; font-size: 0.9rem; color: var(--muted); } |
| .flow-caption { margin: 1.1rem 0 0; } |
| - |
| + |
| @media (max-width: 46rem) { |
| .settings-layout { display: block; } |
| .settings-nav { |
| @@ -292,7 +292,7 @@ |
| .flow-stage.is-carried::before { border-left-color: var(--accent); } |
| .flow-stage.is-carried::after { border-top-color: var(--accent); border-left-color: transparent; } |
| } |
| - |
| + |
| .ladder { list-style: none; margin: 0 0 1rem; padding: 0; max-width: 40rem; } |
| .rung { |
| border: 1px solid var(--rule); border-radius: 0.6rem; padding: 0.8rem 1rem; |
| @@ -307,7 +307,7 @@ |
| .rung .gate { margin: 0.5rem 0 0; } |
| .rung .routes { list-style: none; margin: 0.3rem 0 0.6rem; padding: 0; font-size: 0.95rem; } |
| .rung .routes li { padding: 0.1rem 0; } |
| - |
| + |
| .step { |
| display: flex; align-items: baseline; gap: 0.5rem; flex-wrap: wrap; |
| margin: 0.7rem -1rem -0.8rem; padding: 0.5rem 1rem; |
| @@ -335,62 +335,62 @@ |
| } |
| button:not(.linkish):hover, .btn:hover { background: var(--accent-strong); } |
| button.linkish.danger { color: var(--bad); } |
| - |
| + |
| .btn-sm, button.btn-sm { |
| font-size: 0.85rem; padding: 0.35rem 0.8rem; border-radius: 0.4rem; |
| } |
| button.btn-danger, .btn-danger { background: var(--bad); color: var(--bg); } |
| button.btn-danger:hover, .btn-danger:hover { background: var(--bad); filter: brightness(0.9); } |
| - |
| + |
| td .cell-value { display: inline-block; min-width: 3.5rem; font-weight: 600; } |
| .cellspark { width: 6rem; height: 1.1rem; vertical-align: -0.2rem; color: var(--muted); } |
| .cellspark polyline { stroke-width: 2.5; } |
| - |
| + |
| .feed { list-style: none; margin: 0 0 0.5rem; padding: 0; max-width: 40rem; } |
| .feed li { padding: 0.25rem 0; border-bottom: 1px solid var(--rule); } |
| .feed li:last-child { border-bottom: 0; } |
| - |
| + |
| .confirm-card { |
| border: 1px solid var(--rule); border-radius: 0.6rem; |
| padding: 1.25rem 1.4rem; max-width: 40rem; margin: 0 0 1rem; |
| } |
| .confirm-card .actions { display: flex; gap: 0.9rem; align-items: center; margin-top: 1rem; } |
| .confirm-card .confirm-note { margin: 0.8rem 0 0; } |
| - |
| - |
| + |
| + |
| .archwrap { overflow-x: auto; margin: 0.2rem 0 1.6rem; } |
| - |
| + |
| h4.archband { |
| border-top: 1px solid var(--rule); color: var(--muted); |
| font: 600 0.8rem var(--mono); letter-spacing: 0.02em; |
| margin: 1.5rem 0 0; padding-top: 0.5rem; |
| } |
| - |
| + |
| .archsvg { display: block; } |
| .archsvg rect { fill: var(--accent-soft); stroke: var(--rule); } |
| .archsvg .archnode-box rect { stroke: var(--accent); } |
| .archsvg .archtitle { fill: var(--ink); font: 600 13px var(--sans); } |
| .archsvg .archsub { fill: var(--muted); font: 400 11px var(--sans); } |
| - |
| + |
| .archsvg .archedge { fill: none; stroke: var(--muted); stroke-width: 1.5; } |
| - |
| + |
| .archsvg .archalarm { fill: var(--good); } |
| .archsvg .archalarm-firing { fill: var(--bad); } |
| - |
| + |
| .archbox { |
| border: 1px solid var(--rule); border-radius: 0.6rem; |
| padding: 0.9rem 1.1rem; margin: 0 0 0.6rem; max-width: 64rem; |
| } |
| .archbox h3 { margin: 0 0 0.3rem; } |
| .archbox p { margin: 0 0 0.2rem; } |
| - |
| + |
| .archbox .fact + .fact::before { content: " · "; color: var(--muted); } |
| footer { |
| max-width: 64rem; margin: 0 auto; padding: 1.25rem 0 2rem; |
| border-top: 1px solid var(--rule); |
| font-size: 0.85rem; color: var(--muted); |
| } |
| - |
| + |
| .pagehead { margin: 0 0 1.75rem; } |
| .eyebrow { |
| font-family: var(--mono); font-size: 0.75rem; letter-spacing: 0.08em; |
| @@ -398,9 +398,9 @@ |
| } |
| .pagehead h1 { margin: 0 0 0.35rem; } |
| .pagehead .lede { margin: 0; font-size: 1.05rem; } |
| - |
| + |
| .reveal > summary { font-size: 1.1rem; font-weight: 600; cursor: pointer; } |
| - |
| + |
| .tabs { |
| display: flex; flex-wrap: wrap; gap: 1.25rem; margin: 0 0 2rem; |
| border-bottom: 1px solid var(--rule); |
| @@ -415,11 +415,46 @@ |
| header nav a[aria-current] { color: var(--ink); font-weight: 600; text-decoration: none; } |
| header nav a.addr { color: var(--muted); text-decoration: none; } |
| header nav a.addr:hover { text-decoration: underline; } |
| + |
| + .billing-layout { max-width: 60rem; } |
| + .billing-current { padding: 1.25rem 1.5rem; border: 1px solid var(--rule); border-radius: .85rem; background: var(--accent-soft); margin-bottom: 2rem; } |
| + .billing-current h2 { margin-top: 0; } |
| + .billing-current p:last-child { margin-bottom: 0; } |
| + .billing-layout .billing-quote { max-width: none; display: flex; align-items: end; gap: 1rem; padding: 1rem 0; margin: 0 0 1rem; } |
| + .billing-quote label { flex: 1; max-width: 25rem; } |
| + .billing-layout select, .billing-layout input[type=text] { display: block; width: 100%; padding: .7rem .8rem; margin-top: .4rem; } |
| + .billing-plan-options { border: 0; display: grid; grid-template-columns: repeat(3,minmax(0,1fr)); gap: .85rem; margin: 0 0 1.5rem; padding: 0; } |
| + .billing-plan-option { display: flex; gap: .7rem; align-items: start; border: 1px solid var(--rule); border-radius: .8rem; padding: 1.2rem; cursor: pointer; } |
| + .billing-plan-option input { margin-top: .35rem; accent-color: var(--accent); flex: none; } |
| + .billing-plan-option-body { display: flex; flex-direction: column; gap: .2rem; } |
| + .billing-option-price { font-size: 1.8rem; font-weight: 650; letter-spacing: -.04em; margin-top: .5rem; } |
| + .billing-plan-option:has(input:checked) { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); background: var(--accent-soft); } |
| + .billing-plan-option:has(input:focus-visible) { outline: 3px solid var(--accent); outline-offset: 3px; } |
| + .billing-plan-option.unavailable { opacity: .55; cursor: not-allowed; } |
| + .billing-inclusions { border: 1px solid var(--rule); border-radius: .8rem; margin-bottom: 1rem; } |
| + .billing-inclusions table { width: 100%; margin: 0; } |
| + .billing-inclusions th, .billing-inclusions td { padding: 1rem; vertical-align: top; } |
| + .billing-inclusions th { text-align: left; } |
| + .billing-inclusions td:nth-child(2) { min-width: 10rem; } |
| + .billing-address { display: grid; grid-template-columns: 2fr 1fr; gap: 1rem; margin-top: 1.5rem; } |
| + .billing-address label { display: block; font-weight: 550; } |
| + .billing-payment { margin-top: 1.5rem; border-top: 1px solid var(--rule); padding-top: 1.5rem; } |
| + .billing-consent { display: block; max-width: 48rem; } |
| + .billing-payment button { padding: .8rem 1.3rem; } |
| + .billing-payment .small { margin-top: .75rem; } |
| + @media (max-width: 640px) { |
| + .billing-plan-options, .billing-address { grid-template-columns: 1fr; } |
| + .billing-layout .billing-quote { display: block; } |
| + .billing-quote button { margin-top: .8rem; } |
| + .billing-inclusions table { min-width: 38rem; } |
| + .billing-plan-option-body { flex: 1; } |
| + .billing-option-price { margin-top: .1rem; } |
| + } |
| </style> |
| <style>.preview-state{border-top:3px dashed var(--accent);margin:3rem 0 0;padding-top:1rem}.preview-label{font:600 .85rem/1.4 var(--sans);color:var(--accent);text-transform:uppercase;letter-spacing:.04em;max-width:64rem;margin:0 auto .5rem}</style></head> |
| <body> |
| <header> |
| - |
| + |
| <details class="switcher" id="switcher"> |
| <summary> |
| <span class="small">Account</span> |
| @@ -431,24 +466,24 @@ |
| <li> |
| <span class="current" aria-current="true"><span class="mark"><svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg></span>ops</span> |
| </li> |
| - |
| + |
| </ul> |
| <hr> |
| <div class="new"><a href="/accounts/new"><span class="mark"><svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14"/><path d="M12 5v14"/></svg></span>New account</a></div> |
| </div> |
| </details> |
| - |
| + |
| <nav> |
| - |
| + |
| <a href="/a/ops/">Apps</a> |
| <a href="/a/ops/fleet">Fleet</a> |
| <a href="/a/ops/team">Team</a> |
| <a href="/a/ops/billing" aria-current="page" data-copy="billing.nav">Billing</a> |
| <a href="/a/ops/settings">Settings</a> |
| - |
| + |
| <a class="addr" href="/settings" title="Your settings">paul@keymail.dev</a> |
| <form method="post" action="/auth/signout"> |
| - <input type="hidden" name="csrf" value="kNaVjkqrWoKQCUW0HrmSh6u20nFOLYYgAlZvEDeCt_o"> |
| + <input type="hidden" name="csrf" value="QyDPBgnssyCMLbG0IoQxSv_nTUejKYIiQZS9X3LSn1Q"> |
| <button class="linkish" type="submit">Sign out</button> |
| </form> |
| </nav> |
| @@ -464,12 +499,14 @@ |
| |
| |
| |
| +<div class="billing-layout"> |
| <div class="pagehead"> |
| <p class="eyebrow">Account · ops</p> |
| <h1>Billing</h1> |
| <p class="lede"><span data-copy="billing.lede">Your plan, what it includes, and how to change it.</span></p> |
| </div> |
| |
| +<section class="billing-current"> |
| <h2><span data-copy="billing.current.heading">Your plan</span></h2> |
| |
| <p><span data-copy="billing.current.free">Free. One member, 3 apps, 100 awake hours a month, 250 MB of storage and 1 GB of transfer. Apps sleep after 2 minutes idle.</span></p> |
| @@ -478,17 +515,18 @@ |
| |
| |
| |
| +</section> |
| |
| |
| -<h2><span data-copy="billing.choose.heading">Choose a plan</span></h2> |
| +<h2 id="billing-choose-heading"><span data-copy="billing.choose.heading">Choose a plan</span></h2> |
| <p class="small"><span data-copy="billing.choose.lede">Prices are per year, before VAT, and depend on your billing country. The exact price is shown before you pay.</span></p> |
| |
| -<form class="signin" method="get" action="/a/bab/billing"> |
| +<form class="signin billing-quote" method="get" action="/a/bab/billing"> |
| <label><span data-copy="billing.country.label">Billing country</span> |
| <select name="country"> |
| <option value="" data-copy="billing.country.placeholder">Choose a country</option> |
| <option value="IE" selected>Ireland</option> |
| - |
| + |
| </select> |
| </label> |
| <button class="linkish" type="submit"><span data-copy="billing.quote.button">Show prices for this country</span></button> |
| @@ -496,58 +534,87 @@ |
| |
| <p class="small">Prices for Ireland are 100% of the base price, and so are the monthly inclusions.</p> |
| |
| -<form method="post" action="/a/bab/billing/checkout"> |
| - <input type="hidden" name="csrf" value="kNaVjkqrWoKQCUW0HrmSh6u20nFOLYYgAlZvEDeCt_o"> |
| - <div class="tablewrap"> |
| +<form class="billing-checkout" method="post" action="/a/bab/billing/checkout"> |
| + <input type="hidden" name="csrf" value="QyDPBgnssyCMLbG0IoQxSv_nTUejKYIiQZS9X3LSn1Q"> |
| + <fieldset class="billing-plan-options" aria-labelledby="billing-choose-heading"> |
| + |
| + <label class="billing-plan-option"> |
| + <input type="radio" name="plan" value="personal" required> |
| + <span class="billing-plan-option-body"><strong><span data-copy="billing.plan.personal.name">Personal</span></strong> |
| + <span class="billing-option-price">€24</span> |
| + <span class="small"><span data-copy="billing.price.peryear">a year</span></span> |
| + </span> |
| + </label> |
| + |
| + <label class="billing-plan-option"> |
| + <input type="radio" name="plan" value="community" required> |
| + <span class="billing-plan-option-body"><strong><span data-copy="billing.plan.community.name">Community</span></strong> |
| + <span class="billing-option-price">€5</span> |
| + <span class="small"><span data-copy="billing.price.permember">per member a year</span></span> |
| + </span> |
| + </label> |
| + |
| + <label class="billing-plan-option"> |
| + <input type="radio" name="plan" value="business" required> |
| + <span class="billing-plan-option-body"><strong><span data-copy="billing.plan.business.name">Business</span></strong> |
| + <span class="billing-option-price">€50</span> |
| + <span class="small"><span data-copy="billing.price.permember">per member a year</span></span> |
| + </span> |
| + </label> |
| + |
| + </fieldset> |
| + <div class="tablewrap billing-inclusions"> |
| <table> |
| - |
| + |
| <tr> |
| - <td><label><input type="radio" name="plan" value="personal" required> |
| - <span data-copy="billing.plan.personal.name">Personal</span></label></td> |
| + <th scope="row"><span data-copy="billing.plan.personal.name">Personal</span></th> |
| <td><strong>€24</strong> <span data-copy="billing.price.peryear">a year</span></td> |
| <td class="small"><span data-copy="billing.plan.personal.blurb">One member. Each month: 85 awake hours, 2 GB storage, 2 GB transfer.</span></td> |
| </tr> |
| - |
| + |
| <tr> |
| - <td><label><input type="radio" name="plan" value="community" required> |
| - <span data-copy="billing.plan.community.name">Community</span></label></td> |
| + <th scope="row"><span data-copy="billing.plan.community.name">Community</span></th> |
| <td><strong>€5</strong> <span data-copy="billing.price.permember">per member a year</span> |
| <br><span class="small">€50 <span data-copy="billing.price.peryear">a year</span></span></td> |
| <td class="small"><span data-copy="billing.plan.community.blurb">Per member, minimum 10. Each member adds, per month: 17 awake hours, 0.5 GB storage, 0.4 GB transfer.</span></td> |
| </tr> |
| - |
| + |
| <tr> |
| - <td><label><input type="radio" name="plan" value="business" required> |
| - <span data-copy="billing.plan.business.name">Business</span></label></td> |
| + <th scope="row"><span data-copy="billing.plan.business.name">Business</span></th> |
| <td><strong>€50</strong> <span data-copy="billing.price.permember">per member a year</span> |
| <br><span class="small">€500 <span data-copy="billing.price.peryear">a year</span></span></td> |
| <td class="small"><span data-copy="billing.plan.business.blurb">Per member, minimum 10. Each member adds, per month: 170 awake hours, 5 GB storage, 3 GB transfer, 30,000 replication writes. Priority support.</span></td> |
| </tr> |
| - |
| + |
| </table> |
| </div> |
| <p class="small"><span data-copy="billing.plan.community.name">Community</span> and <span data-copy="billing.plan.business.name">Business</span> are priced per member. You have 1 members; the minimum is 10.</p> |
| + <div class="billing-address"> |
| <p><label><span data-copy="billing.country.label">Billing country</span> |
| <select name="country" required> |
| <option value="" data-copy="billing.country.placeholder">Choose a country</option> |
| <option value="IE" selected>Ireland</option> |
| - |
| + |
| </select> |
| </label></p> |
| <p><label><span data-copy="billing.postal.label">Postal code</span> |
| <input type="text" name="postal" autocomplete="postal-code"> |
| </label></p> |
| + </div> |
| <p class="small"><span data-copy="billing.postal.help">Needed in the United States, Canada and India, where tax depends on it. Leave it empty elsewhere. We do not keep it.</span></p> |
| - <p><label><input type="checkbox" name="consent" value="2026-09-07-v1" required> |
| + <div class="billing-payment"> |
| + <p><label class="billing-consent"><input type="checkbox" name="consent" value="2026-09-07-v1" required> |
| I have read <a href="https://carloku.com/pricing/">the pricing page</a> and agree to be charged yearly at the price shown at checkout, plus usage beyond the plan's inclusions billed monthly.</label></p> |
| <button type="submit"><span data-copy="billing.pay.button">Continue to payment</span></button> |
| <p class="small"><span data-copy="billing.pay.note">You pay by card at Stripe. Nothing is charged until you confirm there.</span></p> |
| + </div> |
| </form> |
| |
| |
| |
| |
| |
| +</div> |
| |
| </main></section> |
| <section class="preview-state"><p class="preview-label">Preview state: After a failed checkout attempt (error=unavailable)</p><main> |
| @@ -561,12 +628,14 @@ |
| |
| |
| |
| +<div class="billing-layout"> |
| <div class="pagehead"> |
| <p class="eyebrow">Account · ops</p> |
| <h1>Billing</h1> |
| <p class="lede"><span data-copy="billing.lede">Your plan, what it includes, and how to change it.</span></p> |
| </div> |
| |
| +<section class="billing-current"> |
| <h2><span data-copy="billing.current.heading">Your plan</span></h2> |
| |
| <p><span data-copy="billing.current.free">Free. One member, 3 apps, 100 awake hours a month, 250 MB of storage and 1 GB of transfer. Apps sleep after 2 minutes idle.</span></p> |
| @@ -575,17 +644,18 @@ |
| |
| |
| |
| +</section> |
| |
| |
| -<h2><span data-copy="billing.choose.heading">Choose a plan</span></h2> |
| +<h2 id="billing-choose-heading"><span data-copy="billing.choose.heading">Choose a plan</span></h2> |
| <p class="small"><span data-copy="billing.choose.lede">Prices are per year, before VAT, and depend on your billing country. The exact price is shown before you pay.</span></p> |
| |
| -<form class="signin" method="get" action="/a/bab/billing"> |
| +<form class="signin billing-quote" method="get" action="/a/bab/billing"> |
| <label><span data-copy="billing.country.label">Billing country</span> |
| <select name="country"> |
| <option value="" data-copy="billing.country.placeholder">Choose a country</option> |
| <option value="IE">Ireland</option> |
| - |
| + |
| </select> |
| </label> |
| <button class="linkish" type="submit"><span data-copy="billing.quote.button">Show prices for this country</span></button> |
| @@ -593,58 +663,87 @@ |
| |
| |
| |
| -<form method="post" action="/a/bab/billing/checkout"> |
| - <input type="hidden" name="csrf" value="kNaVjkqrWoKQCUW0HrmSh6u20nFOLYYgAlZvEDeCt_o"> |
| - <div class="tablewrap"> |
| +<form class="billing-checkout" method="post" action="/a/bab/billing/checkout"> |
| + <input type="hidden" name="csrf" value="QyDPBgnssyCMLbG0IoQxSv_nTUejKYIiQZS9X3LSn1Q"> |
| + <fieldset class="billing-plan-options" aria-labelledby="billing-choose-heading"> |
| + |
| + <label class="billing-plan-option"> |
| + <input type="radio" name="plan" value="personal" required> |
| + <span class="billing-plan-option-body"><strong><span data-copy="billing.plan.personal.name">Personal</span></strong> |
| + <span class="billing-option-price">€24</span> |
| + <span class="small"><span data-copy="billing.price.peryear">a year</span></span> |
| + </span> |
| + </label> |
| + |
| + <label class="billing-plan-option"> |
| + <input type="radio" name="plan" value="community" required> |
| + <span class="billing-plan-option-body"><strong><span data-copy="billing.plan.community.name">Community</span></strong> |
| + <span class="billing-option-price">€5</span> |
| + <span class="small"><span data-copy="billing.price.permember">per member a year</span></span> |
| + </span> |
| + </label> |
| + |
| + <label class="billing-plan-option"> |
| + <input type="radio" name="plan" value="business" required> |
| + <span class="billing-plan-option-body"><strong><span data-copy="billing.plan.business.name">Business</span></strong> |
| + <span class="billing-option-price">€50</span> |
| + <span class="small"><span data-copy="billing.price.permember">per member a year</span></span> |
| + </span> |
| + </label> |
| + |
| + </fieldset> |
| + <div class="tablewrap billing-inclusions"> |
| <table> |
| - |
| + |
| <tr> |
| - <td><label><input type="radio" name="plan" value="personal" required> |
| - <span data-copy="billing.plan.personal.name">Personal</span></label></td> |
| + <th scope="row"><span data-copy="billing.plan.personal.name">Personal</span></th> |
| <td><strong>€24</strong> <span data-copy="billing.price.peryear">a year</span></td> |
| <td class="small"><span data-copy="billing.plan.personal.blurb">One member. Each month: 85 awake hours, 2 GB storage, 2 GB transfer.</span></td> |
| </tr> |
| - |
| + |
| <tr> |
| - <td><label><input type="radio" name="plan" value="community" required> |
| - <span data-copy="billing.plan.community.name">Community</span></label></td> |
| + <th scope="row"><span data-copy="billing.plan.community.name">Community</span></th> |
| <td><strong>€5</strong> <span data-copy="billing.price.permember">per member a year</span> |
| <br><span class="small">€50 <span data-copy="billing.price.peryear">a year</span></span></td> |
| <td class="small"><span data-copy="billing.plan.community.blurb">Per member, minimum 10. Each member adds, per month: 17 awake hours, 0.5 GB storage, 0.4 GB transfer.</span></td> |
| </tr> |
| - |
| + |
| <tr> |
| - <td><label><input type="radio" name="plan" value="business" required> |
| - <span data-copy="billing.plan.business.name">Business</span></label></td> |
| + <th scope="row"><span data-copy="billing.plan.business.name">Business</span></th> |
| <td><strong>€50</strong> <span data-copy="billing.price.permember">per member a year</span> |
| <br><span class="small">€500 <span data-copy="billing.price.peryear">a year</span></span></td> |
| <td class="small"><span data-copy="billing.plan.business.blurb">Per member, minimum 10. Each member adds, per month: 170 awake hours, 5 GB storage, 3 GB transfer, 30,000 replication writes. Priority support.</span></td> |
| </tr> |
| - |
| + |
| </table> |
| </div> |
| <p class="small"><span data-copy="billing.plan.community.name">Community</span> and <span data-copy="billing.plan.business.name">Business</span> are priced per member. You have 1 members; the minimum is 10.</p> |
| + <div class="billing-address"> |
| <p><label><span data-copy="billing.country.label">Billing country</span> |
| <select name="country" required> |
| <option value="" data-copy="billing.country.placeholder">Choose a country</option> |
| <option value="IE">Ireland</option> |
| - |
| + |
| </select> |
| </label></p> |
| <p><label><span data-copy="billing.postal.label">Postal code</span> |
| <input type="text" name="postal" autocomplete="postal-code"> |
| </label></p> |
| + </div> |
| <p class="small"><span data-copy="billing.postal.help">Needed in the United States, Canada and India, where tax depends on it. Leave it empty elsewhere. We do not keep it.</span></p> |
| - <p><label><input type="checkbox" name="consent" value="2026-09-07-v1" required> |
| + <div class="billing-payment"> |
| + <p><label class="billing-consent"><input type="checkbox" name="consent" value="2026-09-07-v1" required> |
| I have read <a href="https://carloku.com/pricing/">the pricing page</a> and agree to be charged yearly at the price shown at checkout, plus usage beyond the plan's inclusions billed monthly.</label></p> |
| <button type="submit"><span data-copy="billing.pay.button">Continue to payment</span></button> |
| <p class="small"><span data-copy="billing.pay.note">You pay by card at Stripe. Nothing is charged until you confirm there.</span></p> |
| + </div> |
| </form> |
| |
| |
| |
| |
| |
| +</div> |
| |
| </main></section> |
| <section class="preview-state"><p class="preview-label">Preview state: A second checkout while one is settling (error=pending)</p><main> |
| @@ -658,12 +757,14 @@ |
| |
| |
| |
| +<div class="billing-layout"> |
| <div class="pagehead"> |
| <p class="eyebrow">Account · ops</p> |
| <h1>Billing</h1> |
| <p class="lede"><span data-copy="billing.lede">Your plan, what it includes, and how to change it.</span></p> |
| </div> |
| |
| +<section class="billing-current"> |
| <h2><span data-copy="billing.current.heading">Your plan</span></h2> |
| |
| <p><span data-copy="billing.current.free">Free. One member, 3 apps, 100 awake hours a month, 250 MB of storage and 1 GB of transfer. Apps sleep after 2 minutes idle.</span></p> |
| @@ -672,17 +773,18 @@ |
| |
| |
| |
| +</section> |
| |
| |
| -<h2><span data-copy="billing.choose.heading">Choose a plan</span></h2> |
| +<h2 id="billing-choose-heading"><span data-copy="billing.choose.heading">Choose a plan</span></h2> |
| <p class="small"><span data-copy="billing.choose.lede">Prices are per year, before VAT, and depend on your billing country. The exact price is shown before you pay.</span></p> |
| |
| -<form class="signin" method="get" action="/a/bab/billing"> |
| +<form class="signin billing-quote" method="get" action="/a/bab/billing"> |
| <label><span data-copy="billing.country.label">Billing country</span> |
| <select name="country"> |
| <option value="" data-copy="billing.country.placeholder">Choose a country</option> |
| <option value="IE">Ireland</option> |
| - |
| + |
| </select> |
| </label> |
| <button class="linkish" type="submit"><span data-copy="billing.quote.button">Show prices for this country</span></button> |
| @@ -690,58 +792,87 @@ |
| |
| |
| |
| -<form method="post" action="/a/bab/billing/checkout"> |
| - <input type="hidden" name="csrf" value="kNaVjkqrWoKQCUW0HrmSh6u20nFOLYYgAlZvEDeCt_o"> |
| - <div class="tablewrap"> |
| +<form class="billing-checkout" method="post" action="/a/bab/billing/checkout"> |
| + <input type="hidden" name="csrf" value="QyDPBgnssyCMLbG0IoQxSv_nTUejKYIiQZS9X3LSn1Q"> |
| + <fieldset class="billing-plan-options" aria-labelledby="billing-choose-heading"> |
| + |
| + <label class="billing-plan-option"> |
| + <input type="radio" name="plan" value="personal" required> |
| + <span class="billing-plan-option-body"><strong><span data-copy="billing.plan.personal.name">Personal</span></strong> |
| + <span class="billing-option-price">€24</span> |
| + <span class="small"><span data-copy="billing.price.peryear">a year</span></span> |
| + </span> |
| + </label> |
| + |
| + <label class="billing-plan-option"> |
| + <input type="radio" name="plan" value="community" required> |
| + <span class="billing-plan-option-body"><strong><span data-copy="billing.plan.community.name">Community</span></strong> |
| + <span class="billing-option-price">€5</span> |
| + <span class="small"><span data-copy="billing.price.permember">per member a year</span></span> |
| + </span> |
| + </label> |
| + |
| + <label class="billing-plan-option"> |
| + <input type="radio" name="plan" value="business" required> |
| + <span class="billing-plan-option-body"><strong><span data-copy="billing.plan.business.name">Business</span></strong> |
| + <span class="billing-option-price">€50</span> |
| + <span class="small"><span data-copy="billing.price.permember">per member a year</span></span> |
| + </span> |
| + </label> |
| + |
| + </fieldset> |
| + <div class="tablewrap billing-inclusions"> |
| <table> |
| - |
| + |
| <tr> |
| - <td><label><input type="radio" name="plan" value="personal" required> |
| - <span data-copy="billing.plan.personal.name">Personal</span></label></td> |
| + <th scope="row"><span data-copy="billing.plan.personal.name">Personal</span></th> |
| <td><strong>€24</strong> <span data-copy="billing.price.peryear">a year</span></td> |
| <td class="small"><span data-copy="billing.plan.personal.blurb">One member. Each month: 85 awake hours, 2 GB storage, 2 GB transfer.</span></td> |
| </tr> |
| - |
| + |
| <tr> |
| - <td><label><input type="radio" name="plan" value="community" required> |
| - <span data-copy="billing.plan.community.name">Community</span></label></td> |
| + <th scope="row"><span data-copy="billing.plan.community.name">Community</span></th> |
| <td><strong>€5</strong> <span data-copy="billing.price.permember">per member a year</span> |
| <br><span class="small">€50 <span data-copy="billing.price.peryear">a year</span></span></td> |
| <td class="small"><span data-copy="billing.plan.community.blurb">Per member, minimum 10. Each member adds, per month: 17 awake hours, 0.5 GB storage, 0.4 GB transfer.</span></td> |
| </tr> |
| - |
| + |
| <tr> |
| - <td><label><input type="radio" name="plan" value="business" required> |
| - <span data-copy="billing.plan.business.name">Business</span></label></td> |
| + <th scope="row"><span data-copy="billing.plan.business.name">Business</span></th> |
| <td><strong>€50</strong> <span data-copy="billing.price.permember">per member a year</span> |
| <br><span class="small">€500 <span data-copy="billing.price.peryear">a year</span></span></td> |
| <td class="small"><span data-copy="billing.plan.business.blurb">Per member, minimum 10. Each member adds, per month: 170 awake hours, 5 GB storage, 3 GB transfer, 30,000 replication writes. Priority support.</span></td> |
| </tr> |
| - |
| + |
| </table> |
| </div> |
| <p class="small"><span data-copy="billing.plan.community.name">Community</span> and <span data-copy="billing.plan.business.name">Business</span> are priced per member. You have 1 members; the minimum is 10.</p> |
| + <div class="billing-address"> |
| <p><label><span data-copy="billing.country.label">Billing country</span> |
| <select name="country" required> |
| <option value="" data-copy="billing.country.placeholder">Choose a country</option> |
| <option value="IE">Ireland</option> |
| - |
| + |
| </select> |
| </label></p> |
| <p><label><span data-copy="billing.postal.label">Postal code</span> |
| <input type="text" name="postal" autocomplete="postal-code"> |
| </label></p> |
| + </div> |
| <p class="small"><span data-copy="billing.postal.help">Needed in the United States, Canada and India, where tax depends on it. Leave it empty elsewhere. We do not keep it.</span></p> |
| - <p><label><input type="checkbox" name="consent" value="2026-09-07-v1" required> |
| + <div class="billing-payment"> |
| + <p><label class="billing-consent"><input type="checkbox" name="consent" value="2026-09-07-v1" required> |
| I have read <a href="https://carloku.com/pricing/">the pricing page</a> and agree to be charged yearly at the price shown at checkout, plus usage beyond the plan's inclusions billed monthly.</label></p> |
| <button type="submit"><span data-copy="billing.pay.button">Continue to payment</span></button> |
| <p class="small"><span data-copy="billing.pay.note">You pay by card at Stripe. Nothing is charged until you confirm there.</span></p> |
| + </div> |
| </form> |
| |
| |
| |
| |
| |
| +</div> |
| |
| </main></section> |
| <section class="preview-state"><p class="preview-label">Preview state: The account changed under the form (error=conflict)</p><main> |
| @@ -755,12 +886,14 @@ |
| <p class="banner error"><span data-copy="billing.error.conflict">The account changed while you were on this page, for example a member was added. Check the plan and try again.</span></p> |
| |
| |
| +<div class="billing-layout"> |
| <div class="pagehead"> |
| <p class="eyebrow">Account · ops</p> |
| <h1>Billing</h1> |
| <p class="lede"><span data-copy="billing.lede">Your plan, what it includes, and how to change it.</span></p> |
| </div> |
| |
| +<section class="billing-current"> |
| <h2><span data-copy="billing.current.heading">Your plan</span></h2> |
| |
| <p><span data-copy="billing.current.free">Free. One member, 3 apps, 100 awake hours a month, 250 MB of storage and 1 GB of transfer. Apps sleep after 2 minutes idle.</span></p> |
| @@ -769,17 +902,18 @@ |
| |
| |
| |
| +</section> |
| |
| |
| -<h2><span data-copy="billing.choose.heading">Choose a plan</span></h2> |
| +<h2 id="billing-choose-heading"><span data-copy="billing.choose.heading">Choose a plan</span></h2> |
| <p class="small"><span data-copy="billing.choose.lede">Prices are per year, before VAT, and depend on your billing country. The exact price is shown before you pay.</span></p> |
| |
| -<form class="signin" method="get" action="/a/bab/billing"> |
| +<form class="signin billing-quote" method="get" action="/a/bab/billing"> |
| <label><span data-copy="billing.country.label">Billing country</span> |
| <select name="country"> |
| <option value="" data-copy="billing.country.placeholder">Choose a country</option> |
| <option value="IE">Ireland</option> |
| - |
| + |
| </select> |
| </label> |
| <button class="linkish" type="submit"><span data-copy="billing.quote.button">Show prices for this country</span></button> |
| @@ -787,58 +921,87 @@ |
| |
| |
| |
| -<form method="post" action="/a/bab/billing/checkout"> |
| - <input type="hidden" name="csrf" value="kNaVjkqrWoKQCUW0HrmSh6u20nFOLYYgAlZvEDeCt_o"> |
| - <div class="tablewrap"> |
| +<form class="billing-checkout" method="post" action="/a/bab/billing/checkout"> |
| + <input type="hidden" name="csrf" value="QyDPBgnssyCMLbG0IoQxSv_nTUejKYIiQZS9X3LSn1Q"> |
| + <fieldset class="billing-plan-options" aria-labelledby="billing-choose-heading"> |
| + |
| + <label class="billing-plan-option"> |
| + <input type="radio" name="plan" value="personal" required> |
| + <span class="billing-plan-option-body"><strong><span data-copy="billing.plan.personal.name">Personal</span></strong> |
| + <span class="billing-option-price">€24</span> |
| + <span class="small"><span data-copy="billing.price.peryear">a year</span></span> |
| + </span> |
| + </label> |
| + |
| + <label class="billing-plan-option"> |
| + <input type="radio" name="plan" value="community" required> |
| + <span class="billing-plan-option-body"><strong><span data-copy="billing.plan.community.name">Community</span></strong> |
| + <span class="billing-option-price">€5</span> |
| + <span class="small"><span data-copy="billing.price.permember">per member a year</span></span> |
| + </span> |
| + </label> |
| + |
| + <label class="billing-plan-option"> |
| + <input type="radio" name="plan" value="business" required> |
| + <span class="billing-plan-option-body"><strong><span data-copy="billing.plan.business.name">Business</span></strong> |
| + <span class="billing-option-price">€50</span> |
| + <span class="small"><span data-copy="billing.price.permember">per member a year</span></span> |
| + </span> |
| + </label> |
| + |
| + </fieldset> |
| + <div class="tablewrap billing-inclusions"> |
| <table> |
| - |
| + |
| <tr> |
| - <td><label><input type="radio" name="plan" value="personal" required> |
| - <span data-copy="billing.plan.personal.name">Personal</span></label></td> |
| + <th scope="row"><span data-copy="billing.plan.personal.name">Personal</span></th> |
| <td><strong>€24</strong> <span data-copy="billing.price.peryear">a year</span></td> |
| <td class="small"><span data-copy="billing.plan.personal.blurb">One member. Each month: 85 awake hours, 2 GB storage, 2 GB transfer.</span></td> |
| </tr> |
| - |
| + |
| <tr> |
| - <td><label><input type="radio" name="plan" value="community" required> |
| - <span data-copy="billing.plan.community.name">Community</span></label></td> |
| + <th scope="row"><span data-copy="billing.plan.community.name">Community</span></th> |
| <td><strong>€5</strong> <span data-copy="billing.price.permember">per member a year</span> |
| <br><span class="small">€50 <span data-copy="billing.price.peryear">a year</span></span></td> |
| <td class="small"><span data-copy="billing.plan.community.blurb">Per member, minimum 10. Each member adds, per month: 17 awake hours, 0.5 GB storage, 0.4 GB transfer.</span></td> |
| </tr> |
| - |
| + |
| <tr> |
| - <td><label><input type="radio" name="plan" value="business" required> |
| - <span data-copy="billing.plan.business.name">Business</span></label></td> |
| + <th scope="row"><span data-copy="billing.plan.business.name">Business</span></th> |
| <td><strong>€50</strong> <span data-copy="billing.price.permember">per member a year</span> |
| <br><span class="small">€500 <span data-copy="billing.price.peryear">a year</span></span></td> |
| <td class="small"><span data-copy="billing.plan.business.blurb">Per member, minimum 10. Each member adds, per month: 170 awake hours, 5 GB storage, 3 GB transfer, 30,000 replication writes. Priority support.</span></td> |
| </tr> |
| - |
| + |
| </table> |
| </div> |
| <p class="small"><span data-copy="billing.plan.community.name">Community</span> and <span data-copy="billing.plan.business.name">Business</span> are priced per member. You have 1 members; the minimum is 10.</p> |
| + <div class="billing-address"> |
| <p><label><span data-copy="billing.country.label">Billing country</span> |
| <select name="country" required> |
| <option value="" data-copy="billing.country.placeholder">Choose a country</option> |
| <option value="IE">Ireland</option> |
| - |
| + |
| </select> |
| </label></p> |
| <p><label><span data-copy="billing.postal.label">Postal code</span> |
| <input type="text" name="postal" autocomplete="postal-code"> |
| </label></p> |
| + </div> |
| <p class="small"><span data-copy="billing.postal.help">Needed in the United States, Canada and India, where tax depends on it. Leave it empty elsewhere. We do not keep it.</span></p> |
| - <p><label><input type="checkbox" name="consent" value="2026-09-07-v1" required> |
| + <div class="billing-payment"> |
| + <p><label class="billing-consent"><input type="checkbox" name="consent" value="2026-09-07-v1" required> |
| I have read <a href="https://carloku.com/pricing/">the pricing page</a> and agree to be charged yearly at the price shown at checkout, plus usage beyond the plan's inclusions billed monthly.</label></p> |
| <button type="submit"><span data-copy="billing.pay.button">Continue to payment</span></button> |
| <p class="small"><span data-copy="billing.pay.note">You pay by card at Stripe. Nothing is charged until you confirm there.</span></p> |
| + </div> |
| </form> |
| |
| |
| |
| |
| |
| +</div> |
| |
| </main></section> |
| <section class="preview-state"><p class="preview-label">Preview state: Back from Stripe, webhook not yet arrived (pending=1)</p><main> |
| @@ -852,12 +1015,14 @@ |
| |
| <p class="banner"><span data-copy="billing.current.pending">Thanks. Stripe is confirming your payment. Your plan turns on within a few minutes, and this page will show it.</span></p> |
| |
| +<div class="billing-layout"> |
| <div class="pagehead"> |
| <p class="eyebrow">Account · ops</p> |
| <h1>Billing</h1> |
| <p class="lede"><span data-copy="billing.lede">Your plan, what it includes, and how to change it.</span></p> |
| </div> |
| |
| +<section class="billing-current"> |
| <h2><span data-copy="billing.current.heading">Your plan</span></h2> |
| |
| <p><span data-copy="billing.current.free">Free. One member, 3 apps, 100 awake hours a month, 250 MB of storage and 1 GB of transfer. Apps sleep after 2 minutes idle.</span></p> |
| @@ -866,17 +1031,18 @@ |
| |
| |
| |
| +</section> |
| |
| |
| -<h2><span data-copy="billing.choose.heading">Choose a plan</span></h2> |
| +<h2 id="billing-choose-heading"><span data-copy="billing.choose.heading">Choose a plan</span></h2> |
| <p class="small"><span data-copy="billing.choose.lede">Prices are per year, before VAT, and depend on your billing country. The exact price is shown before you pay.</span></p> |
| |
| -<form class="signin" method="get" action="/a/bab/billing"> |
| +<form class="signin billing-quote" method="get" action="/a/bab/billing"> |
| <label><span data-copy="billing.country.label">Billing country</span> |
| <select name="country"> |
| <option value="" data-copy="billing.country.placeholder">Choose a country</option> |
| <option value="IE">Ireland</option> |
| - |
| + |
| </select> |
| </label> |
| <button class="linkish" type="submit"><span data-copy="billing.quote.button">Show prices for this country</span></button> |
| @@ -884,58 +1050,87 @@ |
| |
| |
| |
| -<form method="post" action="/a/bab/billing/checkout"> |
| - <input type="hidden" name="csrf" value="kNaVjkqrWoKQCUW0HrmSh6u20nFOLYYgAlZvEDeCt_o"> |
| - <div class="tablewrap"> |
| +<form class="billing-checkout" method="post" action="/a/bab/billing/checkout"> |
| + <input type="hidden" name="csrf" value="QyDPBgnssyCMLbG0IoQxSv_nTUejKYIiQZS9X3LSn1Q"> |
| + <fieldset class="billing-plan-options" aria-labelledby="billing-choose-heading"> |
| + |
| + <label class="billing-plan-option"> |
| + <input type="radio" name="plan" value="personal" required> |
| + <span class="billing-plan-option-body"><strong><span data-copy="billing.plan.personal.name">Personal</span></strong> |
| + <span class="billing-option-price">€24</span> |
| + <span class="small"><span data-copy="billing.price.peryear">a year</span></span> |
| + </span> |
| + </label> |
| + |
| + <label class="billing-plan-option"> |
| + <input type="radio" name="plan" value="community" required> |
| + <span class="billing-plan-option-body"><strong><span data-copy="billing.plan.community.name">Community</span></strong> |
| + <span class="billing-option-price">€5</span> |
| + <span class="small"><span data-copy="billing.price.permember">per member a year</span></span> |
| + </span> |
| + </label> |
| + |
| + <label class="billing-plan-option"> |
| + <input type="radio" name="plan" value="business" required> |
| + <span class="billing-plan-option-body"><strong><span data-copy="billing.plan.business.name">Business</span></strong> |
| + <span class="billing-option-price">€50</span> |
| + <span class="small"><span data-copy="billing.price.permember">per member a year</span></span> |
| + </span> |
| + </label> |
| + |
| + </fieldset> |
| + <div class="tablewrap billing-inclusions"> |
| <table> |
| - |
| + |
| <tr> |
| - <td><label><input type="radio" name="plan" value="personal" required> |
| - <span data-copy="billing.plan.personal.name">Personal</span></label></td> |
| + <th scope="row"><span data-copy="billing.plan.personal.name">Personal</span></th> |
| <td><strong>€24</strong> <span data-copy="billing.price.peryear">a year</span></td> |
| <td class="small"><span data-copy="billing.plan.personal.blurb">One member. Each month: 85 awake hours, 2 GB storage, 2 GB transfer.</span></td> |
| </tr> |
| - |
| + |
| <tr> |
| - <td><label><input type="radio" name="plan" value="community" required> |
| - <span data-copy="billing.plan.community.name">Community</span></label></td> |
| + <th scope="row"><span data-copy="billing.plan.community.name">Community</span></th> |
| <td><strong>€5</strong> <span data-copy="billing.price.permember">per member a year</span> |
| <br><span class="small">€50 <span data-copy="billing.price.peryear">a year</span></span></td> |
| <td class="small"><span data-copy="billing.plan.community.blurb">Per member, minimum 10. Each member adds, per month: 17 awake hours, 0.5 GB storage, 0.4 GB transfer.</span></td> |
| </tr> |
| - |
| + |
| <tr> |
| - <td><label><input type="radio" name="plan" value="business" required> |
| - <span data-copy="billing.plan.business.name">Business</span></label></td> |
| + <th scope="row"><span data-copy="billing.plan.business.name">Business</span></th> |
| <td><strong>€50</strong> <span data-copy="billing.price.permember">per member a year</span> |
| <br><span class="small">€500 <span data-copy="billing.price.peryear">a year</span></span></td> |
| <td class="small"><span data-copy="billing.plan.business.blurb">Per member, minimum 10. Each member adds, per month: 170 awake hours, 5 GB storage, 3 GB transfer, 30,000 replication writes. Priority support.</span></td> |
| </tr> |
| - |
| + |
| </table> |
| </div> |
| <p class="small"><span data-copy="billing.plan.community.name">Community</span> and <span data-copy="billing.plan.business.name">Business</span> are priced per member. You have 1 members; the minimum is 10.</p> |
| + <div class="billing-address"> |
| <p><label><span data-copy="billing.country.label">Billing country</span> |
| <select name="country" required> |
| <option value="" data-copy="billing.country.placeholder">Choose a country</option> |
| <option value="IE">Ireland</option> |
| - |
| + |
| </select> |
| </label></p> |
| <p><label><span data-copy="billing.postal.label">Postal code</span> |
| <input type="text" name="postal" autocomplete="postal-code"> |
| </label></p> |
| + </div> |
| <p class="small"><span data-copy="billing.postal.help">Needed in the United States, Canada and India, where tax depends on it. Leave it empty elsewhere. We do not keep it.</span></p> |
| - <p><label><input type="checkbox" name="consent" value="2026-09-07-v1" required> |
| + <div class="billing-payment"> |
| + <p><label class="billing-consent"><input type="checkbox" name="consent" value="2026-09-07-v1" required> |
| I have read <a href="https://carloku.com/pricing/">the pricing page</a> and agree to be charged yearly at the price shown at checkout, plus usage beyond the plan's inclusions billed monthly.</label></p> |
| <button type="submit"><span data-copy="billing.pay.button">Continue to payment</span></button> |
| <p class="small"><span data-copy="billing.pay.note">You pay by card at Stripe. Nothing is charged until you confirm there.</span></p> |
| + </div> |
| </form> |
| |
| |
| |
| |
| |
| +</div> |
| |
| </main></section> |
| <section class="preview-state"><p class="preview-label">Preview state: Active Personal subscription, portal available</p><main> |
| @@ -949,20 +1144,23 @@ |
| |
| |
| |
| +<div class="billing-layout"> |
| <div class="pagehead"> |
| <p class="eyebrow">Account · ops</p> |
| <h1>Billing</h1> |
| <p class="lede"><span data-copy="billing.lede">Your plan, what it includes, and how to change it.</span></p> |
| </div> |
| |
| +<section class="billing-current"> |
| <h2><span data-copy="billing.current.heading">Your plan</span></h2> |
| |
| -<p><span data-copy="billing.plan.personal.name">Personal</span>, 1 members, renews on 2027-09-30.</p> |
| +<p><span data-copy="billing.plan.personal.name">Personal</span>, 1 members, renews on 2027-10-01.</p> |
| |
| |
| |
| |
| |
| +</section> |
| |
| |
| |
| @@ -970,12 +1168,13 @@ |
| <h2><span data-copy="billing.manage.heading">Cards, invoices and cancelling</span></h2> |
| <p class="small"><span data-copy="billing.manage.body">Change your card, download invoices or cancel at Stripe. Cancelling keeps the plan until the end of the year you paid for.</span></p> |
| <form method="post" action="/a/bab/billing/portal"> |
| - <input type="hidden" name="csrf" value="kNaVjkqrWoKQCUW0HrmSh6u20nFOLYYgAlZvEDeCt_o"> |
| + <input type="hidden" name="csrf" value="QyDPBgnssyCMLbG0IoQxSv_nTUejKYIiQZS9X3LSn1Q"> |
| <button type="submit"><span data-copy="billing.manage.button">Open billing at Stripe</span></button> |
| </form> |
| |
| |
| |
| +</div> |
| |
| </main></section> |
| <section class="preview-state"><p class="preview-label">Preview state: Payment failed on renewal (past_due)</p><main> |
| @@ -989,20 +1188,23 @@ |
| |
| |
| |
| +<div class="billing-layout"> |
| <div class="pagehead"> |
| <p class="eyebrow">Account · ops</p> |
| <h1>Billing</h1> |
| <p class="lede"><span data-copy="billing.lede">Your plan, what it includes, and how to change it.</span></p> |
| </div> |
| |
| +<section class="billing-current"> |
| <h2><span data-copy="billing.current.heading">Your plan</span></h2> |
| |
| -<p><span data-copy="billing.plan.personal.name">Personal</span>, 1 members, renews on 2027-09-30.</p> |
| +<p><span data-copy="billing.plan.personal.name">Personal</span>, 1 members, renews on 2027-10-01.</p> |
| |
| |
| <p class="banner error"><span data-copy="billing.current.pastdue">The last payment did not go through. Update your card below to keep the plan.</span></p> |
| |
| |
| +</section> |
| |
| |
| |
| @@ -1010,12 +1212,13 @@ |
| <h2><span data-copy="billing.manage.heading">Cards, invoices and cancelling</span></h2> |
| <p class="small"><span data-copy="billing.manage.body">Change your card, download invoices or cancel at Stripe. Cancelling keeps the plan until the end of the year you paid for.</span></p> |
| <form method="post" action="/a/bab/billing/portal"> |
| - <input type="hidden" name="csrf" value="kNaVjkqrWoKQCUW0HrmSh6u20nFOLYYgAlZvEDeCt_o"> |
| + <input type="hidden" name="csrf" value="QyDPBgnssyCMLbG0IoQxSv_nTUejKYIiQZS9X3LSn1Q"> |
| <button type="submit"><span data-copy="billing.manage.button">Open billing at Stripe</span></button> |
| </form> |
| |
| |
| |
| +</div> |
| |
| </main></section> |
| <section class="preview-state"><p class="preview-label">Preview state: An operator review hold is open</p><main> |
| @@ -1029,20 +1232,23 @@ |
| |
| |
| |
| +<div class="billing-layout"> |
| <div class="pagehead"> |
| <p class="eyebrow">Account · ops</p> |
| <h1>Billing</h1> |
| <p class="lede"><span data-copy="billing.lede">Your plan, what it includes, and how to change it.</span></p> |
| </div> |
| |
| +<section class="billing-current"> |
| <h2><span data-copy="billing.current.heading">Your plan</span></h2> |
| |
| -<p><span data-copy="billing.plan.personal.name">Personal</span>, 1 members, renews on 2027-09-30.</p> |
| +<p><span data-copy="billing.plan.personal.name">Personal</span>, 1 members, renews on 2027-10-01.</p> |
| |
| |
| <p class="banner error"><span data-copy="billing.current.pastdue">The last payment did not go through. Update your card below to keep the plan.</span></p> |
| <p class="banner"><span data-copy="billing.current.review">Something about this account's billing needs a person to look at it. Nothing is charged while that happens. We will be in touch.</span></p> |
| |
| +</section> |
| |
| |
| |
| @@ -1050,12 +1256,13 @@ |
| <h2><span data-copy="billing.manage.heading">Cards, invoices and cancelling</span></h2> |
| <p class="small"><span data-copy="billing.manage.body">Change your card, download invoices or cancel at Stripe. Cancelling keeps the plan until the end of the year you paid for.</span></p> |
| <form method="post" action="/a/bab/billing/portal"> |
| - <input type="hidden" name="csrf" value="kNaVjkqrWoKQCUW0HrmSh6u20nFOLYYgAlZvEDeCt_o"> |
| + <input type="hidden" name="csrf" value="QyDPBgnssyCMLbG0IoQxSv_nTUejKYIiQZS9X3LSn1Q"> |
| <button type="submit"><span data-copy="billing.manage.button">Open billing at Stripe</span></button> |
| </form> |
| |
| |
| |
| +</div> |
| |
| </main></section> |
| <section class="preview-state"><p class="preview-label">Preview state: A member who is not an owner</p><main> |
| @@ -1069,24 +1276,28 @@ |
| |
| |
| |
| +<div class="billing-layout"> |
| <div class="pagehead"> |
| <p class="eyebrow">Account · ops</p> |
| <h1>Billing</h1> |
| <p class="lede"><span data-copy="billing.lede">Your plan, what it includes, and how to change it.</span></p> |
| </div> |
| |
| +<section class="billing-current"> |
| <h2><span data-copy="billing.current.heading">Your plan</span></h2> |
| |
| -<p><span data-copy="billing.plan.personal.name">Personal</span>, 1 members, renews on 2027-09-30.</p> |
| +<p><span data-copy="billing.plan.personal.name">Personal</span>, 1 members, renews on 2027-10-01.</p> |
| |
| |
| <p class="banner error"><span data-copy="billing.current.pastdue">The last payment did not go through. Update your card below to keep the plan.</span></p> |
| <p class="banner"><span data-copy="billing.current.review">Something about this account's billing needs a person to look at it. Nothing is charged while that happens. We will be in touch.</span></p> |
| |
| +</section> |
| |
| <p class="small"><span data-copy="billing.member.readonly">Only an account owner can change the plan.</span></p> |
| |
| |
| +</div> |
| |
| </main></section> |
| <section class="preview-state"><p class="preview-label">Preview state: Billing switched off on this deployment (production today)</p><main> |
| @@ -1100,12 +1311,14 @@ |
| |
| |
| |
| +<div class="billing-layout"> |
| <div class="pagehead"> |
| <p class="eyebrow">Account · ops</p> |
| <h1>Billing</h1> |
| <p class="lede"><span data-copy="billing.lede">Your plan, what it includes, and how to change it.</span></p> |
| </div> |
| |
| +<section class="billing-current"> |
| <h2><span data-copy="billing.current.heading">Your plan</span></h2> |
| |
| <p><span data-copy="billing.current.free">Free. One member, 3 apps, 100 awake hours a month, 250 MB of storage and 1 GB of transfer. Apps sleep after 2 minutes idle.</span></p> |
| @@ -1114,10 +1327,12 @@ |
| |
| |
| |
| +</section> |
| |
| <p><span data-copy="billing.closed">Paid plans are not open on this console yet. Every account is on the Free plan.</span></p> |
| |
| |
| +</div> |
| |
| </main></section></body> |
| </html> |