Demo

See it before you buy it

Two ways round. Below are the walkthroughs: every screen a buyer meets, in order, with what each one proves. And there is a live OpenCart store with Import/export installed, which you are welcome to break.

Open the live store Read the walkthroughs

The live store

demo.kyvero.dev is a real OpenCart store running the admin unlocked, with Import/export installed. Sign in, import a file, apply it, roll it back. There is nothing in it to protect: it holds OpenCart's own demo catalogue and no real data of anyone's.

It wipes itself back to that catalogue after a spell of nobody using it, and again before the next visitor arrives, so anything you do there is temporary and anything you find there was put there by a stranger. Please do not type a password you use elsewhere into it, and do not leave anything in it you would want back.

Delivery Date is on it too. Back In Stock, Returns Portal, Review Requests, Pre-Order and Product Configurator are not on it yet, so their walkthroughs below are the only place to see them working. Those are photographs of stores built for the occasion by a command in our repository, not of this one.

If it does not answer, it is being rebuilt or its host has gone away. It runs on a free tier and we would rather spend the money on the extensions. The walkthroughs below are the same screens, and the documentation describes every extension in full; neither depends on that store being up.

Import/export, screen by screen

A supplier has sent a price and stock file. This is every screen between that file and the catalogue, in order.

What Import/export is says what it does and what it does not; this is what using it looks like.

Map the columns

Every column of the file, the first few values it holds, and the field it is bound to. The fields offered are the columns this store has, so a column another extension added is mappable with no configuration.

The Map the columns screen. Each column of the uploaded file is listed with the first few values it holds beside the store field it is bound to.

The plan

Seven counts for the whole file before a single write. This is the screen that tells you a file you thought would change three products would in fact create four hundred.

The plan summary card: seven counts across one row, among them rows read, new, changed, unchanged and rejected.

What would change

The before and after for each record, with the current value struck through. The row it refused to read is in red, because a price of “on request” is not a number. Nothing here has been written to the catalogue.

A plan's list of changes. Three products are being updated, each showing the current value struck through and the value that would replace it; one product is being created, with every field it would be given; and one row is rejected in red because its price is not a number.

A plan it will not apply

A price that moved 88% and a quantity that collapsed to zero look like an upstream mistake, so the plan is held: Acknowledge stands where Apply would. You can still apply it, once you have said that you have seen it.

A plan held back: an alert naming two anomalies, the two changes that raised them, and an Acknowledge button standing where Apply would be.

Undo this import

An applied import can be rolled back, and the rollback is itself previewed: the values it would put back, per record, before you confirm. What rollback does not restore is written down in the documentation.

The Undo this import screen, listing per record the values a rollback would put back, before anything is undone.

Profiles and history

The mapping saved as a profile, so next month’s file from the same supplier is an upload and a glance. Every job that ran is still listed, with what it did.

The Profiles and history screen: a saved export and a saved import, each with its schedule controls and when it last ran.

Delivery Date, screen by screen

A store that delivers with its own van. This is the week being set up, a customer booking against it, and the day being read back off the sheet, in that order.

What Delivery Date is says what it does and what it does not; this is what using it looks like.

Your delivery week

Three windows, which weekday each one runs on, and a cap typed into the box under every tick, plus a cap on the whole weekday along the foot. This is the screen behind “three caps, checked together”, and the closed date at the bottom is the one with a note on it.

The delivery week card. At the top, the slot library: three windows named 09:00-12:00, 12:00-15:00 and 15:00-18:00, each with the number of orders it takes: 4, 3 and 2. Below it the grid, seven weekday columns against the three windows, a tick where the window runs and a small cap box under each tick; one weekday’s boxes carry that day’s own smaller numbers, and Saturday runs the morning window only. At the foot, a row of whole-day limits, and under the grid a closed date with the note “Vans in for service”.

What it would offer, before you save it

The next fortnight worked out beside the form by the same code the checkout runs, with the numbers you have typed and not yet saved. Every day it will not offer says why, and the clock field at the top lets you pretend a customer is ordering after the cut-off to check it.

The preview panel. A clock field holding a date and time, then a line of arithmetic: ordered before the 15:00 cut-off, so the batch day is today, one day of preparation added, and the earliest day that comes out of it. Under it the next fortnight, day by day: an offered day lists its windows with the places left against each, and a day that is not offered carries its reason instead: “No delivery on a Sunday”, “Closed — Vans in for service”.

