/*
 * The one stylesheet, shared by the marketing pages and the app.
 *
 * Lifted out of index.html when the site gained real pages. It was inline
 * because there was one page; the moment there were five, inline meant five
 * copies that drift, and a product whose about page does not look like its
 * schedule is not one product.
 *
 * Tokens first, then base, then components. brand.css loads AFTER this one and
 * overrides the tokens — that ordering is what lets a business set a typeface
 * and a palette without touching anything here.
 */
/* One stylesheet, tokenised, both themes. This is used on a phone behind a
   counter as often as on a laptop, so nothing here assumes a pointer or a wide
   viewport. */
:root{
  --bg:#fbfcfd; --surface:#fff; --sunk:#f1f4f7;
  --ink:#101720; --ink-2:#47535f; --ink-3:#6b7885;
  --line:#dde4ea; --line-2:#c2cdd6;
  --accent:#0d5c73; --accent-ink:#fff; --accent-soft:#e3eef2;
  --bad:#a32820;
  /* Roles the palette in brand.css fills in. Declared here too so the page is
     never styled by a variable nothing defines — an undeclared var() does not
     error, it just renders the element unstyled, which this project has been
     caught by before. */
  --warm:#65503f; --warm-soft:#f1e8de; --chart:#6e87a3; --neutral:#6a6a63;
  --radius:10px;
  /* Overridable in brand.css, which loads after this block. The fallbacks stay
     in the stack there too: they are what the first paint uses, and what a
     visitor sees if the font file ever fails to arrive. */
  --font:ui-sans-serif,system-ui,-apple-system,"Segoe UI",sans-serif;
}
@media (prefers-color-scheme:dark){:root:not([data-theme=light]){
  --bg:#0d1317; --surface:#151d23; --sunk:#1b252c;
  --ink:#e9eff3; --ink-2:#b2c0c9; --ink-3:#8496a2;
  --line:#25323a; --line-2:#394a55;
  --accent:#5cb4cd; --accent-ink:#06232c; --accent-soft:#16303a;
  --bad:#e8867c;
  --warm:#c4a488; --warm-soft:#3a2e24; --chart:#8fa6bf; --neutral:#9c9c93;
}}
*{box-sizing:border-box}
body{margin:0;background:var(--bg);color:var(--ink);
  font:15px/1.55 var(--font);
  -webkit-font-smoothing:antialiased}
/* Headings may use a separate display face. The var() fallback means
   brand.css does not have to define --font-display: leave it out and
   headings simply use the body face. */
h1,h2,h3{margin:0;line-height:1.2;text-wrap:balance;
  /* The brand face, if brand.css names one. Three tiers, each falling back to
     the next, so a deployment that sets none of them still renders. */
  font-family:var(--font-brand,var(--font))}
/* A DISPLAY face is drawn for large sizes. Reserved for h1 — at the 15px an h3
   renders at, a condensed display face is cramped rather than characterful. */
h1{font-family:var(--font-display,var(--font-brand,var(--font)))}
h1{font-size:1.5rem;letter-spacing:-.02em}
h2{font-size:1.1rem;letter-spacing:-.01em}
h3{font-size:.95rem}
button{font:inherit}
.hidden{display:none!important}

header{position:sticky;top:0;z-index:20;background:var(--surface);
  border-bottom:1px solid var(--line);padding:10px 16px;
  display:flex;gap:12px;align-items:center;flex-wrap:wrap}
.brand{font-weight:650;margin-right:auto;display:flex;align-items:center;gap:10px;
  line-height:1.25}
.brand .stack{display:flex;flex-direction:column}
.brand small{font-weight:400;color:var(--ink-3);font-size:11.5px}
.brand img{height:30px;width:auto;max-width:130px;object-fit:contain;border-radius:5px}
/* WRAPS, never scrolls sideways.
   It used to be overflow-x:auto, which on any screen narrower than the row hid
   part of the navigation behind a horizontal scroll with nothing to say so —
   reported from a live install as tabs you have to scroll to find, which is not
   a thing anybody looks for in a nav bar. Wrapping costs a second line on a
   narrow screen and hides nothing. */
.tabs{display:flex;flex-wrap:wrap;gap:2px;background:var(--sunk);padding:3px;
  border-radius:var(--radius);max-width:100%}
.tabs button{border:0;background:transparent;color:var(--ink-2);padding:7px 12px;
  border-radius:7px;cursor:pointer;white-space:nowrap;font-size:13.5px}
