/* Ball Buddy — website design system (mockups). Same language as the designer: Ink Colour. */
:root{
  --site:#FFFFFF; --bg:#F2F1F6; --paper:#FFFFFF;
  --ink:#181721; --ink2:#4B4956; --grey:#8B8996; --rule:#E5E3EC;
  --live:#2757D6; --live-deep:#1E48BF; --live-soft:#E8EEFB;
  --red:#E03B2B; --green:#159C63; --amber:#B8892A;
  --ok-bg:#E4F6EC; --ok-fg:#0E7A4C;
  --warn-bg:#FFF4E2; --warn-fg:#7A4E0A;
  --bad-bg:#FDECEA; --bad-fg:#8A2418;
  --violet-bg:#EDE9FB; --violet-fg:#5B3FB8;
  --disp:"Bricolage Grotesque",system-ui,sans-serif;
  --body:"Instrument Sans",system-ui,sans-serif;
  --stencil:"Allerta Stencil",sans-serif;
  --r:14px; --shadow:0 1px 2px rgba(24,23,33,.05);
}
*{box-sizing:border-box}
html,body{margin:0;padding:0}
body{background:var(--site); color:var(--ink); font-family:var(--body); font-size:16px; line-height:1.55;
     -webkit-font-smoothing:antialiased; padding-bottom:70px}
a{color:var(--live)}
img,svg{max-width:100%}
h1,h2,h3,.disp{font-family:var(--disp); letter-spacing:-.03em; line-height:1.05; margin:0}
h1{font-weight:800; font-size:clamp(34px,5vw,56px); letter-spacing:-.04em}
h2{font-weight:800; font-size:clamp(26px,3.4vw,36px)}
h3{font-weight:700; font-size:19px; letter-spacing:-.02em}
p{margin:0}
.muted{color:var(--ink2)}
.small{font-size:13.5px; color:var(--grey)}
.slab{font-size:11.5px; font-weight:700; letter-spacing:.14em; text-transform:uppercase; color:var(--grey); margin:0 0 10px}
.container{max-width:1180px; margin:0 auto; padding:0 30px}
.narrow{max-width:760px}
:focus-visible{outline:3px solid var(--live); outline-offset:2px}

/* ---------- nav ---------- */
/* The mark and the menu stay side by side, as they were, but the pair of them
   is moved to the middle of the bar. Four columns do it: the two in the middle
   size to their contents and hold the pair, and the flexible ones either side
   are equal, so whatever the pair measures it lands on the centre. The first
   is empty on purpose -- it is the counterweight to the account group.

   Every child is given a row as well as a column. Without that the brand comes
   first in the markup, the auto-placement cursor has already passed its column
   by the time it reaches the links, and they drop onto a second row. */
.sitenav{position:relative; display:grid; grid-template-columns:1fr auto auto 1fr;
  align-items:center; column-gap:24px; padding:14px 30px;
  border-bottom:1px solid var(--rule); background:var(--site)}
.sitenav .brand{grid-area:1 / 2; justify-self:end}
.sitenav .links{grid-area:1 / 3; justify-self:start}
.sitenav .right{grid-area:1 / 4; justify-self:end}

/* The workshop bar stays where it was, hard left. It is a tool, not a
   shopfront, and it carries an extra child -- the ADMIN chip -- which the
   shop's four columns would stretch across the empty half of the row. */
.adminnav{grid-template-columns:auto auto 1fr auto}
.adminnav .brand{grid-area:1 / 1; justify-self:start}
.adminnav .tag{grid-area:1 / 2; justify-self:start}
.adminnav .links{grid-area:1 / 3; justify-self:start}
.adminnav .right{grid-area:1 / 4; justify-self:end}

/* Hidden on desktop; the mobile block below turns it on. */
.navburger{display:none; flex-direction:column; justify-content:center; gap:4px;
  width:40px; height:40px; padding:9px; border:0; background:none; cursor:pointer; border-radius:9px}
.navburger span{display:block; height:2px; border-radius:2px; background:var(--ink)}
.navburger:hover{background:var(--paper)}
.sitenav.open .navburger span:nth-child(1){transform:translateY(6px) rotate(45deg)}
.sitenav.open .navburger span:nth-child(2){opacity:0}
.sitenav.open .navburger span:nth-child(3){transform:translateY(-6px) rotate(-45deg)}
.navburger span{transition:transform .18s ease, opacity .18s ease}
/* The Workshop link exists twice: as the pill on the bar, and inside the menu
   for narrow screens. Exactly one of the two is ever shown. */
.sitenav .tolab.inmenu{display:none}
.brand{font-family:var(--disp); font-weight:800; font-size:20px; letter-spacing:-.025em; color:var(--ink); text-decoration:none;
       display:flex; align-items:center; flex:0 0 auto}
.brand i{font-style:normal; color:var(--live)}
/* The logo is cut tight to its ink, so its height is the whole mark: ball,
   word and the shade underneath. 34px puts the word at the same cap height
   the old text wordmark had, with the ball added above and below it. */
.brand img{display:block; height:48px; width:auto}
.adminnav .brand img{height:30px}
.sitefoot .brand img{height:42px; margin-bottom:4px}
.sitenav .links{display:flex; gap:22px}
.sitenav .links a{color:var(--ink2); text-decoration:none; font-size:14.5px; font-weight:500}
.sitenav .links a:hover,.sitenav .links a.on{color:var(--ink)}
.sitenav .right{margin-left:auto; display:flex; align-items:center; gap:18px}
.sitenav .right a{color:var(--ink2); text-decoration:none; font-size:14.5px; font-weight:600; display:flex; align-items:center; gap:8px}
.basketpip{background:var(--live); color:#fff; border-radius:99px; min-width:20px; height:20px; display:grid; place-items:center;
           font-size:11.5px; font-weight:700; padding:0 6px}