Pickup on Saturdays, the courier not

A second calendar bound to one shipping method. It is inheriting the store’s days here, which is why the whole grid is greyed out and unclickable: inheritance is per calendar, never per field. Each timing field prints the number in force beside it.

A per-method calendar. Its name, the shipping methods it speaks for with Pickup ticked and the flat rate left to the store calendar, and “Use the store calendar’s days and slots” switched on, under which the whole week grid is rendered greyed out and uneditable, showing what the calendar is taking from the store. Below it the timing fields, each with an “Effective now” line naming the number actually in force: the store’s preparation, this calendar’s own earlier cut-off, its nearer horizon. On the right, the preview for this calendar.

What the customer gets

The picker sits inside core’s own shipping-method block, with no template edited and no theme file touched. Six days at a time, the nearest given as names instead of dates, and a full window struck through rather than missing.

The checkout’s Shipping Method block. Under the chosen flat rate, a “Delivery date” heading, the day currently chosen said in words, and the reason the earliest day is what it is. Then the days as radio buttons (the nearest ones named “tomorrow” and by weekday, the rest by date), with the chosen day’s windows indented beneath it: the first struck through and greyed as “no longer available”, the second selected and marked “2 left”, the third marked “last one”. At the foot, “Show more dates”.

When the day cannot be kept

Somebody else took the last place while this customer was in checkout. The order moves to the next day that can be kept (never the nearest), and this is the customer being told so before they confirm, in the words they read.

The foot of the checkout’s order summary, the Confirm Order button, and under it a notice telling the customer their delivery changed: the day and window that could not be kept, the ones they have instead, and why: the day they chose filled up.

On the order, where you already look

The delivery day sitting between Shipping Method and Payment Method on core’s own order page, linking into the planner, with the “was …” line where a booking moved, so the record of the change survives on the order itself.

Core’s own order page, the row carrying Shipping Method, Delivery Day and Payment Method side by side. Delivery Day names the day as a link into the planner with the window beside it, and under it a muted “was …” line naming the day this booking was moved from.

Planning the day

The week’s occupancy above the day’s orders, grouped by window. A slot being held for somebody still in checkout is a grey “+1 holding” and is never folded into the count, so a merchant reading 3/4 can trust the 3. It is read-only on purpose: moving a firm booking is a phone call.

Sales, Delivery Days. Across the top, the week as a grid: three delivery windows down the side, the seven days across, and in each cell the firmed orders against that day’s cap. The chosen day’s column is highlighted: two of its windows read as full, the third carries a grey “+1 holding” under its count, and a closed day elsewhere in the week reads as a dash. Below the grid, that day’s sheet, grouped by window: five orders across the three windows, each giving its number, the customer, the town and postcode, the phone number, the item count and the order status.

The sheet that leaves the building

The same day printed for whoever is driving: the full street address the screen shortens to a town, a tick column the screen does not have, and windows with nothing in them left out. The day also exports as CSV, one row per order.

The printed delivery sheet. A heading naming the day and the day’s total, then a section per window: 09:00-12:00 with two orders and 12:00-15:00 with one. Each row is a tick box, the order number, the customer, the full street address over four lines, the phone number, the item count and the order status.

Back In Stock, screen by screen

A size is gone and somebody wants it. This is the field they meet, the list it fills, the number that list becomes, and the one thing that has to be woken for any of it to send.

What Back In Stock is says what it does and what it does not; this is what using it looks like.

What the shopper meets

Spliced in below Add to Cart in the theme already running, with no template edited. It names the variant rather than the product, because that is what the alert will be about, and the notice under the field is the whole promise in the words the shopper reads before typing anything.

The capture form as a shopper meets it, below Add to Cart: the heading “Email me when this is back”, the line “Product 8 — Size: Small” naming the exact variant, one email field with a “Notify me” button, and underneath the consent notice: the store will email once and about nothing else, a confirmation message comes first and nothing is sent until it is answered, the request is deleted after 7 days if nobody confirms and after 12 months if the product does not come back, every email carries a one-click unsubscribe, and the record that they asked is kept for three years.

The waiting list

Addresses masked until you ask to see one, and a pending confirmation counted separately from the people waiting, because somebody who has not clicked the link is not on the list yet. The search beside it answers “what do you hold about me” for one address across every store, and honours a withdrawal or an erasure from the same screen.