.tabs button[aria-selected=true]{background:var(--surface);color:var(--ink);font-weight:600;
  box-shadow:0 1px 2px rgba(0,0,0,.08)}

/* The screens a manager sets up once and revisits twice a year. A <details>
   rather than a scripted menu: it opens on Enter, closes on Escape, and is
   reachable by keyboard without any of that being written by hand. */
.tabs .more{position:relative}
.tabs .more>summary{list-style:none;cursor:pointer;color:var(--ink-2);padding:7px 12px;
  border-radius:7px;white-space:nowrap;font-size:13.5px;user-select:none}
.tabs .more>summary::-webkit-details-marker{display:none}
.tabs .more>summary::after{content:" \25BE";opacity:.6}
.tabs .more>summary[aria-selected=true]{background:var(--surface);color:var(--ink);
  font-weight:600;box-shadow:0 1px 2px rgba(0,0,0,.08)}
.tabs .more[open]>summary{background:var(--surface);color:var(--ink)}
.tabs .more-menu{position:absolute;z-index:40;top:calc(100% + 6px);right:0;
  display:flex;flex-direction:column;gap:2px;min-width:170px;padding:5px;
  background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);
  box-shadow:0 8px 24px rgba(0,0,0,.14)}
.tabs .more-menu button{text-align:left;width:100%}
/* Never taller than the space under it. Seven items on a short phone ran off the
   bottom, so the menu itself became something to scroll — which is exactly the
   thing this row was supposed to stop being. */
.tabs .more-menu{max-height:60vh;overflow-y:auto}
/* On a phone a menu pinned to the right of a wrapped row can still land under
   the edge, so it fills the width instead. */
@media (max-width:560px){
  .tabs .more{position:static}
  .tabs .more-menu{left:8px;right:8px;min-width:0}
}
.btn{border:1px solid var(--line-2);background:var(--surface);color:var(--ink);
  padding:8px 13px;border-radius:8px;cursor:pointer;font-size:13.5px;
  /* The home page uses <a class="btn"> for its calls to action, and a link
     carries an underline by default — so the primary button rendered as
     underlined text in a box. Buttons are not links to look at. */
  text-decoration:none;display:inline-block;text-align:center}
.btn:hover{border-color:var(--accent)}
.btn.primary{background:var(--accent);border-color:var(--accent);color:var(--accent-ink);font-weight:600}
.btn.sm{padding:5px 9px;font-size:12.5px}
.btn[disabled]{opacity:.5;cursor:default}
:focus-visible{outline:2px solid var(--accent);outline-offset:2px}

main{max-width:1060px;margin:0 auto;padding:20px 16px 80px;display:flex;
  flex-direction:column;gap:18px}
.card{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);padding:18px}

/* A card that folds. Optional settings — and the demand model this site is NOT
   using — were rendered in full at 0.6 opacity under a heading saying "(not in
   use)": a working form that reads as disabled, which is the worst of both. A
   day-one Shifts screen was 2095px of six sections at equal weight. Closed, the
   summary still says what is inside and what state it is in, so nothing is
   hidden — only folded. */
details.card{padding:0}
details.card>summary{padding:18px 44px 18px 18px;cursor:pointer;list-style:none;
  display:flex;gap:3px 10px;align-items:baseline;flex-wrap:wrap;position:relative}
details.card>summary::-webkit-details-marker{display:none}
/* Absolutely placed, so it is NOT one of the wrapping items. As a flex child with
   margin-left:auto it dropped onto a second line the moment the title and its tag
   filled a phone's width, which reads as a card that failed to finish drawing. */
details.card>summary::after{content:'';position:absolute;right:20px;top:calc(50% - 5px);
  width:8px;height:8px;
  border-right:1.5px solid var(--ink-3);border-bottom:1.5px solid var(--ink-3);
  transform:rotate(45deg);transition:transform .15s}
details.card[open]>summary::after{transform:rotate(-135deg);top:calc(50% - 2px)}
details.card>summary h2{margin:0}
details.card>summary .tag{font-size:12px;color:var(--ink-3)}
details.card>.fold{padding:0 18px 18px}
details.card[open]>summary{border-bottom:1px solid var(--line);margin-bottom:16px}

/* A tick and the sentence it belongs to. `.row` is flex-WRAP, so on a phone a
   long label broke onto the line below its own checkbox and the two stopped
   reading as one control. Aligned to the first line rather than centred, because
   the sentence is often three lines and a box centred against them floats. */