.adminnav{background:var(--ink); border-bottom:0}
.adminnav .brand{color:#fff}
.adminnav .links a{color:#C9C8D3}
.adminnav .links a:hover,.adminnav .links a.on{color:#fff}
.adminnav .right a{color:#C9C8D3}
.adminnav .tag{font-size:11px; letter-spacing:.12em; text-transform:uppercase; color:#FFD79B; font-weight:700;
               border:1px solid rgba(255,215,155,.4); border-radius:99px; padding:3px 9px}

/* ---------- sections ---------- */
.section{padding:64px 0}
.section.tint{background:var(--bg)}
.section.tight{padding:36px 0}
.sechead{display:flex; align-items:flex-end; justify-content:space-between; gap:20px; margin-bottom:28px; flex-wrap:wrap}
.sechead p{color:var(--ink2); max-width:56ch}

/* ---------- buttons ---------- */
.btn{display:inline-flex; align-items:center; justify-content:center; gap:9px; background:var(--live); color:#fff; border:0; border-radius:99px;
     font-family:var(--disp); font-weight:800; font-size:15.5px; letter-spacing:-.015em; padding:13px 24px; cursor:pointer;
     text-decoration:none; box-shadow:0 6px 16px rgba(39,87,214,.26); white-space:nowrap; line-height:1.1}
.btn:hover{background:var(--live-deep)}
.btn.lg{padding:17px 30px; font-size:17.5px}
.btn.sm{padding:8px 14px; font-size:13.5px; box-shadow:none}
.btn.ghost{background:var(--bg); color:var(--ink2); box-shadow:none; font-family:var(--body); font-weight:600; font-size:14.5px; padding:10px 17px; letter-spacing:0}
.btn.ghost:hover{color:var(--ink); background:#E9E8EF}
.btn.line{background:transparent; border:1.5px solid var(--rule); color:var(--ink); box-shadow:none; font-family:var(--body); font-weight:600; font-size:14.5px; padding:9px 16px; letter-spacing:0}
.btn.line:hover{border-color:var(--ink2); background:transparent}
.btn.ok{background:var(--green); box-shadow:0 6px 16px rgba(21,156,99,.26)}
.btn.ok:hover{background:#0F7F50}
.btn.wide{width:100%}
.btn:disabled{background:#B9BCC7; box-shadow:none; cursor:not-allowed}
.btn .k{font-family:var(--body); font-weight:600; opacity:.8; font-size:.9em}
.linkbtn{background:none; border:0; padding:0; font:inherit; color:var(--live); cursor:pointer; text-decoration:underline; text-underline-offset:3px}

/* ---------- cards & panels ---------- */
.card{background:var(--paper); border:1px solid var(--rule); border-radius:var(--r); box-shadow:var(--shadow); padding:22px}
.card.pad-lg{padding:30px}
.panel{background:var(--bg); border-radius:var(--r); padding:22px}
.stack>*+*{margin-top:14px}
.row{display:flex; align-items:center; gap:12px}
.row.between{justify-content:space-between}
.row.wrap{flex-wrap:wrap}
.grid2{display:grid; grid-template-columns:1fr 1fr; gap:14px}
.grid3{display:grid; grid-template-columns:repeat(3,1fr); gap:18px}
.grid4{display:grid; grid-template-columns:repeat(4,1fr); gap:18px}
.split{display:grid; grid-template-columns:minmax(0,1fr) 380px; gap:36px; align-items:start}
.sticky{position:sticky; top:22px}
/* The basket: items, then the summary with its checkout button, then the
   offers. On a desktop the summary sits beside both. On a phone the columns
   stack, and this order is what puts "Go to checkout" one scroll down instead of
   under six panels of offers -- where nobody who added a design ever found it
   (3 Sep 2026: three baskets, not one checkout). */
.split.basket{grid-template-areas:"lines aside" "offers aside"; grid-template-rows:auto 1fr; row-gap:0}
.split.basket>.lines-col{grid-area:lines}
.split.basket>.offers-col{grid-area:offers}
.split.basket>aside{grid-area:aside}
hr.rule{border:0; border-top:1px solid var(--rule); margin:18px 0}

/* ---------- forms ---------- */
/* A field arrived at from a "Fill it in →" link flashes once. Without it the
   link looks dead when it points at the page you are already on. */
input,select,textarea{scroll-margin-top:90px}
.field.flash{animation:fieldflash 1.7s ease-out}
@keyframes fieldflash{
  0%,50%{box-shadow:0 0 0 3px var(--live-soft); border-radius:10px}
  100%{box-shadow:0 0 0 3px transparent; border-radius:10px}
}
@media (prefers-reduced-motion:reduce){.field.flash{animation:none; box-shadow:0 0 0 3px var(--live-soft); border-radius:10px}}
.field{display:flex; flex-direction:column; gap:6px}
.field+.field,.grid2+.field,.field+.grid2{margin-top:14px}
.field label,.lbl{font-size:12px; font-weight:700; letter-spacing:.08em; text-transform:uppercase; color:var(--grey)}
.field .help{font-size:13px; color:var(--grey)}
input[type=text],input[type=email],input[type=password],input[type=tel],input[type=number],input[type=search],select,textarea{
  font:inherit; font-size:15px; padding:11px 13px; border:1px solid var(--rule); border-radius:10px; background:var(--paper); color:var(--ink); width:100%}
input:focus,select:focus,textarea:focus{outline:0; border-color:var(--live); box-shadow:0 0 0 3px var(--live-soft)}
input::placeholder{color:#B4B2BE}
.check{display:flex; align-items:flex-start; gap:10px; font-size:14.5px; color:var(--ink2); cursor:pointer}
.check input{width:18px; height:18px; margin-top:2px; accent-color:var(--live); flex:0 0 auto}
.choice{display:flex; align-items:center; gap:12px; border:1.5px solid var(--rule); border-radius:12px; padding:13px 15px; cursor:pointer; background:var(--paper)}
.choice.on{border-color:var(--live); box-shadow:0 0 0 3px var(--live-soft)}
.choice input{accent-color:var(--live); width:18px; height:18px}
.choice .t{font-weight:600}
.choice .s{font-size:13px; color:var(--grey)}
.choice .p{margin-left:auto; font-weight:700}
.err{color:var(--bad-fg); font-size:13px}

/* ---------- status ---------- */
.st{display:inline-flex; align-items:center; gap:7px; border-radius:99px; padding:4px 11px 4px 9px; font-size:12.5px; font-weight:700; white-space:nowrap;
    font-family:var(--body); letter-spacing:0; line-height:1.3; vertical-align:middle}
.st::before{content:""; width:7px; height:7px; border-radius:50%; background:currentColor}
.st.new{background:var(--live-soft); color:var(--live)}
.st.paid{background:var(--ok-fg); color:#fff}
.st.printing{background:var(--warn-bg); color:var(--warn-fg)}
.st.printed{background:var(--violet-bg); color:var(--violet-fg)}
.st.sent{background:var(--ok-bg); color:var(--ok-fg)}
.st.done{background:var(--bg); color:var(--ink2)}
.st.hold{background:var(--bad-bg); color:var(--bad-fg)}

/* order progress: a real sequence, so the numbering carries information */
.steps{display:flex; align-items:flex-start; gap:0; margin:6px 0}
.step{flex:1; position:relative; text-align:left; padding-right:12px}
.step .dot{width:26px; height:26px; border-radius:50%; background:var(--paper); border:2px solid var(--rule); display:grid; place-items:center;
           font-size:12px; font-weight:700; color:var(--grey); position:relative; z-index:1}
.step::after{content:""; position:absolute; top:12px; left:26px; right:0; height:2px; background:var(--rule)}
.step:last-child::after{display:none}
.step .t{font-weight:700; font-size:14px; margin-top:9px}
.step .s{font-size:12.5px; color:var(--grey)}
.step.done .dot{background:var(--live); border-color:var(--live); color:#fff}
.step.done::after{background:var(--live)}
.step.now .dot{border-color:var(--live); color:var(--live); box-shadow:0 0 0 4px var(--live-soft)}
.step.now .t{color:var(--live)}

/* ---------- tables ---------- */
.table{width:100%; border-collapse:collapse; font-size:14.5px}
.table th{font-size:11.5px; letter-spacing:.1em; text-transform:uppercase; color:var(--grey); text-align:left; padding:10px 12px; border-bottom:1px solid var(--rule); font-weight:700}
.table td{padding:12px; border-bottom:1px solid var(--rule); vertical-align:middle}
.table tr:last-child td{border-bottom:0}
.table tr.rowlink:hover td{background:#FAFAFC; cursor:pointer}
.table .num{text-align:right; font-variant-numeric:tabular-nums}
.table td.num{font-weight:600}
.mono{font-family:ui-monospace,"SF Mono",Menlo,monospace; font-size:.92em}

/* ---------- the ball ---------- */
.ball{display:block; width:100%; height:auto; aspect-ratio:1; color:var(--live)}
.ball .pen{stroke:currentColor; fill:currentColor}
.ball text{font-family:var(--stencil); fill:currentColor; stroke:none}
.ink-blue{color:var(--live)} .ink-black{color:var(--ink)} .ink-red{color:var(--red)} .ink-green{color:var(--green)}
.thumb{width:56px; height:56px; flex:0 0 auto}
.thumb.lg{width:84px; height:84px}
.pencolour{display:inline-block; width:12px; height:12px; border-radius:50%; vertical-align:-1px; margin-right:5px; box-shadow:0 0 0 1px var(--rule)}

/* ---------- misc ---------- */
.eyebrow{display:inline-flex; align-items:center; gap:8px; font-size:12.5px; font-weight:700; letter-spacing:.1em; text-transform:uppercase; color:var(--live); margin-bottom:18px}
.eyebrow::before{content:""; width:22px; height:3px; border-radius:2px; background:var(--live)}
.notice{display:flex; gap:11px; border-radius:12px; padding:13px 15px; font-size:14px; line-height:1.45}
.notice.ok{background:var(--ok-bg); color:var(--ok-fg)}
.notice.warn{background:var(--warn-bg); color:var(--warn-fg)}
.notice.info{background:var(--live-soft); color:#1C3E9C}
.notice.bad{background:var(--bad-bg); color:var(--bad-fg)}
.crumbs{padding:20px 0 0; font-size:13.5px; color:var(--grey)}
.crumbs a{color:var(--grey); text-decoration:none}
.crumbs span{margin:0 7px}
.price{font-family:var(--disp); font-weight:800; letter-spacing:-.03em}
.kv{display:grid; grid-template-columns:auto 1fr; gap:8px 18px; font-size:14.5px; margin:0}
.kv dt{color:var(--grey); font-weight:600}
.kv dd{margin:0}
.total-row{display:flex; justify-content:space-between; font-size:14.5px; padding:6px 0}
.total-row.big{font-size:19px; font-weight:800; font-family:var(--disp); letter-spacing:-.02em; border-top:1px solid var(--rule); margin-top:8px; padding-top:14px}
details.faq{border-top:1px solid var(--rule); padding:18px 0}
details.faq:last-of-type{border-bottom:1px solid var(--rule)}
details.faq summary{cursor:pointer; font-weight:700; font-size:17px; list-style:none; display:flex; justify-content:space-between; align-items:center; font-family:var(--disp); letter-spacing:-.02em}
details.faq summary::-webkit-details-marker{display:none}
details.faq summary::after{content:"+"; color:var(--grey); font-size:22px; font-weight:400}
details.faq[open] summary::after{content:"–"}
details.faq p{margin-top:10px; color:var(--ink2); max-width:64ch}

/* ---------- footer ---------- */
.sitefoot{border-top:1px solid var(--rule); padding:44px 30px 30px; margin-top:40px; background:var(--site)}
.sitefoot .cols{max-width:1180px; margin:0 auto; display:grid; grid-template-columns:1.6fr 1fr 1fr 1fr; gap:30px}
.sitefoot h4{margin:0 0 12px; font-size:12px; letter-spacing:.12em; text-transform:uppercase; color:var(--grey)}
.sitefoot a{display:block; color:var(--ink2); text-decoration:none; font-size:14.5px; margin-bottom:8px}
.sitefoot a:hover{color:var(--ink)}
.sitefoot .blurb{color:var(--ink2); font-size:14.5px; max-width:36ch; margin-top:10px}
.sitefoot .legal{max-width:1180px; margin:34px auto 0; padding-top:18px; border-top:1px solid var(--rule); display:flex; gap:18px; flex-wrap:wrap; font-size:13px; color:var(--grey)}
.sitefoot .legal a{display:inline; margin:0; font-size:13px; color:var(--grey)}

/* ---------- email frame ---------- */
.emailwrap{background:#EAE9EF; padding:40px 16px; min-height:100vh}
.email{max-width:600px; margin:0 auto; background:#fff; border-radius:14px; overflow:hidden; border:1px solid #DDDCE5}
.email .ehead{padding:22px 30px; border-bottom:1px solid var(--rule)}
.email .ebody{padding:30px}
.email .efoot{padding:20px 30px; background:var(--bg); font-size:12.5px; color:var(--grey); line-height:1.6}
.email h1{font-size:30px}
.email .eitem{display:flex; gap:14px; align-items:center; padding:12px 0; border-bottom:1px solid var(--rule)}
.email .eitem:last-child{border-bottom:0}
.emailmeta{max-width:600px; margin:0 auto 14px; font-size:13px; color:var(--ink2); background:#fff; border:1px solid #DDDCE5; border-radius:10px; padding:12px 16px}
.emailmeta b{color:var(--ink)}

/* The bar collapses sooner than the rest of the layout does. Centring the logo
   means the two outer columns have to be equal, so the row needs room for the
   links twice over plus the mark between them; below about 1150px there is not
   any, and the account group would be shoved off the end. */
/* The centred pair needs its own width twice over, once for the empty column
   and once for the account group. Below that the menu goes behind the burger
   and the bar becomes burger, mark, basket. */
@media (max-width:1060px){
  .sitenav{grid-template-columns:1fr auto 1fr; column-gap:10px; padding:12px 22px}
  .navburger{display:flex; grid-area:1 / 1; justify-self:start}
  .sitenav .brand{grid-area:1 / 2; justify-self:center}
  .sitenav .right{grid-area:1 / 3; justify-self:end; gap:14px; min-width:0}
  .sitenav .tolab.onbar{display:none}      /* the widest thing on the bar */
  .adminnav{grid-template-columns:auto auto 1fr auto}
  .adminnav .brand{grid-area:1 / 1; justify-self:start}
  .adminnav .tag{grid-area:1 / 2; justify-self:start}
  .adminnav .links{grid-area:1 / 3; justify-self:start}
  .adminnav .right{grid-area:1 / 4; justify-self:end}

  /* The links become a sheet under the bar. Not display:none -- that left a
     phone with no navigation at all. */
  /* grid-area and justify-self both have to be undone, or left:0 and right:0
     do nothing. The bar is a grid: an absolutely positioned grid item is
     contained by its own grid area rather than the bar, and justify-self:start
     then gives it a shrink-to-fit width inside that. The sheet came out as a
     strip over the right-hand third of the screen. */
  .sitenav .links{position:absolute; top:100%; left:0; right:0; display:none;
    grid-area:auto; justify-self:stretch;
    flex-direction:column; gap:0; background:var(--site);
    border-bottom:1px solid var(--rule); box-shadow:0 14px 24px rgba(24,23,33,.10); z-index:60}
  .sitenav.open .links{display:flex}

  /* The admin bar gets the same burger as the shop's. It had none, so the rule
     above hid its links with nothing to open them -- a phone got whichever page
     was already on screen and no way to any other.

     The sheet needs dressing for a dark bar: the burger's three bars are drawn
     in ink, which is the colour of the bar itself, and the sheet and its
     separators are built for the light one. */
  .adminnav{grid-template-columns:auto auto 1fr auto}
  .adminnav .navburger{display:flex; grid-area:1 / 1; justify-self:start}
  .adminnav .navburger span{background:#fff}
  .adminnav .navburger:hover{background:rgba(255,255,255,.10)}
  .adminnav .brand{grid-area:1 / 2; justify-self:start}
  .adminnav .tag{grid-area:1 / 3; justify-self:start}
  .adminnav .right{grid-area:1 / 4; justify-self:end}
  .adminnav .links{background:var(--ink); border-bottom-color:#2E2C3B}
  .sitenav.adminnav .links a{border-top:1px solid #2E2C3B}

  .sitenav .links a{padding:13px 22px; font-size:16px; border-top:1px solid var(--rule)}
  .sitenav .links a:first-child{border-top:0}
  .sitenav .links .tolab.inmenu{display:block; background:none; color:var(--ink2); border-radius:0; font-weight:600}
}

/* Narrower than this, a 40px burger on one side and the account group on the
   other are too different in width for the bar to hold a truly centred mark as
   well. Centre it on what is left between them instead. */
@media (max-width:560px){
  .sitenav{grid-template-columns:auto 1fr auto}
}

@media (max-width:900px){
  /* max() keeps the gutter clear of a foldable's rounded corners and any
     notch the browser reports, without shrinking it on ordinary phones. */
  .container{padding:0 max(20px, env(safe-area-inset-left)) 0 max(20px, env(safe-area-inset-right))}
  .sitenav{padding:10px max(10px, env(safe-area-inset-left))}
  .sitenav .right .acct{display:none}      /* the basket is what people reach for */
  .sitenav .links a{padding:13px max(20px, env(safe-area-inset-left))}
  .grid3,.grid4{grid-template-columns:1fr 1fr}
  /* minmax(0,…) so the single column may shrink below its contents. A bare 1fr
     is minmax(auto,1fr) and floors at the widest child, which put the checkout
     card 53px past the right edge of a folded phone. */
  .split{grid-template-columns:minmax(0,1fr)}
  .sticky{position:static}
  .split.basket{grid-template-areas:"lines" "aside" "offers"; grid-template-rows:auto}
  .split.basket>aside{margin-top:18px}
  .brand img{height:36px}
  .sitefoot .brand img{height:38px}
  .sitefoot .cols{grid-template-columns:1fr 1fr}
  .section{padding:44px 0}
  .steps{flex-wrap:wrap; gap:14px}
  .step{flex:1 1 40%}
  .step::after{display:none}
  .mockbar{left:8px; bottom:8px; font-size:12px}
}
@media (max-width:560px){
  /* Buttons are nowrap by design, but a label like "Design your golf ball
     stencil" is simply wider than a folded phone. Let those few wrap rather
     than push the page sideways. */
  .btn{white-space:normal; text-align:center}
  .grid2,.grid3,.grid4{grid-template-columns:1fr}
  .sitefoot .cols{grid-template-columns:1fr}
  /* Three ticks laid out as a wrapping row put two on one line and one on the
     next, which reads as an accident. One a line, evenly spaced, scans. */
  .hero .facts{flex-direction:column; gap:10px}
}
@media (prefers-reduced-motion:reduce){ *{animation:none !important; transition:none !important} }

/* ---------- flash messages ---------- */
.flashwrap{max-width:1180px; margin:14px auto 0; padding:0 30px}
.flash{border-radius:12px; padding:12px 16px; font-size:14.5px; font-weight:600; transition:opacity .6s}
.flash.ok{background:var(--ok-bg); color:var(--ok-fg)}
.flash.warn{background:var(--warn-bg); color:var(--warn-fg)}
.flash.bad{background:var(--bad-bg); color:var(--bad-fg)}
.flash.gone{opacity:0}
.field .err{margin-top:2px}
.designer-frame{width:100%; height:clamp(560px,76vh,700px); border:1px solid var(--rule); border-radius:20px; background:var(--bg); display:block}
/* 1180px was taller than a phone screen, so the designer had to be scrolled
   through inside a page that also scrolled. It now fits the screen and behaves
   as one pane: canvas on top, tools in the sheet beneath.

   It also breaks out of the container's gutters. The drawing area is the whole
   point of the page and 40px of side padding is a tenth of a phone's width;
   edge to edge, the ball is meaningfully bigger. */
@media (max-width:900px){
  .designer-frame{
    /* Reclaim 36px straight into the designer. The sliver that is left keeps a
       bit of the page visible above and below, so it never reads as a screen
       you are trapped inside. */
    height:calc(100dvh - 44px); min-height:600px;
    /* Cancel the container's gutters exactly, rather than reaching for 100vw:
       100vw counts the scrollbar, so it came out wider than the page and put
       the whole thing into horizontal scroll. */
    --gut: max(20px, env(safe-area-inset-left));
    margin-left:calc(-1 * var(--gut)); margin-right:calc(-1 * var(--gut));
    width:calc(100% + 2 * var(--gut));
    border-left:0; border-right:0; border-radius:0;
  }
  .flashwrap{padding:0 18px}
}


/* ======================================================================
   Page styles (moved out of the mockups so pages carry no inline CSS)
   ====================================================================== */

/* ---- home ---- */
/* padding-block, not the padding shorthand: .hero is also a .container, and the
   shorthand reset its side gutters to 0, which put the headline hard against
   the edge of the screen on a phone. */
.hero{display:grid; grid-template-columns:minmax(0,1.05fr) minmax(0,.95fr); gap:40px; align-items:center; padding-top:56px; padding-bottom:40px}
.hero h1{max-width:17ch}
.hero .dek{margin:22px 0 30px; font-size:18.5px; color:var(--ink2); max-width:46ch}
.hero .ctas{display:flex; gap:12px; flex-wrap:wrap; align-items:center}
.facts{display:flex; gap:22px; flex-wrap:wrap; margin-top:34px; font-size:14px; color:var(--ink2); font-weight:500}
.facts span{display:flex; align-items:center; gap:7px}
.facts svg{color:var(--green)}
.heroball{position:relative; max-width:460px; margin:0 auto; width:100%}
.heroball .ball{filter:drop-shadow(0 26px 30px rgba(24,23,33,.14))}
.heroball .draw{stroke-dasharray:56; stroke-dashoffset:56; animation:draw .9s .35s cubic-bezier(.6,0,.3,1) forwards}
.heroball .late{opacity:0; animation:fade .5s 1.15s forwards}
.heroball .later{opacity:0; animation:fade .5s 1.5s forwards}
@keyframes draw{to{stroke-dashoffset:0}}
@keyframes fade{to{opacity:1}}
.pentag{position:absolute; right:-6px; bottom:38px; background:var(--paper); border:1px solid var(--rule); border-radius:12px; padding:10px 13px;
        font-size:13px; font-weight:600; box-shadow:0 8px 22px rgba(24,23,33,.10); display:flex; align-items:center; gap:9px; opacity:0; animation:fade .5s 1.8s forwards}
.pentag .dots{display:flex; gap:5px}
.pentag .dots .pen{width:14px; height:14px; border-radius:50%; display:block; border:0; padding:0; cursor:pointer;
        box-shadow:0 0 0 1px var(--rule); transition:transform .15s, box-shadow .15s}
.pentag .dots .pen:hover{transform:scale(1.15)}
.pentag .dots .pen.on{box-shadow:0 0 0 2px var(--paper), 0 0 0 4px var(--live)}
.pentag .dots .pen:focus-visible{outline:2px solid var(--live); outline-offset:3px}
.how{display:grid; grid-template-columns:repeat(3,1fr); gap:20px}
.how .card{padding:0; overflow:hidden}
.how .pic{background:var(--bg); height:190px; display:grid; place-items:center; padding:20px}
.how .txt{padding:20px 22px 24px}
.how .n{width:30px; height:30px; border-radius:9px; background:var(--live-soft); color:var(--live); display:grid; place-items:center; font-weight:800; font-size:14px; margin-bottom:12px; font-family:var(--disp)}
.how p{color:var(--ink2); font-size:14.5px; margin-top:6px}
/* how-it-works, live: the same three things the customer actually meets — the
   designer's own flat view, the real marker mesh coming out of the printer, and
   the real ball being marked. howitworks.js builds them and adds .ready; until
   then (and for good, if WebGL or the server is unavailable) the flat drawing
   in the page stands. */
.how .pic{position:relative; overflow:hidden}
.how .pic canvas.hw-live,.versus .vpic canvas.hw-live{width:100%; height:100%; display:block}
.how .pic svg.hw-live{width:100%; height:100%; display:block}
.how .pic .hw-live,.versus .vpic .hw-live{position:absolute; inset:0; opacity:0; transition:opacity .4s}
.how .pic.ready .hw-live,.versus .vpic.ready .hw-live{opacity:1}
/* .enhancing goes on the moment the script commits to building, so the flat
   drawing is never shown and then replaced; it comes back only if that panel
   cannot be built. */
.how .pic.enhancing .hw-fall,.versus .vpic.enhancing .hw-fall{opacity:0; transition:opacity .2s}
.how .pic .hw-chip{position:absolute; right:12px; bottom:11px; display:flex; align-items:center; gap:5px; opacity:0;
                   background:var(--ok-bg); color:var(--ok-fg); border-radius:99px; padding:3px 10px 3px 8px;
                   font-size:11.5px; font-weight:700; letter-spacing:.01em}
.versus{display:grid; grid-template-columns:1fr 1fr; gap:24px; max-width:840px; margin:0 auto}
.versus .card{text-align:center; padding:28px 28px 24px}
.versus .ball{max-width:220px; margin:0 auto 18px}
.versus .vpic{position:relative; width:min(220px,100%); aspect-ratio:1; margin:0 auto 18px}
.versus .vpic .ball{margin:0}
.versus h3{font-size:20px}
.versus p{color:var(--ink2); font-size:14.5px; margin-top:6px}
.versus .bad h3{color:var(--grey)}
.prod{padding:0; overflow:hidden; display:flex; flex-direction:column; text-decoration:none; color:inherit}
.prod .pic{background:var(--bg); padding:26px 40px}
.prod .pic.photo{padding:0}
.prod .pic.photo img{display:block; width:100%; aspect-ratio:1; object-fit:cover}
/* the ready-made product-page gallery: a big picture the thumbnails switch,
   no JavaScript -- the thumbnails are labels for hidden radios. */
.gallery{width:100%}
.gallery .gmain{width:100%; aspect-ratio:1; background:var(--paper); border-radius:16px; overflow:hidden; display:grid; place-items:center}
.gallery .gmain .gm{display:none}
.gallery .gmain img.gm{width:100%; height:100%; object-fit:contain}
.gallery .gsel{position:absolute; width:1px; height:1px; opacity:0; pointer-events:none}
.gallery .gthumbs{display:flex; gap:10px; margin-top:14px; flex-wrap:wrap}
.gallery .gth{width:66px; height:66px; border-radius:12px; overflow:hidden; border:2px solid transparent; cursor:pointer; background:var(--paper); box-shadow:0 0 0 1px var(--rule)}
.gallery .gth img{width:100%; height:100%; object-fit:cover; display:block}
.gallery .gth-3d{display:grid; place-items:center; background:var(--bg)}
.gallery .gth-3d .td{font-family:var(--disp); font-weight:800; font-size:15px; letter-spacing:-.02em; color:var(--ink2)}
.rmdetail .stage.photos{padding:20px}
/* the interactive 3-D view: canvas over a drawn-ball poster that shows until
   WebGL is ready (and stays if it never is). */
.rmball{position:relative; width:100%; aspect-ratio:1}
.rmball canvas{position:absolute; inset:0; width:100%; height:100%; opacity:0; transition:opacity .35s; touch-action:none}
.rmball.ready canvas{opacity:1}
.rmball .rmposter{position:absolute; inset:0; display:grid; place-items:center; padding:20px; transition:opacity .35s}
.rmball .rmposter .ball{width:100%; max-width:440px}
.rmball.ready .rmposter{opacity:0; pointer-events:none}
.rmball .spinhint{position:absolute; left:0; right:0; bottom:6px; text-align:center; font-size:12.5px; color:var(--grey); font-weight:600; opacity:0; pointer-events:none; transition:opacity .35s}
.rmball.ready .spinhint{opacity:1}
.prod .txt{padding:16px 18px 18px; display:flex; flex-direction:column; gap:4px; flex:1}
.prod .name{font-weight:700; font-size:16px}
.prod .foot{display:flex; align-items:center; justify-content:space-between; margin-top:auto; padding-top:12px}
.prod .price{font-size:19px}
.strip{display:grid; grid-template-columns:repeat(4,1fr); gap:20px}
.strip b{display:block; font-family:var(--disp); font-size:26px; letter-spacing:-.03em; font-weight:800}
.strip span{font-size:14px; color:var(--ink2)}

/* ---- product (design your own) ---- */
.prodhead{display:flex; align-items:flex-end; justify-content:space-between; gap:26px; padding:14px 0 22px; flex-wrap:wrap}
.prodhead h1{font-size:clamp(30px,4.2vw,42px)}
.prodhead p{margin-top:8px; color:var(--ink2); max-width:54ch}
.prodmeta{text-align:right}
.prodmeta .price{font-size:32px}
.prodmeta .s{font-size:13.5px; color:var(--grey); font-weight:600}
.addons{display:grid; grid-template-columns:minmax(0,1fr) 380px; gap:24px; margin-top:26px; align-items:start}
.penrow{display:flex; gap:8px}
.penrow label{position:relative; width:30px; height:30px; flex:0 0 30px; border-radius:50%; border:3px solid var(--paper); box-shadow:0 0 0 1px var(--rule); cursor:pointer}
.penrow label input{position:absolute; inset:0; opacity:0; cursor:pointer}
.penrow label:has(input:checked){box-shadow:0 0 0 3px var(--live)}
.penrow label:focus-within{outline:3px solid var(--live); outline-offset:2px}
.whatyouget{display:grid; grid-template-columns:repeat(3,1fr); gap:18px}
.whatyouget .card{padding:20px}
.whatyouget h3{font-size:16.5px; margin-bottom:6px}
.whatyouget p{font-size:14px; color:var(--ink2)}
.designer-note{margin-top:10px; font-size:13px; color:var(--grey)}

/* ---- ready-made ---- */
.rmhead{padding:26px 0 22px; max-width:62ch}
.rmhead h1{font-size:clamp(30px,4.2vw,42px); margin-bottom:8px}
.rmhead p{color:var(--ink2)}
.rmdetail{display:grid; grid-template-columns:minmax(0,620px) minmax(300px,420px); gap:44px; justify-content:center; align-items:start; padding:20px 0 40px}
.rmdetail .stage{background:var(--bg); border-radius:20px; padding:40px; display:grid; place-items:center}
.rmdetail .stage .ball{max-width:280px}
.rmdetail h1{font-size:clamp(28px,4vw,40px)}
.rmdetail .blurb{margin:8px 0 18px; color:var(--ink2); font-size:17px}
.rmdetail .price{font-size:30px}
.penpick{display:flex; gap:10px; margin:8px 0 18px}
.penpick label{position:relative; width:36px; height:36px; border-radius:50%; border:3px solid var(--paper); box-shadow:0 0 0 1px var(--rule); cursor:pointer}
.penpick label input{position:absolute; inset:0; opacity:0; cursor:pointer}
.penpick label:has(input:checked){box-shadow:0 0 0 3px var(--live)}
.penpick label:focus-within{outline:3px solid var(--live); outline-offset:2px}
.rmdetail ul{margin:18px 0 0; padding-left:20px; color:var(--ink2); font-size:14.5px; line-height:1.7}

/* ---- basket ---- */
.pagehead{padding:26px 0 22px; display:flex; align-items:flex-end; justify-content:space-between; gap:20px; flex-wrap:wrap}
.pagehead h1{font-size:clamp(30px,4.2vw,42px)}
.pagehead .small{margin-bottom:6px}
.lines .item{display:flex; gap:18px; align-items:flex-start; padding:20px 0; border-bottom:1px solid var(--rule)}
.lines .item:first-child{padding-top:0}
.lines .item:last-child{border-bottom:0; padding-bottom:0}
.item .pic{width:84px; height:84px; flex:0 0 84px; background:var(--bg); border-radius:12px; display:grid; place-items:center; padding:8px}
.item .pic .ball{width:68px; height:68px}
.item .body{flex:1; min-width:0}
.item .name{font-weight:700; font-size:16.5px}
.item .desc{font-size:14px; color:var(--ink2); margin-top:3px}
.item .acts{display:flex; gap:16px; margin-top:12px; font-size:13.5px; align-items:center}
.item .acts a,.item .acts button{color:var(--ink2); text-decoration:none; font-weight:600; background:none; border:0; padding:0; font:inherit; font-size:13.5px; cursor:pointer}
.item .acts a:hover,.item .acts button:hover{color:var(--ink)}
.item .acts .edit{color:var(--ink)}
.item .acts .rm:hover{color:var(--red)}
.item .end{display:flex; flex-direction:column; align-items:flex-end; gap:12px; flex:0 0 auto}
.item .price{font-size:18px}
.qty{display:inline-flex; align-items:center; border:1.5px solid var(--rule); border-radius:99px; overflow:hidden}
.qty button{width:32px; height:32px; display:grid; place-items:center; font-weight:700; color:var(--ink2); cursor:pointer; background:none; border:0; font:inherit; font-size:16px}
.qty button:hover{color:var(--live); background:var(--bg)}
.qty input{width:34px; border:0; text-align:center; font-size:14.5px; font-weight:700; padding:0; background:transparent; font-variant-numeric:tabular-nums}
.qty input:focus{box-shadow:none}
.penpic{width:68px; height:68px}
.friend{display:flex; align-items:center; gap:16px; margin-top:18px}
.friend .mini{display:flex; gap:6px}
.friend .mini .ball{width:38px; height:38px}
.friend .t{font-weight:700}
.friend .s{font-size:13.5px; color:var(--ink2)}
.friend .btn{margin-left:auto}
.friend form{margin-left:auto; display:flex; gap:8px; align-items:center}
/* The second-stencil offer. The price is what is being sold, so it sits on the
   right like a ticket, and the three ways to take it get a row of their own --
   side by side with the copy they are too wide to fit. */
.panel.sell{background:var(--live-soft); margin-top:18px}
.panel.sell .top{display:flex; align-items:center; gap:16px}
.panel.sell .mini{display:flex; gap:6px}
.panel.sell .mini .ball{width:38px; height:38px}
.panel.sell .t{font-weight:700}
.panel.sell .s{font-size:13.5px; color:var(--ink2)}
.panel.sell .tag{margin-left:auto; text-align:right; line-height:1.15}
.panel.sell .tag b{display:block; font-family:var(--disp); font-weight:800; font-size:26px; letter-spacing:-.035em}
.panel.sell .tag span{font-size:12.5px; color:var(--grey); font-weight:600; text-decoration:line-through}
.panel.sell .acts{display:flex; gap:8px; align-items:center; flex-wrap:wrap; margin-top:14px;
                  padding-top:14px; border-top:1px solid rgba(39,87,214,.14)}
.item .end .saved{font-size:12.5px; font-weight:600; color:var(--green)}
.total-row.saved{color:var(--green); font-weight:600}
/* The VAT line hangs off the total rather than adding to it, so it is set
   quiet and tight underneath instead of reading as another charge. */
.total-row.vatline{font-size:12.5px; color:var(--grey); padding:2px 0 0}
.offer{background:var(--live-soft); border-radius:10px; padding:13px 14px; margin:12px 0 2px}
.offer .t{font-family:var(--disp); font-weight:800; font-size:17px; letter-spacing:-.025em}
.offer .s{font-size:13px; color:var(--ink2); margin:2px 0 10px}
.offer .or{display:block; text-align:center; font-size:13px; font-weight:600; margin-top:8px}
.summary .total-row.big{font-size:21px}
.freehint{display:flex; align-items:center; gap:9px; background:var(--live-soft); color:#1C3E9C; border-radius:10px; padding:10px 12px; font-size:13.5px; font-weight:600; margin:12px 0 2px}
.freehint .bar{flex:1; height:6px; background:#fff; border-radius:99px; overflow:hidden}
.freehint .bar i{display:block; height:100%; background:var(--live); border-radius:99px}
.paywith{display:flex; align-items:center; gap:8px; margin-top:14px; font-size:12.5px; color:var(--grey); flex-wrap:wrap}
.cardmarks{display:inline-flex; gap:4px}
.cardmarks i{display:block; width:26px; height:17px; border-radius:4px; border:1px solid var(--rule); background:#fff; position:relative}
.cardmarks i.visa{background:#1A1F71}
.cardmarks i.mc::before,.cardmarks i.mc::after{content:""; position:absolute; top:3px; width:10px; height:10px; border-radius:50%}
.cardmarks i.mc::before{left:4px; background:#EB001B}
.cardmarks i.mc::after{left:10px; background:#F79E1B; opacity:.9}
.cardmarks i.amex{background:#2E77BC}
.cardmarks i.apple{background:#181721}
.cardmarks i.gpay::before{content:"G"; position:absolute; inset:0; display:grid; place-items:center; font-size:11px; font-weight:700; color:#4285F4; font-family:var(--body)}
.cont{display:block; text-align:center; margin-top:14px; font-size:14px; color:var(--ink2); text-decoration:none; font-weight:600}
.cont:hover{color:var(--ink)}
.emptybasket{text-align:center; padding:60px 20px}
.emptybasket .ball{max-width:140px; margin:0 auto 20px; opacity:.8}

/* ---- guides index ---- */
.ghead{padding:44px 0 30px; max-width:62ch}
.ghead h1{font-size:clamp(32px,4.4vw,46px); margin:8px 0 12px}
.ghead p{color:var(--ink2); font-size:17.5px}
.gcards{display:grid; grid-template-columns:repeat(3,1fr); gap:18px}
a.g{display:flex; flex-direction:column; background:var(--paper); border:1px solid var(--rule); border-radius:var(--r); overflow:hidden; text-decoration:none; color:inherit; transition:transform .12s, box-shadow .12s}
a.g:hover{transform:translateY(-2px); box-shadow:0 8px 22px rgba(24,23,33,.08)}
a.g .pic{background:var(--bg); padding:22px; display:grid; place-items:center; height:170px}
a.g .pic .ball{max-width:118px}
a.g .pic .balls{display:flex; gap:10px}
a.g .pic .balls .ball{max-width:86px}
a.g .txt{padding:16px 18px 18px; display:flex; flex-direction:column; gap:6px; flex:1}
a.g .cat{font-size:11.5px; font-weight:700; letter-spacing:.14em; text-transform:uppercase; color:var(--live)}
a.g h2{font-size:19px; letter-spacing:-.02em}
a.g p{font-size:14.5px; color:var(--ink2)}
a.g .rt{margin-top:auto; padding-top:10px; font-size:13px; color:var(--grey); font-weight:600}
.next{margin-top:44px}
.next ul{margin:10px 0 0; padding-left:20px; color:var(--ink2); line-height:1.8}

/* ---- plain document pages (help, about, delivery, privacy, terms, contact, gift) ---- */
.docpage{padding:44px 0 60px}
.docpage h1{font-size:clamp(30px,4.2vw,42px); margin:8px 0 12px}
.docpage .lede{font-size:17.5px; color:var(--ink2); max-width:62ch}
.docpage h2{font-size:23px; margin:40px 0 10px}
.docpage h3{font-size:17px; margin:22px 0 6px}
.docpage p{margin:8px 0; color:var(--ink2); max-width:70ch; line-height:1.65}
.docpage p b,.docpage li b{color:var(--ink)}
.docpage ul,.docpage ol{margin:8px 0; padding-left:22px; color:var(--ink2); line-height:1.7; max-width:70ch}
.docpage .card{margin:18px 0}
.docpage .photo{aspect-ratio:16/9; border:1.5px dashed #C9C7D4; border-radius:12px; display:grid; place-items:center; color:var(--grey); font-size:13.5px; font-weight:600; padding:20px; background:var(--paper); margin:18px 0}
.docpage table{width:100%; border-collapse:collapse; font-size:14.5px; margin:12px 0}
.docpage td,.docpage th{padding:10px 12px; border-bottom:1px solid var(--rule); text-align:left; vertical-align:top}
.docpage th{font-size:11.5px; letter-spacing:.1em; text-transform:uppercase; color:var(--grey)}
.docpage .updated{font-size:13px; color:var(--grey); margin-top:30px}

@media (max-width:900px){
  /* gap:0 matters more than it looks. display:contents below lifts the copy
     out of its <div> and into this grid, so the desktop 40px gap starts
     landing between every single line of the hero -- on top of the margins
     each of them already carries. That is where the holes came from. The gap
     goes; each element sets its own space. */
  .hero{grid-template-columns:minmax(0,1fr); gap:0; padding-top:18px; padding-bottom:26px}

  /* On a phone the headline reads first, then the ball, then the sell. The
     text is one <div> on desktop, so display:contents lifts its children into
     the hero grid and lets them be ordered around the ball individually. Only
     inside this query — desktop keeps the two-column layout untouched. */
  .hero > div:first-child{display:contents}
  .hero .eyebrow{order:1}
  .hero h1{order:2; max-width:none}
  .heroball{order:3; margin:10px auto 16px; max-width:340px}
  .hero .dek{order:4; margin:0 0 20px}
  .hero .ctas{order:5; gap:10px}
  .hero .ctarider{order:6; margin-top:15px}
  .hero .facts{order:7; margin-top:17px; gap:11px 18px}

  /* The price block is right-aligned so it sits opposite the heading on a wide
     screen. On a phone it wraps underneath instead, and a right-aligned column
     under left-aligned text just looks like a mistake. It is also saying the
     price a second time — "Add to basket · £12.99" is right there in the
     designer — so on a phone it goes entirely. */
  .prodhead{gap:10px; padding-bottom:16px}
  .prodmeta{display:none}
  /* The tag deliberately overhangs the ball by 6px on desktop. On a folded
     phone that 6px is past the viewport and the whole page scrolls sideways. */
  .pentag{right:0}
  .how,.versus{grid-template-columns:1fr}
  .strip{grid-template-columns:1fr 1fr}
  .addons,.rmdetail{grid-template-columns:minmax(0,1fr)}
  .whatyouget{grid-template-columns:minmax(0,1fr)}
  .gcards{grid-template-columns:1fr 1fr}
}
@media (max-width:600px){
  .item{flex-wrap:wrap}
  .item .end{flex-direction:row; width:100%; justify-content:space-between; align-items:center}
  .friend{flex-wrap:wrap}
  .friend .btn,.friend form{margin-left:0}
  .gcards{grid-template-columns:1fr}
  .strip{grid-template-columns:1fr}
}

/* ---------- checkout ---------- */
.sitenav.quiet{gap:12px}
.sitenav.quiet .right{margin-left:auto}
.lockline{display:inline-flex; align-items:center; gap:6px; color:var(--ink2); font-weight:600; font-size:14px}
.lockline svg{color:var(--green)}
.chk-head{padding:26px 0 22px}
.chk-head h1{font-size:clamp(30px,4.2vw,42px)}
.chk-head p{color:var(--ink2); margin-top:6px}
.chk-sec{margin-bottom:18px}
.chk-sec .head{display:flex; align-items:center; gap:12px; margin-bottom:18px}
.chk-sec .n{width:30px; height:30px; border-radius:9px; background:var(--live-soft); color:var(--live); display:grid; place-items:center; font-weight:800; font-size:14px; font-family:var(--disp); flex:0 0 30px}
.chk-sec h3{font-size:19px}
.chk-sec .head .edit{margin-left:auto; font-size:13.5px; color:var(--grey)}
.chk-sec .opt{font-weight:500; letter-spacing:0; text-transform:none}
.chk-sec .checks{display:flex; flex-direction:column; gap:10px; margin-top:16px}
.chk-sec .checks .help{font-size:13px; color:var(--grey); margin-left:28px; margin-top:-4px}
.chk-sec .choices{display:flex; flex-direction:column; gap:10px}
.chk-sec input[aria-invalid="true"]{border-color:var(--red)}
.chk-pay{border:1px solid var(--rule); border-radius:12px; padding:16px 18px; background:var(--paper); color:var(--ink2); font-size:14.5px; line-height:1.55}
.chk-pay b{color:var(--ink)}
.cardmarks{display:flex; gap:8px; margin-top:12px; align-items:center}
.cm{display:inline-grid; place-items:center; height:24px; min-width:38px; padding:0 6px; border-radius:4px; font-size:10px; font-weight:800; letter-spacing:.02em; font-family:var(--body)}
.cm.visa{background:#1A1F71; color:#fff; font-style:italic}
.cm.mc{background:#151515; position:relative}
.cm.mc i{width:12px; height:12px; border-radius:50%; display:inline-block; background:#EB001B; margin-right:-4px}
.cm.mc i+i{background:#F79E1B; opacity:.9; margin-right:0}
.cm.amex{background:#2E77BC; color:#fff}
.cm.apple{background:#000; color:#fff}
.cm.gpay{background:#fff; color:#3C4043; border:1px solid var(--rule)}
.chk-paybtn{margin-top:20px}
.payline{font-size:13px; color:var(--grey); margin-top:12px; text-align:center; line-height:1.5}
.payline a{color:var(--grey)}
.chk-sum .item{display:flex; gap:12px; align-items:center; padding:10px 0; border-bottom:1px solid var(--rule)}
.chk-sum .item:last-of-type{border-bottom:0}
.chk-sum .pic{width:56px; height:56px; flex:0 0 56px; background:var(--bg); border-radius:10px; display:grid; place-items:center; padding:5px}
.chk-sum .pic .ball{width:46px; height:46px}
.chk-sum .name{font-weight:700; font-size:14.5px}
.chk-sum .desc{font-size:12.5px; color:var(--grey)}
.chk-sum .p{margin-left:auto; font-weight:700; font-size:14.5px}
.chk-sum .total-row.big{font-size:20px}
/* A way out of the checkout that can actually be seen and hit -- it was a
   grey link tucked on the end of the VAT sentence, invisible on a phone. */
.chk-sum .backbasket{display:flex; margin-top:12px}
.penpic{width:44px; height:44px; display:block}

/* ---------- order confirmed ---------- */
.cfm-thanks{text-align:center; padding:40px 0 26px}
.cfm-thanks .tick{width:64px; height:64px; border-radius:50%; background:var(--ok-bg); color:var(--ok-fg); display:grid; place-items:center; margin:0 auto 18px}
.cfm-thanks .tick.wait{background:var(--warn-bg); color:var(--warn-fg)}
.cfm-thanks .tick svg{width:30px; height:30px}
.cfm-thanks h1{font-size:clamp(28px,4vw,40px)}
.cfm-thanks p{color:var(--ink2); margin-top:10px}
.cfm-thanks .ref{font-weight:700; color:var(--ink)}
.cfm-item{display:flex; gap:14px; align-items:center; padding:12px 0; border-bottom:1px solid var(--rule)}
.cfm-item .pic{width:56px; height:56px; flex:0 0 56px; background:var(--bg); border-radius:10px; display:grid; place-items:center; padding:5px}
.cfm-item .pic .ball{width:46px; height:46px}
.cfm-item .name{font-weight:700}
.cfm-item .desc{font-size:13px; color:var(--grey)}
.cfm-item .p{margin-left:auto; font-weight:700}
.cfm-totals{margin-top:10px}
.cfm-addr{margin-top:16px; padding-top:14px; border-top:1px solid var(--rule)}
.cfm-actions{display:flex; gap:12px; justify-content:center; margin:26px 0 10px; flex-wrap:wrap}
.cfm-after{text-align:center}

/* ---------- sign in / register (account) ---------- */
.authwrap{max-width:900px; margin:0 auto; padding:56px 30px 40px}
.authwrap h1{font-size:clamp(30px,4vw,42px); margin-bottom:8px}
.authwrap .lead{color:var(--ink2); margin-bottom:32px}
.auth{display:grid; grid-template-columns:1fr 1fr; gap:22px; align-items:start}
.auth .card{padding:30px}
.auth .card.new{background:var(--bg); border-color:transparent; box-shadow:none}
.auth h2{font-size:24px; margin-bottom:6px}
.auth .sub{color:var(--ink2); font-size:14.5px; margin-bottom:22px}
.auth .btn.wide{margin-top:20px}
.forgot{display:flex; justify-content:flex-end; margin-top:8px}
.forgot a{font-size:13.5px; color:var(--ink2)}
.perks{list-style:none; margin:0 0 22px; padding:0; display:flex; flex-direction:column; gap:9px}
.perks li{display:flex; align-items:center; gap:10px; font-size:14.5px; color:var(--ink2)}
.perks svg{color:var(--green); flex:0 0 auto}
.guest{margin-top:26px; text-align:center}
.guest a{color:var(--ink2)}
.linkish{background:none; border:0; padding:0; font:inherit; color:inherit; cursor:pointer; text-decoration:underline; text-underline-offset:3px}
form.inline{display:inline}
.adminnav .right form.inline{color:#C9C8D3; font-size:14.5px; font-weight:600}
.adminnav .right .linkish{color:#C9C8D3}
.adminnav .right .linkish:hover{color:#fff}
@media (max-width:760px){ .auth{grid-template-columns:1fr} .authwrap{padding:34px 18px 30px} }

/* ---------- account page ---------- */
.acchead{padding:34px 0 26px}
.acchead h1{font-size:clamp(30px,4vw,42px)}
.acchead p{color:var(--ink2); margin-top:8px}
.acc{display:grid; grid-template-columns:220px minmax(0,1fr); gap:32px; align-items:start}
.sidenav{padding:10px; position:sticky; top:22px}
.sidenav a,.sidenav .sidebtn{display:flex; align-items:center; gap:10px; padding:10px 12px; border-radius:10px; color:var(--ink2); text-decoration:none; font-weight:600; font-size:14.5px; width:100%; text-align:left}
.sidenav a:hover,.sidenav .sidebtn:hover{background:var(--bg); color:var(--ink)}
.sidenav hr{border:0; border-top:1px solid var(--rule); margin:8px 6px}
.acc section{margin-bottom:40px}
.acc section h2{font-size:22px; margin-bottom:16px}
.orderrow{display:flex; align-items:center; gap:18px; padding:18px 22px}
.orderrow+.orderrow{margin-top:12px}
.orderrow .who{flex:1; min-width:0}
.orderrow .id{font-weight:700; font-size:15.5px}
.orderrow .id span{color:var(--grey); font-weight:500; font-size:13.5px; margin-left:8px}
.orderrow .desc{color:var(--ink2); font-size:14px; margin-top:2px}
.orderrow .tot{font-weight:700; min-width:64px; text-align:right}
.designs{display:grid; grid-template-columns:1fr 1fr; gap:18px}
.design{display:flex; gap:18px; align-items:center; padding:20px}
.design .name{font-weight:700; font-size:15.5px}
.design .pen{font-size:13.5px; color:var(--grey); margin:2px 0 12px}
.design .row{gap:8px}
.details .kv{margin-bottom:0}
@media (max-width:900px){
  /* minmax(0,1fr), not 1fr: a bare 1fr floors at the content's own width, and
     the sidenav links are width:100% flex items whose max-content contribution
     came out at 453px — inside a 289px screen. The desktop rule above already
     spells it minmax(0,1fr) for the same reason. */
  .acc{grid-template-columns:minmax(0,1fr)}
  .sidenav{position:static; display:flex; flex-wrap:wrap; gap:4px; min-width:0}
  .sidenav hr{display:none}
  .designs{grid-template-columns:minmax(0,1fr)}
  /* The card is a thumbnail beside a text column. The column has to be allowed
     to shrink or it keeps its full width and hangs off the side of the card. */
  .design{flex-wrap:wrap; min-width:0}
  .design > *{min-width:0; max-width:100%}
  .orderrow{flex-wrap:wrap}
}

/* ---------- one order (customer + admin) ---------- */
.ordhead{display:flex; align-items:flex-start; justify-content:space-between; gap:20px; padding:14px 0 24px; flex-wrap:wrap}
.ordhead h1{font-size:clamp(28px,3.8vw,40px); display:flex; align-items:center; gap:14px; flex-wrap:wrap}
.ordhead h1 .st{font-size:13px}
.ordhead .small{margin-top:8px; font-weight:500}
.ordhead .actions{display:flex; gap:10px; flex-wrap:wrap; align-items:center}
.progress{margin-bottom:28px}
.progress .note{margin-top:18px; color:var(--ink2); font-size:14.5px; display:flex; gap:9px; align-items:center; flex-wrap:wrap}
.progress .note svg{color:var(--live); flex:0 0 auto}
.item{display:flex; gap:16px; align-items:center; padding:14px 0; border-bottom:1px solid var(--rule)}
.item:first-of-type{padding-top:0}
.item .who{flex:1; min-width:0}
.item .name{font-weight:700}
.item .desc{color:var(--ink2); font-size:14px; margin-top:2px}
.item .qty{color:var(--grey); font-size:13.5px; min-width:28px; text-align:center}
.item .p{font-weight:700; min-width:64px; text-align:right}
.totals{margin-top:12px}
.side .card+.card{margin-top:16px}
.side h3{margin-bottom:12px}
.side address{font-style:normal; line-height:1.5}
.side .kv{grid-template-columns:78px 1fr}
.again{margin-top:32px; display:flex; align-items:center; gap:16px; flex-wrap:wrap}
.again .small{max-width:44ch}
@media (max-width:900px){ .item{flex-wrap:wrap} }

/* ---------- admin ---------- */
body.admin{background:var(--bg)}
.admin .pagehead{display:flex; align-items:center; gap:18px; flex-wrap:wrap; padding:30px 0 20px}
.admin .pagehead h1{font-size:clamp(28px,3.6vw,38px)}
.admin .pagehead .search{flex:1; min-width:240px; max-width:420px; position:relative}
.admin .pagehead .search svg{position:absolute; left:13px; top:50%; transform:translateY(-50%); color:var(--grey)}
.admin .pagehead .search input{padding-left:38px; background:var(--paper)}
.admin .pagehead .dl{margin-left:auto; display:flex; align-items:center; gap:12px}
.tiles{display:grid; grid-template-columns:repeat(4,1fr); gap:14px; margin-bottom:22px}
.tile{display:block; text-decoration:none; color:inherit; padding:16px 18px}
.tile:hover{border-color:#C9C7D4}
.tile .lab{font-size:12.5px; font-weight:700; letter-spacing:.08em; text-transform:uppercase; color:var(--grey)}
.tile .val{font-family:var(--disp); font-weight:800; font-size:34px; letter-spacing:-.04em; line-height:1.1; margin-top:6px; display:flex; align-items:center; gap:10px}
.tile .val i{width:10px; height:10px; border-radius:50%; display:inline-block}
.tile.new .val i{background:var(--live)} .tile.printing .val i{background:#D48A0C} .tile.printed .val i{background:var(--violet-fg)} .tile.hold .val i{background:var(--red)}
.filters{display:flex; gap:4px; flex-wrap:wrap; margin-bottom:14px}
.filters a{text-decoration:none; color:var(--ink2); font-size:14px; font-weight:600; padding:7px 14px; border-radius:99px}
.filters a:hover{background:#E9E8EF; color:var(--ink)}
.filters a.on{background:var(--ink); color:#fff}
.filters .cnt{color:var(--grey); font-weight:500; margin-left:5px}
.filters a.on .cnt{color:#C9C8D3}
.bulkbar{display:flex; gap:10px; align-items:center; flex-wrap:wrap; margin-bottom:12px}
.ordercard{padding:0; overflow:hidden}
.ordercard .table th:first-child,.ordercard .table td:first-child{padding-left:18px}
.table td.go{width:36px; color:var(--grey); font-size:18px; text-align:right; padding-right:18px}
.table input[type=checkbox]{width:17px; height:17px; accent-color:var(--live); display:block}
.table .ord{font-weight:700; white-space:nowrap}
.table .ord a{color:inherit; text-decoration:none}
.table .who{font-weight:600}
.table .who a{color:inherit; text-decoration:none}
.table .who span{display:block; font-size:12.5px; color:var(--grey); font-weight:400}
.table .placed{white-space:nowrap; color:var(--ink2)}
.table .placed span{display:block; font-size:12.5px; color:var(--grey)}
.table .design{display:flex; align-items:center; gap:12px; min-width:230px}
.table .design .thumb{width:44px; height:44px}
.table .design b{display:block; font-weight:600}
.table .design span{font-size:12.5px; color:var(--grey)}
.table .items{color:var(--ink2); white-space:nowrap}
.table .sub{display:block; font-size:12px; color:var(--grey); margin-top:4px; font-weight:400}
.tablefoot{display:flex; align-items:center; justify-content:space-between; gap:12px; padding:14px 18px; border-top:1px solid var(--rule); background:#FAFAFC}
.tablefoot .pager{display:flex; gap:8px}
.admin .card h3{margin-bottom:14px}
.admin .card+.card{margin-top:18px}
.designview{display:grid; grid-template-columns:240px minmax(0,1fr); gap:24px; align-items:start; margin-bottom:6px}
.designview .ball{max-width:240px; filter:drop-shadow(0 16px 20px rgba(24,23,33,.12))}
.dispatch{border:2px solid var(--green)}
.dispatch h3{display:flex; align-items:center; gap:10px}
.dispatch h3 .auto{font-family:var(--body); font-size:11.5px; font-weight:700; letter-spacing:.1em; text-transform:uppercase; color:var(--ok-fg); background:var(--ok-bg); border-radius:99px; padding:3px 9px}
.dispatch .grid2{align-items:end}
.mailpreview{display:flex; gap:12px; align-items:flex-start; background:var(--bg); border-radius:12px; padding:13px 15px; font-size:14px; margin-top:16px}
.mailpreview .env{flex:0 0 34px; height:34px; border-radius:9px; background:var(--live-soft); color:var(--live); display:grid; place-items:center}
.mailpreview b{display:block}
.mailpreview .sub{color:var(--ink2)}
.dispatch .foot{display:flex; align-items:center; justify-content:space-between; gap:14px; flex-wrap:wrap; margin-top:16px}
.timeline{list-style:none; margin:0; padding:0}
.timeline li{display:grid; grid-template-columns:118px 22px 1fr; gap:0 10px; align-items:start; position:relative; padding-bottom:16px}
.timeline li:last-child{padding-bottom:0}
.timeline .when{font-size:13px; color:var(--grey); font-weight:600; padding-top:2px; font-variant-numeric:tabular-nums}
.timeline .when span{display:block; color:var(--ink2)}
.timeline .mark{position:relative; height:100%}
.timeline .mark i{display:block; width:12px; height:12px; border-radius:50%; background:var(--live); border:2px solid var(--paper); box-shadow:0 0 0 2px var(--live); margin:5px auto 0; position:relative; z-index:1}
.timeline li:not(:last-child) .mark::after{content:""; position:absolute; left:50%; top:20px; bottom:-4px; width:2px; margin-left:-1px; background:var(--rule)}
.timeline .what{font-size:14.5px; padding-top:1px}
.timeline .what span{display:block; font-size:13px; color:var(--grey)}
.timeline li.future .mark i{background:var(--paper); box-shadow:0 0 0 2px var(--rule)}
.timeline li.future .what,.timeline li.future .when{color:var(--grey)}
.timeline li.future .what{font-style:italic}
.items .line{display:flex; gap:12px; align-items:center; padding:10px 0; border-bottom:1px solid var(--rule)}
.items .line:last-of-type{border-bottom:0}
.items .line .thumb{width:44px; height:44px}
.items .line b{display:block; font-weight:600; font-size:14.5px}
.items .line span{font-size:12.5px; color:var(--grey)}
.items .line .amt{margin-left:auto; font-weight:600; white-space:nowrap}
.items .penchip{width:44px; height:44px; border-radius:10px; background:var(--bg); display:grid; place-items:center; flex:0 0 44px}
.items .penchip i{width:8px; height:30px; border-radius:3px; display:block}
.note{background:var(--warn-bg); color:var(--warn-fg); border-radius:10px; padding:11px 13px; font-size:14px; line-height:1.45; margin-top:12px}
textarea{min-height:72px; resize:vertical}
.cust .name{font-weight:700; font-size:16px}
.cardnum{display:flex; align-items:center; gap:10px; font-weight:600}
.cardnum .visa{background:#1A1F71; color:#fff; font-size:10px; font-weight:800; letter-spacing:.05em; border-radius:4px; padding:3px 6px; font-style:italic}
.designgrid{display:grid; grid-template-columns:repeat(auto-fill,minmax(110px,1fr)); gap:12px}
.dcell{text-align:center} .dcell .ball{max-width:90px; margin:0 auto 6px}
/* settings */
.setlayout{display:grid; grid-template-columns:230px minmax(0,1fr); gap:26px; align-items:start}
.setlayout .side{position:sticky; top:22px}
.setlayout .side a{display:block; padding:10px 14px; border-radius:10px; color:var(--ink2); text-decoration:none; font-weight:600; font-size:14.5px}
.setlayout .side a:hover{background:#E9E8EF; color:var(--ink)}
.setlayout .side .grp{font-size:11px; letter-spacing:.14em; text-transform:uppercase; color:var(--grey); font-weight:700; padding:16px 14px 6px}
.sec{margin-bottom:22px}
.sec h2{font-size:22px; margin-bottom:4px}
.sec .lede{color:var(--ink2); font-size:14.5px; margin-bottom:18px}
.g3{display:grid; grid-template-columns:repeat(3,1fr); gap:14px}
.g3 .field+.field{margin-top:0}
.unit{position:relative}
.unit input{padding-right:46px}
.unit span{position:absolute; right:13px; top:50%; transform:translateY(-50%); font-size:13px; color:var(--grey); font-weight:600}
.savebar{display:flex; align-items:center; gap:12px; margin-top:0; margin-bottom:34px}
.savebar .small{margin-left:auto}
.cal{display:grid; grid-template-columns:1fr 1fr 1fr; gap:14px}
.cal .card{padding:16px 18px; box-shadow:none; margin-top:0 !important}
.cal .val{font-family:var(--disp); font-weight:800; font-size:26px; letter-spacing:-.03em; margin:4px 0 2px}
.cal .desc{font-size:13px; color:var(--ink2); line-height:1.5}
.toggles{display:grid; grid-template-columns:repeat(3,1fr); gap:10px; margin-top:6px}
.tog{display:flex; align-items:center; gap:10px; background:var(--bg); border-radius:11px; padding:11px 13px; font-weight:600; font-size:14px; cursor:pointer}
.tog input{accent-color:var(--live); width:18px; height:18px}
.tog.off{color:var(--grey)}
.emailrow{display:flex; align-items:center; gap:14px; padding:13px 0; border-bottom:1px solid var(--rule)}
.emailrow:last-child{border-bottom:0}
.emailrow .t{font-weight:700}
.emailrow .s{font-size:13.5px; color:var(--ink2); margin-top:2px}
.dot{display:inline-block; width:9px; height:9px; border-radius:50%; margin-right:8px; background:var(--grey)}
.dot.ok{background:var(--green)} .dot.off{background:var(--amber)}
@media (max-width:900px){
  .tiles{grid-template-columns:1fr 1fr}
  .admin .pagehead .dl{margin-left:0; width:100%}
  .ordercard{overflow-x:auto}
  .ordercard .table{min-width:880px}
  .designview{grid-template-columns:1fr}
  .designview .ball{margin:0 auto}
  .timeline li{grid-template-columns:90px 22px 1fr}
  .setlayout{grid-template-columns:1fr}
  .setlayout .side{position:static}
  .g3,.cal,.toggles{grid-template-columns:1fr 1fr}
}

/* ---------- home: how it's made (dark) ---------- */
.made{background:var(--ink); color:#fff}
.made h2{color:#fff; max-width:16ch}
.made .eyebrow.light{color:#8FB6FF}
.made .eyebrow.light::before{background:#8FB6FF}
.made-grid{display:grid; grid-template-columns:minmax(0,1.05fr) minmax(0,.95fr); gap:48px; align-items:center}
.made-lede{margin:18px 0 26px; color:#C9C8D3; font-size:17px; max-width:52ch}
.made-facts{display:grid; grid-template-columns:1fr 1fr; gap:18px 26px; margin-bottom:28px}
.made-facts b{display:block; font-family:var(--disp); font-size:22px; letter-spacing:-.03em; font-weight:800; color:#fff}
.made-facts span{font-size:14px; color:#A9A8B8}
.btn.light{background:#fff; color:var(--ink); box-shadow:none}
.btn.light:hover{background:#E9E8EF}
.made-pic{filter:drop-shadow(0 30px 40px rgba(0,0,0,.35))}
.made-pic .beam{transform-origin:220px 82px; animation:sweep 3.2s ease-in-out infinite}
.made-pic .fresh{animation:fresh 3.2s ease-in-out infinite}
.made-pic .glow{opacity:0; animation:glow 3.2s ease-in-out infinite}
@keyframes sweep{0%,100%{transform:rotate(-14deg)} 50%{transform:rotate(14deg)}}
@keyframes fresh{0%,100%{x:170px; width:40px} 50%{x:230px; width:40px}}
@keyframes glow{0%,100%{opacity:0} 50%{opacity:.9}}
@media (max-width:900px){ .made-grid{grid-template-columns:1fr} .made-facts{grid-template-columns:1fr 1fr} }
@media (max-width:560px){ .made-facts{grid-template-columns:1fr} }

/* ---------- home hero: the real ball ---------- */
.heroball3d{display:none; position:relative; width:100%; aspect-ratio:1}
.heroball3d canvas{display:block; width:100%; height:100%; touch-action:none}
.heroshadow{position:absolute; left:18%; right:18%; bottom:4%; height:9%; border-radius:50%; background:radial-gradient(ellipse at center, rgba(24,23,33,.22) 0%, rgba(24,23,33,.10) 45%, rgba(24,23,33,0) 75%); z-index:-1}
.heroball.ready .heroball3d{display:block}
.heroball.ready > svg.ball{display:none}

/* hero: the still photo shows first, the live 3-D fades in over it */
/* The poster overlays the canvas and dissolves off it. The canvas already has
   a frame rendered before .ready lands, so it needs no fade of its own: hiding
   the poster outright while the canvas faded up from zero left 0.6s with
   neither of them showing, which read as a flash on every load. */
.hero-poster{display:block; width:100%; height:auto}
.heroball.ready .hero-poster{position:absolute; inset:0; width:100%; height:100%;
  opacity:0; transition:opacity .35s ease; pointer-events:none}

/* ---------- emails & documents (admin) ---------- */
/* .field sets display:flex, which beats the browser's own [hidden] rule on
   specificity; without this a hidden field is still on the page. */
[hidden]{display:none !important}
.conn{display:flex; align-items:flex-start; gap:12px; background:var(--paper); border:1px solid var(--rule); border-radius:var(--r);
      padding:14px 18px; font-size:14.5px; color:var(--ink2); line-height:1.55; margin-bottom:24px}
.conn .dot{width:9px; height:9px; border-radius:50%; margin-top:7px; flex:0 0 9px}
.conn.ok .dot{background:var(--green)} .conn.warn .dot{background:var(--amber)}
.conn.warn{background:var(--warn-bg); border-color:#F2DFBC; color:var(--warn-fg)}
.conn b{color:inherit}
.conn code{background:rgba(24,23,33,.06); border-radius:5px; padding:1px 6px; font-size:13px}
.conn .last{margin-left:auto; white-space:nowrap; font-weight:600; text-decoration:none}

.mailgrid{display:grid; grid-template-columns:repeat(auto-fill,minmax(252px,1fr)); gap:18px}
.mailcard{background:var(--paper); border:1px solid var(--rule); border-radius:var(--r); overflow:hidden; box-shadow:var(--shadow);
          display:flex; flex-direction:column; transition:border-color .12s, box-shadow .12s}
.mailcard:hover{border-color:#C9C7D4; box-shadow:0 8px 24px rgba(24,23,33,.09)}
.mailcard.off{opacity:.62}
.mailcard.off:hover{opacity:1}
.mailcard .shot{position:relative; display:block; height:196px; overflow:hidden; background:#EAE9EF; border-bottom:1px solid var(--rule)}
.mailcard .shot iframe{position:absolute; top:0; left:50%; width:600px; height:1000px; border:0; transform:scale(.4); transform-origin:0 0;
                       margin-left:-120px; pointer-events:none}
.mailcard .veil{position:absolute; inset:0; display:grid; place-items:center; background:rgba(24,23,33,0); transition:background .12s}
.mailcard .veil .open{opacity:0; background:var(--ink); color:#fff; font-size:13px; font-weight:700; border-radius:99px; padding:8px 16px; transition:opacity .12s}
.mailcard .shot:hover .veil{background:rgba(24,23,33,.32)}
.mailcard .shot:hover .open{opacity:1}
.mailcard .meta{padding:14px 16px 16px; display:flex; flex-direction:column; gap:5px; flex:1}
.mailcard .nm{font-weight:700; font-size:15.5px; color:var(--ink); text-decoration:none; letter-spacing:-.01em}
.mailcard .sub{font-size:13px; color:var(--ink2); overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.mailcard .who{font-size:12.5px; color:var(--grey); display:flex; align-items:center; gap:7px; margin-top:1px}
.mailcard .pill{font-size:11px; font-weight:700; letter-spacing:.04em; border-radius:99px; padding:2px 8px}
.mailcard .pill.cust{background:var(--live-soft); color:var(--live)}
.mailcard .pill.you{background:var(--violet-bg); color:var(--violet-fg)}
.mailcard .auto{margin-top:auto; padding-top:11px; border-top:1px solid var(--rule); font-size:13.5px}
.mailcard .byhand{margin-top:auto; padding-top:11px; border-top:1px solid var(--rule); font-size:13px; color:var(--grey)}

.preview{background:var(--paper); border:1px solid var(--rule); border-radius:var(--r); overflow:hidden; box-shadow:var(--shadow)}
.preview .bar{display:flex; align-items:center; gap:12px; padding:11px 14px; border-bottom:1px solid var(--rule); background:#FAFAFC; flex-wrap:wrap}
.preview .widths{display:flex; gap:3px; background:var(--bg); border-radius:99px; padding:3px}
.preview .w{border:0; background:none; font:inherit; font-size:13px; font-weight:600; color:var(--ink2); padding:6px 14px; border-radius:99px; cursor:pointer}
.preview .w.on{background:var(--paper); color:var(--ink); box-shadow:0 1px 3px rgba(24,23,33,.12)}
.preview .subject{flex:1; min-width:120px; font-size:14px; font-weight:600; color:var(--ink); overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.preview .live{margin-left:auto; color:var(--grey); display:flex; align-items:center; gap:7px}
.preview .live::before{content:""; width:7px; height:7px; border-radius:50%; background:var(--green)}
.preview .stage{background:#EAE9EF; padding:22px; display:flex; justify-content:center; max-height:78vh; overflow:auto}
.preview .stage iframe{border:0; background:#EAE9EF; width:600px; height:1180px; max-width:100%; transition:width .16s}
.preview .stage.pdf{padding:0; max-height:none}
.preview .stage.pdf iframe{width:100%; height:840px; background:#EAE9EF}
.preview .blurb{padding:13px 16px; border-top:1px solid var(--rule); font-size:13.5px; color:var(--ink2); background:#FAFAFC}
.preview.docs .doctabs{background:var(--bg)}

.jump{font:inherit; font-size:14px; font-weight:600; color:var(--ink); background:var(--paper); border:1.5px solid var(--rule);
      border-radius:99px; padding:8px 14px; max-width:260px}
.plain{margin-top:18px}
.plain summary{cursor:pointer; font-weight:700; font-size:15px}
.plain pre{margin:14px 0 0; padding:16px 18px; background:var(--bg); border-radius:12px; font-size:13px; line-height:1.6;
           white-space:pre-wrap; word-break:break-word; color:var(--ink2)}

.factline{display:flex; justify-content:space-between; gap:14px; padding:7px 0; border-bottom:1px solid var(--rule); font-size:14.5px}
.factline:last-child{border-bottom:0}
.factline span{color:var(--grey)}
.factline b.good{color:var(--ok-fg)} .factline b.amber{color:var(--warn-fg)}

.swatches{display:flex; gap:8px; flex-wrap:wrap}
.sw{width:30px; height:30px; border-radius:9px; border:2px solid var(--paper); box-shadow:0 0 0 1.5px var(--rule); cursor:pointer; padding:0}
.sw:hover{box-shadow:0 0 0 2px var(--ink2)}
.colourrow{display:flex; gap:10px; align-items:center}
.colourrow input[type=color]{width:46px; height:42px; padding:2px; border:1.5px solid var(--rule); border-radius:10px; background:var(--paper); cursor:pointer}
.colourrow input[type=text]{flex:1; font-family:ui-monospace,Menlo,Consolas,monospace}

.sendmenu{display:flex; gap:10px; flex-wrap:wrap; align-items:flex-end}
.sendmenu select{flex:1; min-width:200px}
.docrow{display:flex; gap:10px; flex-wrap:wrap; margin-top:4px}

@media (max-width:960px){
  .preview .stage{padding:12px}
  .preview .stage iframe{width:100% !important}
  .mailgrid{grid-template-columns:repeat(auto-fill,minmax(220px,1fr))}
}

/* ---------------------------------------------------------------- legal bits
   The trader identity line, the checkout acknowledgement, and the model
   cancellation form. All three exist because UK consumer law asks for them,
   so they are styled to be read rather than skipped. */

.sitefoot .traderline{max-width:1180px; margin:30px auto 0; padding-top:18px;
  border-top:1px solid var(--rule); font-size:12.5px; line-height:1.7; color:var(--grey)}
.sitefoot .traderline a{display:inline; margin:0; font-size:12.5px; color:var(--grey);
  text-decoration:underline; text-decoration-color:var(--rule)}
.sitefoot .traderline a:hover{color:var(--ink2)}
.sitefoot .traderline + .legal{margin-top:14px; border-top:0; padding-top:0}

/* The "I know a custom stencil can't be returned" tick. Deliberately not a
   grey afterthought: it has to be seen for the exemption to hold. */
.ackbox{display:flex; gap:12px; align-items:flex-start; margin:4px 0 16px; padding:14px 16px;
  background:var(--bg); border:1px solid var(--rule); border-radius:12px; cursor:pointer}
.ackbox:hover{border-color:#CFCDD8}
.ackbox input{width:19px; height:19px; margin:1px 0 0; flex:0 0 auto; accent-color:var(--ink); cursor:pointer}
.ackbox span{font-size:13.5px; line-height:1.5; color:var(--ink2)}
.ackbox b{color:var(--ink)}
.ackbox.bad{border-color:#E03B2B; background:#FEF4F2}

/* The model cancellation form: blank rules to write on, on screen or printed. */
.cancelform{border:1px solid var(--rule); border-radius:var(--r); padding:24px 26px; margin:20px 0 26px;
  background:var(--paper)}
.cancelform h2{font-size:15px; margin:20px 0 8px}
.cancelform h2:first-child{margin-top:0}
.cancelform p{margin:0; color:var(--ink2); line-height:1.7}
.fillin{border-bottom:1px solid var(--ink); min-height:28px; margin:6px 0 2px}
.fillrows{width:100%; border-collapse:collapse; margin-top:14px}
.fillrows th{text-align:left; vertical-align:top; padding:8px 14px 8px 0; width:34%;
  font-size:13.5px; font-weight:600; color:var(--ink2); white-space:nowrap}
.fillrows td{padding:8px 0}
.fillrows .small{font-weight:400; white-space:normal}

@media print{
  .sitenav,.sitefoot,.crumbs,.eyebrow{display:none}
  .cancelform{border:0; padding:0}
  .docpage{padding:0}
}

@media (max-width:560px){
  .fillrows th{width:auto; white-space:normal; display:block; padding-bottom:0}
  .fillrows td{display:block; padding-top:2px}
}

/* The "ready to take money" list on /admin/settings. Outstanding items are
   amber and unmissable; done ones fade back so the eye goes to what is left. */
.launchlist{list-style:none; margin:0; padding:0}
.launchlist li{display:flex; gap:14px; align-items:flex-start; padding:14px 0; border-top:1px solid var(--rule)}
.launchlist li:first-child{border-top:0; padding-top:2px}
.launchlist .mark{flex:0 0 auto; width:22px; height:22px; border-radius:50%; display:grid; place-items:center;
  font-size:12px; font-weight:800; margin-top:1px}
.launchlist li.ok .mark{background:#E4F5EC; color:#0E7A4B}
.launchlist li.todo .mark{background:#FDF0D9; color:#8A5A00}
.launchlist li b{font-size:14.5px; display:block; margin-bottom:2px}
.launchlist li.ok b{color:var(--ink2); font-weight:600}
.launchlist li.todo b{color:var(--ink)}
.launchlist li p{margin:0; font-size:13.5px; line-height:1.55; color:var(--ink2); max-width:74ch}
.launchlist li.ok p{color:var(--grey)}
.launchlist li a{color:var(--ink); font-weight:600; text-decoration:underline; white-space:nowrap}

/* The free-pen line under the hero buttons. Green tick, quiet weight: it is a
   fact about what arrives, not a promotion shouting for attention. */
.ctarider{margin:13px 0 0; font-size:14.5px; color:var(--ink2); display:flex; align-items:center; gap:8px}
.ctarider svg{color:var(--green); flex:0 0 auto}
.ctarider b{color:var(--ink); font-weight:600}

/* "Pen included, free" in the basket, and the Free pill on the product page. */
.panel.included{display:flex; gap:11px; align-items:flex-start; background:var(--ok-bg);
  border:1px solid #C9E9D7; color:var(--ok-fg)}
.panel.included svg{color:var(--green)}
.panel.included .t{font-weight:700; font-size:14.5px; color:#0B5F3B; margin-bottom:2px}
.panel.included .s{font-size:13.5px; color:#256C4C; line-height:1.5}
.pillfree{font-family:var(--disp); font-weight:800; font-size:13px; letter-spacing:.02em;
  background:var(--ok-bg); color:var(--ok-fg); padding:5px 12px; border-radius:99px}

/* The show/hide eye on password fields. Added by shop.js, which wraps the input,
   so the wrapper has to behave like the input did inside a flex .field. */
.pwwrap{position:relative; display:block; width:100%}
.pwwrap input{width:100%; padding-right:44px}
.pweye{position:absolute; right:4px; top:50%; transform:translateY(-50%);
  width:36px; height:36px; display:grid; place-items:center;
  background:none; border:0; padding:0; cursor:pointer; color:var(--grey); border-radius:9px}
.pweye:hover{color:var(--ink2); background:var(--bg)}
.pweye[aria-pressed="true"]{color:var(--live)}
.pweye:focus-visible{outline:2px solid var(--live); outline-offset:1px}

/* A notice carrying a second line of explanation stacks instead of sitting in
   two squashed columns, which is what a bare text node beside a div gives you
   inside a flex row. */
.notice.stack{flex-direction:column; gap:5px}
.notice.stack .hint{font-size:13px; opacity:.85; line-height:1.45}

/* "Workshop ↗" in the shop nav — only an admin ever sees it. Marked out from
   the customer links so it reads as a different place, not another shop page. */
.sitenav .tolab{background:var(--ink); color:#fff; border-radius:99px; padding:7px 14px;
  font-size:13px; font-weight:700; letter-spacing:-.005em}
.sitenav .tolab:hover{background:#2A2837; color:#fff}

/* ---------- stats ----------
   Charts drawn with divs, no library. Everything on this page is a single
   series -- one blue, length carries the number -- so nothing here needs a
   legend or a second hue. Where two measures had to be shown together they are
   two charts stacked on one axis, never two scales on one chart. Green and red
   are kept for "paid for itself" / "did not" and are used nowhere else. */
.statgrid{display:grid; grid-template-columns:repeat(auto-fit,minmax(168px,1fr)); gap:14px; margin-bottom:20px}
/* ".admin .card+.card" adds a top margin so stacked cards breathe. Side by side
   in a grid that pushes every card but the first down by 18px and shortens it
   by the same, and the row comes out ragged. Cancelled wherever cards sit in a
   row rather than a stack. */
.statgrid .card+.card,.smalls .card+.card,.split>.card+.card{margin-top:0}
/* One flex column each, so the grey line under the number sits on the floor of
   every tile whether it wrapped to two lines or not. */
.statgrid .tile{display:flex; flex-direction:column}
.statgrid .tile .sub{margin-top:auto; padding-top:6px}
.tile .delta{font-family:var(--body); font-size:13px; font-weight:700; letter-spacing:0}
.tile .delta.up{color:var(--ok-fg)} .tile .delta.down{color:var(--bad-fg)} .tile .delta.flat{color:var(--grey)}
.tile .sub{font-size:12.5px; color:var(--grey); margin-top:4px}

.funnel{display:flex; flex-direction:column; gap:10px}
.fstep{display:grid; grid-template-columns:170px minmax(0,1fr) 92px; gap:14px; align-items:center}
.fstep .flab{font-size:14px; font-weight:600; color:var(--ink2)}
.ftrack{background:var(--bg); border-radius:5px; height:26px; position:relative; overflow:hidden}
.fbar{background:var(--live); height:100%; border-radius:0 5px 5px 0; min-width:3px;
      display:flex; align-items:center; justify-content:flex-end; padding-right:9px}
.fbar b{color:#fff; font-size:12.5px; font-weight:700; font-variant-numeric:tabular-nums}
.fstep .fnum{font-size:13.5px; color:var(--grey); text-align:right; font-variant-numeric:tabular-nums}
.fstep .fnum b{color:var(--ink); font-weight:700}
/* The gap between one step and its parent, which is the number worth reading. */
.fstep.leak .fnum b{color:var(--bad-fg)}
/* The designer pair hangs off the product page rather than following the row
   above it, so it is drawn as what it is. */
.fstep.branch .flab{padding-left:16px; position:relative; color:var(--grey)}
.fstep.branch .flab::before{content:""; position:absolute; left:4px; top:-2px; bottom:8px;
  width:1px; background:var(--rule)}
.fstep.branch .flab::after{content:""; position:absolute; left:4px; bottom:8px; width:7px;
  height:1px; background:var(--rule)}
.fstep.branch .fbar{background:#6C8BE4}

.smalls{display:grid; grid-template-columns:repeat(auto-fit,minmax(230px,1fr)); gap:22px}
.smalls h4{font-size:13px; letter-spacing:.08em; text-transform:uppercase; color:var(--grey); margin:0 0 10px}
.smalls .fstep{grid-template-columns:96px minmax(0,1fr) 46px; gap:9px}
.smalls .ftrack{height:18px}
.smalls .fbar b{font-size:11px}

.daychart{margin-top:6px}
.daychart h4{font-size:13px; letter-spacing:.08em; text-transform:uppercase; color:var(--grey); margin:0 0 8px}
.daybars{display:flex; align-items:flex-end; gap:2px; height:96px; padding-bottom:2px; border-bottom:1px solid var(--rule)}
.daybars .d{flex:1 1 0; min-width:2px; background:var(--live); border-radius:3px 3px 0 0; min-height:1px}
.daybars .d.zero{background:var(--rule); min-height:1px}
.dayaxis{display:flex; justify-content:space-between; font-size:12px; color:var(--grey); margin-top:6px}
.daychart+.daychart{margin-top:20px}

.attn{display:flex; flex-direction:column; gap:9px}
.arow{display:grid; grid-template-columns:190px minmax(0,1fr) 118px; gap:12px; align-items:center}
.arow .alab{font-size:14px; font-weight:600; color:var(--ink2); overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.arow .atrack{background:var(--bg); border-radius:5px; height:20px; overflow:hidden}
.arow .abar{background:var(--live); height:100%; border-radius:0 5px 5px 0; min-width:3px}
.arow .anum{font-size:13px; color:var(--grey); text-align:right; font-variant-numeric:tabular-nums}
.arow .anum b{color:var(--ink)}

.statsbar{display:flex; gap:12px; align-items:center; flex-wrap:wrap; margin-bottom:16px}
.statsbar select{max-width:280px}
.pill{display:inline-block; font-size:11.5px; font-weight:700; letter-spacing:.06em; text-transform:uppercase;
      border-radius:99px; padding:3px 9px}
.pill.good{background:var(--ok-bg); color:var(--ok-fg)}
.pill.bad{background:var(--bad-bg); color:var(--bad-fg)}
.pill.idle{background:var(--bg); color:var(--ink2)}
.nodata{padding:26px; text-align:center; color:var(--grey); font-size:14.5px}
@media (max-width:700px){
  .fstep{grid-template-columns:120px minmax(0,1fr) 74px; gap:9px}
  .arow{grid-template-columns:120px minmax(0,1fr) 92px}
}

/* ---------- consent banner ----------
   Only ever on the page when shop/consent.py says advertising is switched on
   and this visitor has not answered. Accept and Reject are deliberately the
   same size and weight: a banner that makes refusing harder is not consent. */
.consent{position:fixed; left:0; right:0; bottom:0; z-index:60; background:var(--paper);
         border-top:1px solid var(--rule); box-shadow:0 -6px 24px rgba(24,23,33,.10)}
.consent-in{max-width:1080px; margin:0 auto; padding:18px 20px; display:flex; gap:22px;
            align-items:center; flex-wrap:wrap}
.consent-say{flex:1 1 380px}
.consent-say h2{font-size:19px; font-weight:700; letter-spacing:-.02em; margin-bottom:5px}
.consent-say p{font-size:14px; color:var(--ink2); line-height:1.5}
.consent-do{display:flex; gap:10px; flex-wrap:wrap}
.cbtn{font-family:var(--body); font-size:14.5px; font-weight:700; padding:11px 20px; border-radius:99px;
      border:1px solid var(--ink); background:var(--paper); color:var(--ink); cursor:pointer}
.cbtn:hover{background:var(--bg)}
.cbtn[data-consent=accept]{background:var(--ink); color:#fff}
.cbtn[data-consent=accept]:hover{background:#2C2A38}
@media (max-width:560px){.consent-do{width:100%}.cbtn{flex:1}}

/* ---------- benchmarks ----------
   One row per figure: a pale band showing where a working shop usually sits,
   and a marker showing where this shop actually is. The band is the point --
   a single "average" number invites chasing a decimal, a range says whether
   anything is actually wrong. */
.arow.bench .btrack{position:relative; height:20px; background:var(--bg); border-radius:5px}
.arow.bench .band{position:absolute; top:0; bottom:0; background:#DCE6FA; border-radius:4px}
.arow.bench .mark{position:absolute; top:-3px; width:4px; height:26px; border-radius:3px;
  background:var(--ink); margin-left:-2px}
.arow.bench .mark.low{background:var(--red)}
.arow.bench .mark.high{background:var(--green)}
.arow.bench.thin{opacity:.5}
.benchnote{margin:-2px 0 6px 202px; color:var(--ink2); max-width:70ch}
@media (max-width:700px){.benchnote{margin-left:132px}}
.table td .sub{display:block; font-size:12px; color:var(--grey); margin-top:3px}

/* ---- affiliates: the code box in the basket, the partner dashboard, the admin pages ---- */
.codeform{margin-top:16px; padding-top:14px; border-top:1px solid var(--rule)}
.codeform .row{display:flex; gap:8px; margin-top:6px}
.codeform .row input{flex:1; min-width:0; text-transform:uppercase}
.codeform .applied{font-size:14px; color:var(--green); font-weight:600}
.codeform .applied+.linkish{margin-left:8px; font-size:13px; color:var(--grey)}
.row2{display:flex; gap:8px}
.row2 input{flex:1; min-width:0}
.row2 select{width:auto; flex:0 0 auto}
.affcode{font-family:ui-monospace,"SF Mono",Menlo,monospace; font-weight:700; font-size:clamp(26px,4vw,38px); letter-spacing:.06em; background:var(--bg); border-radius:12px; padding:14px 18px; display:inline-block}
.afflink{width:100%; font-family:ui-monospace,"SF Mono",Menlo,monospace; font-size:13.5px; padding:10px 12px; border:1px solid var(--rule); border-radius:10px; background:var(--bg); color:var(--ink)}
.qrbox{display:flex; gap:22px; align-items:flex-start; flex-wrap:wrap}
.qrbox img{width:180px; height:180px; border:1px solid var(--rule); border-radius:12px; background:#fff; padding:6px; flex:0 0 auto}
.qrbox>div{flex:1; min-width:200px}
.qrbox .acts{display:flex; gap:8px; flex-wrap:wrap; margin-top:12px}
.tiles.six{grid-template-columns:repeat(6,1fr)}
.tile .val.money{font-size:26px}
@media (max-width:980px){.tiles.six{grid-template-columns:repeat(3,1fr)}}
@media (max-width:560px){.tiles.six{grid-template-columns:1fr 1fr} .tile .val.money{font-size:22px}}