Catalog → Back In Stock. Across the top: 2 waiting now, 1 pending confirmation marked “not counted above”, none in flight, none parked, none alerted, and when the last sweep ran. Below, a table of three subscriptions with their addresses masked and a “Show” link beside each, what they are waiting for, how long, the store and the language, and a “Stop this alert” button on every row. Beside it, a search box reading “What we hold about an address”.

What to reorder

The waiting list read as a number: per variant, how many are waiting, how long the longest has been, and why an alert cannot go out right now. There is no all-time figure and the footnote says why: requests are deleted on the schedule the shopper was promised, so a total nobody can reconstruct is not printed as though they could.

The Back In Stock Demand report. A strip reading 2 waiting now, 2 variants watched, average and longest wait, and how many were alerted in the last 60 days. Below it a table with one row per product: a thumbnail, the name, how many variants of it are watched, waiting now, longest wait, alerted, and an alert state reading “0 of 1 sendable”, with buttons to edit the product and to see who is waiting. A filter card sits beside it, and a footnote explains why there is no all-time figure.

Per variant, on the product

A row for the product and one for each of its option values, with a switch that inherits from the module until you say otherwise. The state column is the useful half: a variant that cannot be alerted says which of the conditions it is failing, rather than sitting silently at zero.

The Back In Stock tab on the product form. One row per counter (the product itself, then Size › Large, Size › Medium and Size › Small), each with its stock figure, a capture-form switch reading “Inherit (follow the module switch)”, how many people are waiting, the longest wait, and an alert state. Three read “Sendable now” in green; Size › Small, at zero stock with one person waiting, reads “This variant, or a required option beside it, is unavailable”.

The part that has to be woken

No alert is ever sent by a page view, which makes this the screen that decides whether the extension does anything at all. Three ways to call the sweep (OpenCart’s own scheduler, a URL anything can fetch, or a command), each printed with this store’s own paths already in it, and any one of them is enough.

The “Sending the alerts” card on the settings screen. Above the three doors, the per-pass cap and the missed-cycles warning. Then the three ways to wake the sweep, each with the exact line to paste: a crontab line running the store’s own cron.php, a curl line fetching the sweep web address with its secret, and a command line running the extension’s own script. Below them the sweep web address itself, with Copy and Rotate buttons.

Returns Portal, screen by screen

Something is going back, and the person sending it has no account. This is every screen between “I want to return this” and a decision recorded line by line, in order.

What Returns Portal is says what it does and what it does not; this is what using it looks like.

Proving the order is theirs

Two fields and no account. OpenCart’s own form accepts an order number without checking that the order exists or that it belongs to the person typing it; this checks both, and every refusal is worded the same way whatever went wrong, so the screen cannot be used to find out whose address is on an order. The two ways out under the rule are there because a customer who has lost the email has not lost the right to return the thing.

The storefront lookup, headed “Return an item”: give the order number and the email address the order confirmation was sent to, and we will show you what can be sent back. Two required fields, each with a hint under it (the order number is on the confirmation email and the invoice in the parcel, and the address is the one the confirmation went to, which may not be the one you use now), and a “Find my order” button. Under a rule: “Cannot find the order number, or not sure which address it went to?”, with links to sign in and pick from your orders, or to contact the store.

Picking the lines

Every line of the order, with the one that may not come back carrying the reason rather than being hidden. The card adds up as the customer ticks and shows its working (subtotal, share of any order discount, tax), because a number with its arithmetic beside it is a number a merchant can check against their own coupon. “Exchange requested” is worded that way on the button itself: it records what was asked for and creates no order.

The line picker on a three-line order, under a banner reading “Returnable until 12/09/2026”. Two lines are ticked, each with a quantity, a reason chosen from a list, an Opened or Unopened choice and an optional photo field; the first has two files attached. The third line, Marchmont Engraved Tag, has a dash in place of a tick and “This item cannot be returned.” in red under its name. A card on the right reads Subtotal 2 item(s) $80.00, Share of order discount −$8.00, Tax $0.00, Estimated refund $72.00, with the notes that ticking updates the estimate and that the final amount is confirmed by the store. Below, a choice between Refund and Exchange requested, and a “Send this request” button.

The slip, printed before anybody has agreed