label.check{display:flex;gap:9px;align-items:flex-start;cursor:pointer}
label.check input{margin-top:3px;flex:none}

/* The FAQ. One column of questions, answers on demand — the same fold the app
   uses for what is optional, so the site and the product agree about what a
   closed disclosure looks like. Its own rules rather than details.card's,
   because these sit INSIDE a card rather than being one. */
.faq details{border-top:1px solid var(--line)}
.faq details:last-child{border-bottom:1px solid var(--line)}
.faq summary{list-style:none;cursor:pointer;padding:12px 30px 12px 0;position:relative;
  font-weight:600;font-size:14.5px}
.faq summary::-webkit-details-marker{display:none}
.faq summary::after{content:'';position:absolute;right:8px;top:calc(50% - 4px);
  width:7px;height:7px;border-right:1.5px solid var(--ink-3);
  border-bottom:1.5px solid var(--ink-3);transform:rotate(45deg);transition:transform .15s}
.faq details[open] summary::after{transform:rotate(-135deg);top:calc(50% - 1px)}
.faq details>p{margin:0 0 14px;max-width:70ch}
.hint{color:var(--ink-3);font-size:13px;margin:2px 0 0}
.row{display:flex;gap:10px;flex-wrap:wrap;align-items:center}
label.fld{display:flex;flex-direction:column;gap:4px;font-size:12.5px;color:var(--ink-2);
  min-width:150px;flex:1}
input,select,textarea{font:inherit;padding:8px 10px;border:1px solid var(--line-2);
  border-radius:8px;background:var(--surface);color:var(--ink);min-width:0}
table{border-collapse:collapse;width:100%;font-size:13.5px}
th,td{text-align:left;padding:8px 10px;border-bottom:1px solid var(--line);vertical-align:top}
th{font-size:11px;text-transform:uppercase;letter-spacing:.08em;color:var(--ink-3);font-weight:500}
/* A SHADOW THAT SAYS THERE IS MORE, and only when there is.
   
   Every wide table in the product sits in one of these — the published schedule,
   the team, payroll, the coverage template — and on a phone they all overflow.
   Scrolling worked; nothing said it was possible. The manager's own week was cut
   mid-name at 390px with days three to seven off the edge, on a card whose left
   column and every row were fully visible, which is what makes a truncation
   silent rather than obvious.
   
   The two `local` layers are painted in page coordinates, so they sit ON the
   corresponding shadow and hide it exactly when that edge is reached; the two
   `scroll` layers stay pinned to the viewport of the box. No script, no resize
   listener, and it is right on the first paint — which matters, because the
   thing it is announcing is only visible for as long as somebody has not yet
   scrolled. */
.scroll{overflow-x:auto;
  background:
    linear-gradient(to right, var(--surface) 40%, rgba(255,255,255,0)) left center / 28px 100% no-repeat local,
    linear-gradient(to left, var(--surface) 40%, rgba(255,255,255,0)) right center / 28px 100% no-repeat local,
    radial-gradient(farthest-side at 0 50%, rgba(0,0,0,.14), rgba(0,0,0,0)) left center / 12px 100% no-repeat scroll,
    radial-gradient(farthest-side at 100% 50%, rgba(0,0,0,.14), rgba(0,0,0,0)) right center / 12px 100% no-repeat scroll}
.tiles{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:1px;
  background:var(--line);border:1px solid var(--line);border-radius:var(--radius);overflow:hidden}
.tile{background:var(--surface);padding:13px 15px}
.tile .k{font-size:11px;text-transform:uppercase;letter-spacing:.08em;color:var(--ink-3)}
.tile .v{font-size:1.35rem;font-weight:650;font-variant-numeric:tabular-nums;margin-top:3px}
.pill{display:inline-block;font-size:11px;padding:2px 8px;border-radius:20px;
  background:var(--accent-soft);color:var(--accent);font-weight:600}
/* The only literal colours left in this stylesheet were here, so a palette
   change could not reach them. */
.pill.warn{background:var(--warm-soft);color:var(--warm)}
.note{border-left:3px solid var(--accent);background:var(--sunk);padding:11px 14px;
  border-radius:0 8px 8px 0;font-size:13.5px;color:var(--ink-2)}
.note.bad{border-left-color:var(--bad);color:var(--bad)}
/* Something needs doing, but nothing is wrong — unsent changes rather than an
   error. Oxblood for that would tell somebody their picks had failed. */