The customer gets it immediately, because making them wait for it is how a parcel arrives with nothing in it saying whose return it is. The overprint is the whole reason it can be immediate: it says outright that nobody has accepted the return yet, so it cannot be read as permission to post. Approve the request and it prints without the box.

The printable returns slip, headed RMA-1, with “NOT YET APPROVED — DO NOT POST” in red inside a red box across the width of it. Under it the order number and date, what the customer asked for, and a table of the two lines with their models, quantities, reasons and estimated refunds, totalling $72.00. Then “Send it to” and the store’s returns address, an instruction to put the slip in the parcel and keep the proof of postage, and a note that this is an estimate.

The queue

Three tabs with their counts, so what is waiting on you is a number rather than a scroll. “Approved, awaiting parcel” is the one worth having: its count is what tells you something was agreed a fortnight ago and never arrived. Both customers here are badged Guest, which is the case OpenCart’s own returns handle worst: it files a guest’s return where that guest can never see it again.

Sales → Return Requests on the “Needs a decision” tab, which carries a count of 2, beside “Approved, awaiting parcel” at 1 and “Settled” at 1. Under a heading reading “2 need a decision · 2 shown”, an Export CSV button on the right and a table of two requests: RMA-1 and RMA-2, their order numbers, the customers (both badged Guest), how many lines, what was asked for, the estimate, how many photos, how long they have been waiting, and a “Needs a decision” state badge on each.

Half of it, and the reason for the other half

Refuse one line and the card shows two figures rather than one: what the customer was shown, and what you are accepting now. The save button counts the refusals back at you before you press it. The box above is required on a refusal, because “why” is what the customer is about to be emailed, line by line, in your words.

A request mid-decision, nothing saved yet. On the left a State card: a “Needs a decision” badge, a box headed “Why, in words the customer will read” holding a typed reason, and a save button reading “Save — 1 of 2 refused” beside a “The customer withdrew it” button. On the right an Estimated refund card: Subtotal $100.00, Tax $0.00, then “Estimate the customer was shown $100.00” and under it, in bold, “Accepting now — 1 of 2 lines $40.00”.

Review Requests, screen by screen

An order has arrived and nobody has said anything about it. This is the message that goes out, the page it opens, what ends up on the product page, and the two screens the merchant reads it back from.

What Review Requests is says what it does and what it does not; this is what using it looks like.

What lands in the inbox

One message for the whole order, not one per product, with the first few named and the rest counted. The stars are live (clicking one pre-fills that rating on the page), and the footer carries the reason, the way out and the postal address, because a marketing email that carries none of those is the kind that gets a store blocked.

The request email. The store logo, then “Hello Idris,” and a line saying they ordered from Northfell Outfitters on 29/08/2026 and that other shoppers would find it useful to know what they thought. Three bordered cards follow (Ashgrove Wool Throw, Calder Ceramic Mug, Marchmont Linen Apron), each with a row of five stars labelled Poor at one end and Great at the other. Under them a grey line notes that Ferrybridge Oak Board and Southgate Enamel Jug from the same order are on it too, then a black “Write a review” button, then a line saying a person at the store reads the review before it goes on the site. Below a rule: why they are getting this, a “Don’t send me review requests” link, and the store’s name and postal address over five lines.

The page the link opens

No login, no password and no captcha: the link is the proof of purchase, which is what lets a guest order be asked like any other. One card per product, each submitting on its own, so a customer who only wants to talk about one of five can. The card already sent shows its own state back rather than disappearing.

The Write a review page opened from the emailed link. A line says “You ordered these from Northfell Outfitters on 29/08/2026. Tell other shoppers what you thought.” The first card, Calder Ceramic Mug, is already done: five black stars, a grey “Waiting to be checked” badge, the review text, and a line offering to sort out a mistake. The second card, Southgate Enamel Jug, is still open: a “Your rating” row of five grey stars with “1 is poor, 5 is great” under it, an empty review box reading “0 characters — 25 more to go”, a collapsed “Posting as Noor W. — Change”, and a Submit review button. A footnote says a person at the store reads the review before it goes on the site, that it gets published whatever the rating, and that the unflattering ones are not dropped.

What it puts on the product page

The badge is the point, and the paragraph above the list is what makes it mean something: it says in plain words what the mark is, that unmarked reviews came through the form, and that critical reviews are not removed. Both are spliced into the theme already running, both are yours to reword per language, and turning one off takes the other with it.