.note.warn{border-left-color:var(--warm);color:var(--warm)}
.grid{display:grid;gap:1px;background:var(--line);border:1px solid var(--line);
  border-radius:var(--radius);overflow:hidden;min-width:700px}
.grid>div{background:var(--surface);padding:9px 10px;font-size:12.5px}
.grid .hd{background:var(--sunk);font-weight:600;font-size:11.5px}
.who{display:block;padding:2px 0;color:var(--ink-2)}
.centre{max-width:430px;margin:8vh auto;padding:0 16px}
@media (prefers-reduced-motion:reduce){*{transition:none!important;animation:none!important}}

/* ---- the home page ---- */
/* The PUBLIC pages carry the brand face for their prose. The APP does not,
   by default: its screens are dense tables of times and head-counts at 13px,
   and a text serif is drawn for reading sentences rather than for telling
   11:00 from 14:00 at a glance. To use the brand face there too, uncomment
   --font in brand.css — it is one line, and the trade is legibility of the
   numbers against consistency of the voice.

   Keyed on body.marketing, which the server-rendered pages carry. It used to be
   #home, an id inside the app shell — and when the marketing moved out into real
   pages, that selector silently stopped matching anything a visitor sees. The
   typeface just quietly went missing from the whole public site. */
body.marketing{font-family:var(--font-brand,var(--font))}
.hero{max-width:1060px;margin:0 auto;padding:56px 16px 20px;text-align:center}
.hero h1{font-size:clamp(1.9rem,5vw,2.7rem);letter-spacing:-.03em}
/* 52ch, not 44: a lede is often a full paragraph rather than one line, and
   at 44 a real product description wraps into eight short ragged lines. */
.hero p.lede{color:var(--ink-2);font-size:1.05rem;max-width:52ch;margin:14px auto 0}
.plans{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));gap:14px}
.plan{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);
  padding:18px;display:flex;flex-direction:column;gap:6px}
.plan .price{font-size:1.8rem;font-weight:650;letter-spacing:-.02em}
.plan .price small{font-size:.8rem;font-weight:400;color:var(--ink-3)}
.points{display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:16px}
footer{max-width:1060px;margin:0 auto;padding:24px 16px 60px;color:var(--ink-3);font-size:12.5px}

/* ---- the staff app ---- */
/* auto-FIT, not auto-fill. auto-fill keeps the empty tracks, so a team of one
   drew a narrow button in the left half of a two-column grid, orphaned under
   centred text — and a shop with one employee is every shop on its first day.
   auto-fit collapses them, so one name is one full-width button and several are
   unchanged. */
.names{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:8px}
.names button{padding:14px 10px;border-radius:10px;border:1px solid var(--line-2);
  background:var(--surface);color:var(--ink);cursor:pointer;font-size:15px;font-weight:550;
  /* The first thing anybody taps in this product, on a phone, where there is no
     hover to fall back on. Without a pressed state a tap reads as ignored —
     which is exactly how the PIN pad this sits above came to be reported broken
     three times. touch-action drops the 300ms double-tap wait. */
  touch-action:manipulation}
.names button:active{background:var(--sunk);border-color:var(--accent);transform:scale(.985)}
/* A PIN is typed into a real field, so the phone opens its own number pad and
   the person can see that a digit registered. The custom keypad this replaced
   was reported broken three times — sized wrong, no press feedback, and finally
   not showing input at all — and every browser test drove it with click(),
   which needs none of the things a thumb needs. */
.reveal{position:relative;display:block}
.reveal input{width:100%;padding-right:64px;font-size:17px;letter-spacing:.14em}
/* 16px or more, or iOS zooms the whole page in on focus and never zooms back. */
.peek{position:absolute;right:6px;top:50%;transform:translateY(-50%);
  border:0;background:none;color:var(--accent);font:inherit;font-size:13px;
  font-weight:600;padding:8px 10px;cursor:pointer;border-radius:8px;
  touch-action:manipulation}
.peek:hover{background:var(--accent-soft)}
.peek:active{opacity:.7}
/* THE WEEK PICKER, which turns sideways on a phone.
   
   Every cell is placed EXPLICITLY from two custom properties the markup carries
   — its day and its shift — rather than by document order. That is what lets a
   media query transpose the whole grid without a second copy of the DOM: the day
   headings still come from dowOf and cannot drift out of step with the cells
   underneath them, which is the bug this screen has already shipped once.
   
   Seven days across 390px does not fit: measured at 518px inside a 320px box,
   with Friday to Sunday off the edge and nothing to say so. Three shifts across
   a phone fit comfortably, and seven days DOWN one is what a phone is for. */
.picker{display:grid;gap:1px;background:var(--line);border:1px solid var(--line);
  border-radius:var(--radius);overflow:hidden;
  grid-template-columns:var(--cols-wide);min-width:520px}
.picker>div{background:var(--surface);padding:0}
.picker .corner{grid-row:1;grid-column:1}
.picker .dayhd{grid-row:1;grid-column:calc(var(--d) + 2)}
.picker .shifthd{grid-column:1;grid-row:calc(var(--s) + 2);text-align:left}
.picker .cell{grid-column:calc(var(--d) + 2);grid-row:calc(var(--s) + 2)}
@media (max-width:560px){
  .picker.flip{grid-template-columns:var(--cols-narrow);min-width:0}
  /* The two axes swap, and so does the alignment: a day is a row label now and
     a shift is a column heading. */
  .picker.flip .dayhd{grid-column:1;grid-row:calc(var(--d) + 2);text-align:left;
    display:flex;flex-direction:column;justify-content:center}
  .picker.flip .shifthd{grid-row:1;grid-column:calc(var(--s) + 2);text-align:center}
  .picker.flip .cell{grid-column:calc(var(--s) + 2);grid-row:calc(var(--d) + 2)}
  /* A thumb, not a cursor. 44px is the smallest target Apple will call
     comfortable and this is the one control the whole product is used through. */
  .picker.flip button.slot{padding:15px 4px;min-height:46px}
}
.picker .hd{background:var(--sunk);font-weight:600;font-size:11.5px;padding:8px 6px;
  text-align:center}
.picker button.slot{width:100%;border:0;background:transparent;color:var(--ink-3);
  padding:12px 4px;cursor:pointer;font-size:12px}
/* A shift somebody has ASKED for, which is the one thing on this screen that
   is a preference rather than a fact. The warm accent separates "I want this"
   from every other selected state in the app, which are all blue. */
.picker button.slot.on{background:var(--warm-soft);color:var(--warm);font-weight:650}
.rank{display:inline-block;min-width:18px}

/* A row built from too few observations to read a shape into. Deliberately a
   WORDED marker rather than a colour or a grade: the whole reason these reports
   have no score is that a number tells a manager what to think, and a quiet grey
   asterisk would be a score with extra steps. */
.thin{display:inline-block;background:var(--sunk);color:var(--ink-3);
  border-radius:5px;padding:1px 6px;font-size:11px;white-space:nowrap}

/* The shifts somebody has been given. One line on a laptop, stacked on a phone,
   and clipped at no width — which the six-column table it replaces could not
   say: its two actions sat off the right edge of a 390px screen, so an employee
   who needed to say they could not work a shift could not see the button. */
ul.shifts{list-style:none;margin:10px 0 0;padding:0;border-top:1px solid var(--line)}
ul.shifts li{display:flex;flex-wrap:wrap;gap:8px 14px;align-items:center;
  justify-content:space-between;padding:11px 0;border-bottom:1px solid var(--line)}
ul.shifts .when{display:flex;flex-direction:column;gap:2px;min-width:0}
ul.shifts .when .hint{margin:0}
ul.shifts .acts{display:flex;gap:8px;flex-wrap:wrap}
/* A shift the business is paying extra for. It has to read as an OFFER rather
   than as a warning, so it borrows the warm accent the picker already uses for
   "I want this" rather than the red that means something is wrong. */
.picker button.slot.paid{box-shadow:inset 0 0 0 1.5px var(--warm)}
.picker button.slot .extra{display:block;font-size:10px;font-weight:700;
  color:var(--warm);letter-spacing:.02em;margin-top:2px}

/* ---- the public pages ----
   Home, how it works, pricing and about are real pages served by the server,
   not sections of the app. These are the few rules they need beyond what the
   app already provides. */
header.site{position:sticky;top:0;z-index:20;background:var(--surface);
  border-bottom:1px solid var(--line);padding:10px 16px;
  display:flex;gap:12px;align-items:center;flex-wrap:wrap}
header.site .brand{font-weight:650;margin-right:auto;text-decoration:none;color:var(--ink);
  display:flex;align-items:center;gap:10px}