A product page’s review list. Above it a paragraph headed “How we handle reviews” explains that every review is checked before it is published, that all reviews passing that check are published and none is removed for being critical, that a review marked Verified purchase was written by a customer invited by email after buying that product and matched to the order it came from, that reviews without the mark came through the form on the page, that the star average is calculated from published reviews, and that reviews are neither paid for nor accepted from anyone with a commercial relationship. Below it one review: “Noor W.” with a green Verified purchase badge beside the name, the date on the right, the review text and five stars. Under that, OpenCart’s own Write a review form.

One row per order, in one of nine states

A queue rather than a send-and-hope. Needs a look counts the rows pointing at something that has changed since (an order refunded, a review deleted with its product), and a failed send carries your mail engine’s own error with a Resend button, because a message that never left is a thing you can act on.

The Requests tab of the Review Requests module. A dismissible notice repeats that approving a review on OpenCart 4.1 does not change the product’s star average. Below it ten buckets count the requests in each state (Needs a look 1 in amber, Upcoming 0, Asked 4 selected, Reminded 0, Send interrupted 0, Send failed 1, Waiting to be checked 0, On the site 1, Not asked 0, Unsubscribed 0), and a Filter button. Then a table of four orders with the customer’s address, the state, how many of the order’s products have been reviewed, the rating and the date. The last row is open, listing its five products with “Not reviewed” beside each.

Why nothing is sending

Seven lines, each naming the screen that fixes it, and the sixth is the one no other extension can answer: it checks the review template your store renders rather than OpenCart’s, so a theme where the badge would silently not appear says so here instead of on the product page.

The “Before anything is sent” checklist at the top of the Settings tab, reading “This store is set up to send.” Seven green ticks: this store can send email; emails from this store link to http://127.0.0.1:8090/, with a note that the address is a constant in config.php and no admin screen can change it; reviews are switched on so the reviews you collect are displayed; customers are asked once their order reaches the status you chose; a pass ran at 2026-08-29 09:57:43; the verified-purchase badge has somewhere to go in this store’s review template; and approving a review on OpenCart 4.1 does not change the star average. Under them a line saying 0 orders sit behind where the extension started reading, a “Run a pass now” button, and a “Start an initial collection” button.

Pre-Order, screen by screen

A lantern is on its way and the date is known. This is every screen between marking it and the customer paying for it, in order, handed between the merchant and the shopper twice.

What Pre-Order is says what it does and what it does not; this is what using it looks like.

Where a pre-order is made

One tab on the product you already had open, and the whole answer is on it. The three option values disagree with the product on purpose: Large is on the shelf, Medium follows the product, and Small is a pre-order with a date a month later than the product’s. That is the claim this screen proves: per option value, not per product.

The Pre-Order tab of a product in Catalog → Products. A blue notice says a product with nothing set here is not a pre-order, and that it can be turned on for the product or left off with individual option values set below. “Sell as a pre-order” is a toggle, switched on, with “Every option value follows this unless you say otherwise below.” under it. “Available from” holds 03/17/2027 and a note that it is what the customer is told at checkout, and that leaving it empty is a real answer. “Payment” is a dropdown reading “Charge when stock arrives”, with a note explaining that Charge in full takes the money at checkout and Charge when stock arrives takes the order without charging and emails a payment link once the stock lands. Below, an “Option values” table with three rows (Size › Large set to “Not a pre-order”, Size › Medium set to “Same as the product”, Size › Small set to “Pre-order” with its own date of 04/21/2027), each with its own Available from and Payment column.

The line under the price, everywhere at once

The same line appears on category pages, search results, brand pages and related-product strips, from one template, so a shopper browsing never clicks through to be surprised. No theme file is edited to get it, which is also why a heavily customised theme can end up without it.

A product card as it appears on a category page: the placeholder image, the name “Halcyon Field Lantern” in blue, the price $48.00, a grey “Ex Tax: $48.00”, and under that a line with a clock icon reading “Pre-order · ships 17/03/2027”. Below the card, the theme’s own row of cart, wishlist and compare buttons.

What the shopper agrees to

The date, the terms and the button’s own wording, shown before the basket rather than at it, and all three yours to reword per language. The third sentence is the one restriction a shopper can hit: a deferred pre-order is checked out on its own, because an order carries one payment method.