header.site .brand img{display:block;width:auto;max-width:170px;object-fit:contain}
.site-nav{display:flex;gap:4px;flex-wrap:wrap}
.site-nav a{color:var(--ink-2);text-decoration:none;padding:7px 11px;border-radius:8px;
  font-size:13.5px}
.site-nav a:hover{background:var(--sunk);color:var(--ink)}
/* The page you are on, marked for everyone rather than only for a mouse. */
.site-nav a[aria-current=page]{background:var(--accent-soft);color:var(--accent);font-weight:600}
.hero.narrow{padding-top:44px}
.hero.narrow h1{font-size:clamp(1.7rem,4vw,2.3rem)}
.prose p{margin:0 0 12px;font-size:14.5px;line-height:1.65;color:var(--ink-2)}
.prose p:last-child{margin-bottom:0}
/* A legal page is the one long document on this site, and the only one somebody
   reads looking for one particular sentence. So it gets real headings to scan
   by and lists that sit apart from the prose — a wall of justified paragraphs is
   how a terms page comes to be agreed to without being read. */
.prose h2{font-size:15px;margin:26px 0 10px;letter-spacing:-.01em}
.prose h2:first-child{margin-top:0}
.prose ul{margin:0 0 12px;padding-left:20px}
.prose li{font-size:14.5px;line-height:1.65;color:var(--ink-2);margin-bottom:7px}
.prose li:last-child{margin-bottom:0}
.prose.legal{max-width:70ch}
/* The yearly line, directly under the monthly price it is an alternative to.
   Bordered rather than merely coloured, because it is a second price and two
   prices on one card need to be told apart by something other than size. */
.plan .annual{margin:8px 0 0;padding:8px 10px;border-radius:8px;
  background:var(--accent-soft);color:var(--accent)}
.plan .annual strong{color:var(--accent)}
/* The brand mark where it is shown as a picture rather than as a logo: the staff
   sign-in, the About page, the 404. Capped by WIDTH as well as height so it
   cannot dominate a 390px phone, which is where the staff app mostly lives. */
.mark{display:block;margin:0 auto 14px;height:auto;width:100%;max-width:160px;
  border-radius:10px}
.mark.big{max-width:220px}
/* Directly under the price, not pinned to the floor of the tallest card. The
   plans genuinely differ in length — the larger two are "everything below, plus"
   — so margin-top:auto left the short columns with a void above their button and
   put the cheapest plan's button 750px under its own price. */
.plan .btn{margin-top:14px}
/* The line above the headline. --ink-2 rather than the accent: it is the
   category the page is in, not a thing to look at, and it sits directly above
   the largest text on the site. */
.hero .eyebrow{color:var(--ink-2);font-size:13px;font-weight:600;letter-spacing:.04em;
  text-transform:uppercase;margin:0 0 12px}
/* The requests a manager is already carrying. Set as speech rather than as a
   list, because that is what they are. */
.quotes{list-style:none;padding:0;margin:0;display:grid;
  grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:10px}
.quotes li{background:var(--sunk);border-radius:10px;padding:11px 13px;
  color:var(--ink-2);font-size:14px;font-style:italic}
/* Feature and qualification lists. The marker is drawn with a pseudo-element
   rather than a list-style so it can take the accent without the text doing so
   — accent-coloured body text is the thing the contrast suite fails on. */
.ticks{list-style:none;padding:0;margin:14px 0 0;display:grid;gap:7px}
.ticks li{position:relative;padding-left:22px;color:var(--ink-2);font-size:14px;
  line-height:1.5}
.ticks li::before{content:"";position:absolute;left:4px;top:.55em;width:9px;height:9px;
  border-radius:50%;background:var(--accent-soft);border:1.5px solid var(--accent)}
.plan .ticks{margin-top:10px}
/* The product itself, above the argument for it. Full-bleed inside its card and
   clipped to the radius, so it reads as a window onto the app rather than as a
   picture pasted onto a page. */
.card.shot{padding:0; overflow:hidden}
.card.shot img{display:block; width:100%; height:auto; border-bottom:1px solid var(--line)}
.card.shot .hint{padding:12px 18px; margin:0}
footer.site{max-width:1060px;margin:0 auto;padding:28px 16px 60px;color:var(--ink-3);
  font-size:12.5px;border-top:1px solid var(--line);display:flex;flex-direction:column;gap:8px}
footer.site a{color:var(--ink-2)}
@media (max-width:600px){
  header.site{gap:8px}
  .site-nav{order:3;width:100%}
  .site-nav a{padding:6px 9px}
}