A product page above the add-to-cart row. A pale blue panel headed “Pre-order” with a clock icon reads “Expected 17/03/2027”, then “You will not be charged today. When the item arrives we will email you a link to pay. Pre-order items have to be ordered on their own, without in-stock items in the same basket.” Under the panel, a Qty field holding 1 and a blue button labelled Pre-Order where Add to Cart would be.

What is owed, and what it refused to do

The stock landed and did not cover everybody, so nothing was emailed. The two orders sit in Ready to notify with the shortfall spelled out in red and a button that sends anyway. That is the whole of the rationing policy: there is none, and the decision is handed back with the number in front of you. The last table is the audit: the status Pre-Order would have named, beside the status the order is really on.

The Pre-Orders screen. Five counters across the top: Live pre-orders 3, Lines waiting on stock 0, Lines ready 3, Orders asked to pay 1, Lines expired 0. Then a blue-bordered “Ready to notify” panel explaining that every pre-order line on these orders has landed and nobody has been asked to pay yet, listing orders #3 Noor Whitlam and #2 Idris Vance, each with a red sentence saying there is not enough stock for everyone waiting so nothing was sent automatically, and a blue “Send payment request” button. Then an amber-bordered “Asked to pay, not paid” panel noting that a link stops working at the end of its window whether or not anything on the store records it, listing order #1 Marta Kelsey, asked 0 days ago, state Ready, order status Pre-Order Payment Requested, with a Reissue button. Then an “Owed by product” table with a Download CSV button, one row per product or option being pre-ordered, giving the payment mode, the expected date, units owed, on hand and short by: Halcyon Field Lantern owes 4 with 2 on hand, short by 2 in red. Last a “Pre-orders” table of all three orders with the customer, the pre-order lines, the expected date 17/03/2027, the state, the payment mode “Charge when stock arrives” and the order status each is really on.

The page the link opens

No login and no account: the single-use link is the identity, which is what lets a guest pre-order like anybody else. The notice at the top is the guarantee: the order is replayed exactly as it was committed, at the price it was placed at, and nothing is recalculated. The link is dead at the end of its window whether or not your host ever calls OpenCart’s scheduler.

The “Pay for your pre-order” page for Order 1, opened from the emailed link. A blue notice reads “This is the order you placed, at the price you placed it. Nothing has been recalculated.” Below it the order as committed: one line, Halcyon Field Lantern, Model HAL-3300, quantity 1, $48.00; then Sub-Total $48.00, Flat Shipping Rate $5.00, Eco Tax (-2.00) $2.00, VAT (20%) $1.00 and Total $56.00. Under that a heading “How would you like to pay?” and a Cash On Delivery radio button.

Product Configurator, screen by screen

A writing desk that comes in oak or aluminium, where half the questions only apply to one of them. Two screens: the two rules that say so, and a customer meeting them.

What Product Configurator is says what it does and what it does not; this is what using it looks like.

Where a rule is written

A tab on OpenCart’s own product form, saved by that form’s own Save button. There is no second screen and no second save. The two rules differ in their target on purpose: the first takes away a whole option, the second takes away one value, Brass, and leaves the rest of Handle finish standing. That second shape is the compatibility case, and it is the one a list of parts needs.

The Configurator tab on a product’s edit form, carrying two rules. Rule 1 reads WHEN Frame material is Aluminium THEN hide the option Wood stain; Rule 2 reads WHEN Frame material is Aluminium THEN hide the value Brass of Handle finish. Each line is a row of dropdowns, with a plus button to add a condition and an Add Rule button underneath.

The same two rules, from the customer’s side

Aluminium is picked, so Wood stain has gone and Brass has gone with it. That happens as the customer clicks, with no reload, on the page the store’s own theme draws. The swatches are not a second feature to configure: OpenCart already held an image on each frame value, and this draws it. What the picture cannot show is the half that matters: add this to the cart with a hidden answer forced in and OpenCart’s own validation refuses it.

The Aldbury Writing Desk on the storefront, mid-configuration. Frame material is drawn as two swatch tiles, Oak and Aluminium, with Aluminium picked and outlined. Beneath it Handle finish offers Brushed steel alone, and the Wood stain option that was there a moment ago is gone.

These are photographs of the admin screens, not mock-ups. Each set was taken against a store built for the purpose by a command in our repository, which asserts what is on the screen before it takes the picture, and throws the store away afterwards.