/* The shop front. GENERATED -- see tools/make_shopfront.py; edit the
   template, not this file.

   WHAT THIS IS FOR. Somebody meets JTS on the hub, sees a coloured card,
   clicks it, and lands here. Before this, that landing felt like walking
   out of a shop and into a boiler room: the hub is loud, light and
   typographic, and every product site was the quiet dark working screen
   that a customer stares at doing their figures on a Tuesday night. Two
   different companies, to look at.

   WHAT CHANGED AND WHAT DID NOT. The COLOUR SCHEME stays -- black ground,
   this product's own accent -- because that is the product's identity and
   it is what the working screens are. What is borrowed from the hub is
   everything ELSE: the same two typefaces, the same big display scale, the
   same 2px rules and hard un-blurred offset shadow, the same pill buttons,
   the same fluid width, the same scroll reveals, and the same flat
   colour-field art panel carrying the product's own promise -- in the very
   colour of the card that was just clicked. So the page is recognisably
   the same hand without pretending to be a light page.

   WHERE IT APPLIES, AND WHY THAT MATTERS. This file is loaded ONLY on the
   public pages -- the sales page, signing up, paying, terms. EVERY rule is
   under `body.shopfront`, and no template inside the app sets that class.
   EZ Move is the reason both of those are belt and braces: its app screens
   and its sales page share one layout and one stylesheet, so an unscoped
   rule here would restyle a tool somebody is working in.

   It is a SEPARATE FILE rather than an addition to style.css for the same
   reason: style.css is untouched, so nothing here can reach the app even
   by accident, and the whole change comes off by deleting one link. */

body.shopfront {
  /* Everything is prefixed --sf- on purpose. The app's own variables live
     in the same document on EZ Move, and a shop front must not be able to
     reach in and repaint a working screen. */
  --sf-accent: #57a6f5;
  --sf-art:    #1F5FA8;          /* this tool's colour ON THE HUB, so the
                                    card that was clicked and the panel
                                    that is landed on are the same colour */
  --sf-bg:     var(--bg, #0f1216);
  --sf-panel:  var(--surface, #171b21);
  --sf-ink:    var(--ink, #e9eef5);
  --sf-dim:    var(--dim, var(--muted, #94a1b2));
  --sf-edge:   #333c48;
  --sf-shadow: 6px 6px 0 rgba(0, 0, 0, .62);
  --sf-wrap:   1720px;
  --sf-gutter: clamp(16px, 2.6vw, 52px);
  --sf-r:      16px;

  padding-left: var(--sf-gutter);
  padding-right: var(--sf-gutter);
  background: var(--sf-bg);
  color: var(--sf-ink);
  font-family: Archivo, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  font-size: 16.5px;
  line-height: 1.6;
  overflow-x: hidden;
}

body.shopfront h1,
body.shopfront h2,
body.shopfront h3,
body.shopfront .sf-display {
  font-family: "Bricolage Grotesque", Archivo, "Segoe UI", Helvetica, Arial,
               sans-serif;
  font-weight: 800;
  letter-spacing: -.02em;
}

body.shopfront main,
body.shopfront > header.top,
body.shopfront > section,
body.shopfront > div.notice,
body.shopfront > div.strip,
body.shopfront > p.foot,
body.shopfront > footer {
  max-width: var(--sf-wrap);
  margin-left: auto;
  margin-right: auto;
}

/* ---- scroll reveal ------------------------------------------------------
   THE RULE THAT MATTERS MORE THAN THE EFFECT: the hiding only happens once
   the script has said it can un-hide. If the script never runs, the page is
   an ordinary readable page rather than a blank one. A sales page that
   hides its own content and then fails to show it has sold nothing. */
html.can-reveal body.shopfront .reveal {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity .55s cubic-bezier(.22,.7,.3,1),
              transform .55s cubic-bezier(.22,.7,.3,1);
  will-change: opacity, transform;
}
html.can-reveal body.shopfront .reveal.in { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  html.can-reveal body.shopfront .reveal {
    opacity: 1; transform: none; transition: none;
  }
}

/* ---- header ------------------------------------------------------------ */
body.shopfront header.top {
  padding: 18px 0 10px;
  display: flex;
  align-items: center;
  gap: 14px;
  border: 0;
  background: none;
}
body.shopfront header.top .brand {
  display: flex;
  align-items: center;
  gap: 10px;
  text-decoration: none;
  color: var(--sf-ink);
  font-family: "Bricolage Grotesque", Archivo, sans-serif;
  font-weight: 800;
  letter-spacing: -.02em;
  font-size: 20px;
}
body.shopfront header.top .jts-mark { width: 34px; height: 34px; }

body.shopfront .sf-nav {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  justify-content: flex-end;
}
body.shopfront .sf-nav a {
  text-decoration: none;
  color: var(--sf-ink);
  font-size: 15px;
  font-weight: 600;
  padding: 9px 14px;
  border-radius: 999px;
  border: 2px solid transparent;
  white-space: nowrap;
}
body.shopfront .sf-nav a:hover { background: var(--sf-panel); }

/* The way back out to the shop. It carries the hexagon so it reads as the
   company mark rather than as one more link. */
body.shopfront .sf-tools {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  border-color: var(--sf-edge) !important;
}
body.shopfront .sf-tools:hover {
  border-color: var(--sf-accent) !important;
  background: var(--sf-panel);
}
body.shopfront .sf-tools svg { width: 17px; height: 17px; flex: none; }
body.shopfront .sf-nav .sf-cta {
  background: var(--sf-accent);
  color: #06120b;
  border-color: var(--sf-accent);
}
body.shopfront .sf-nav .sf-cta:hover { filter: brightness(1.08); }

/* ---- type -------------------------------------------------------------- */
body.shopfront h1 {
  font-size: clamp(34px, 5.6vw, 64px);
  line-height: 1;
  margin: 0 0 18px;
  text-wrap: balance;
}
body.shopfront h2 { font-size: clamp(24px, 3vw, 34px); line-height: 1.08; }
body.shopfront h3 { font-size: 20px; letter-spacing: -.01em; }

body.shopfront .lead,
body.shopfront .sub {
  font-size: clamp(16.5px, 1.7vw, 19px);
  color: var(--sf-dim);
  max-width: 58ch;          /* prose does NOT grow with the page: the extra
                               width goes to the grids instead */
}
body.shopfront .sf-eyebrow {
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--sf-dim);
  margin: 0 0 14px;
}

/* ---- the hero ---------------------------------------------------------- */
body.shopfront .sf-hero {
  display: grid;
  grid-template-columns: 1.25fr 1fr;
  gap: 30px;
  align-items: center;
  padding: 30px 0 8px;
}
@media (max-width: 900px) {
  body.shopfront .sf-hero { grid-template-columns: 1fr; gap: 22px; }
}
body.shopfront .sf-hero-words { min-width: 0; }
body.shopfront .sf-buttons {
  display: flex; flex-wrap: wrap; gap: 12px; margin: 22px 0 16px;
}
body.shopfront .sf-note {
  font-size: 15px;
  color: var(--sf-dim);
  margin: 0;
  padding-left: 14px;
  border-left: 4px solid var(--sf-accent);
}

/* THE PICTURE. There are no photographs here and no invented screenshots.
   The image is the product's own promise set large on its own colour --
   the same panel the hub puts on its cards, so the click and the landing
   are visibly the same object. It says something true and cannot go
   stale. */
body.shopfront .sf-art {
  position: relative;
  background: var(--sf-art);
  color: #fff;
  border: 2px solid var(--sf-edge);
  border-radius: var(--sf-r);
  box-shadow: var(--sf-shadow);
  padding: 22px;
  min-height: 250px;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
body.shopfront .sf-art::before {          /* a drawing board, faintly */
  content: "";
  position: absolute; inset: 0;
  background-image: linear-gradient(rgba(255,255,255,.14) 1px, transparent 1px),
                    linear-gradient(90deg, rgba(255,255,255,.14) 1px, transparent 1px);
  background-size: 26px 26px;
  opacity: .5;
}
body.shopfront .sf-art-who {
  position: relative;
  font-size: 11.5px; font-weight: 700; letter-spacing: .13em;
  text-transform: uppercase; opacity: .85;
}
/* THE PANEL IS A SIGN, NOT AN ECHO. It first carried the product's own
   tagline -- which is also the headline three inches to its left, so the
   page said the same sentence twice and the picture earned nothing. It now
   carries what a sign carries: the trade, the name, and the one concrete
   thing underneath. */
body.shopfront .sf-art-name {
  position: relative;
  margin-top: auto;
  font-family: "Bricolage Grotesque", Archivo, sans-serif;
  font-weight: 800;
  letter-spacing: -.03em;
  font-size: clamp(38px, 4.4vw, 58px);
  line-height: .95;
  text-wrap: balance;
}
body.shopfront .sf-art-say {
  position: relative;
  margin-top: 10px;
  font-size: 15px;
  line-height: 1.35;
  opacity: .92;
  font-variant-numeric: tabular-nums;
}
body.shopfront .sf-art-mark {
  position: absolute;
  right: -10px; bottom: -40px;
  font-family: "Bricolage Grotesque", Archivo, sans-serif;
  font-weight: 800;
  font-size: 170px;
  line-height: 1;
  color: rgba(255, 255, 255, .13);
  pointer-events: none;
}

/* ---- panels ------------------------------------------------------------
   The existing pages are built out of .card, and they keep it -- the
   construction is what changes: a real 2px rule and a hard un-blurred
   offset, the way the hub builds a panel, instead of a soft raised box. */
body.shopfront .card,
body.shopfront .sf-panel {
  background: var(--sf-panel);
  border: 2px solid var(--sf-edge);
  border-radius: var(--sf-r);
  box-shadow: var(--sf-shadow);
  padding: 24px;
  margin: 22px 0;
}
body.shopfront .card > h2:first-child,
body.shopfront .sf-panel > h2:first-child { margin-top: 0; }

body.shopfront .sf-cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 315px), 1fr));
  gap: 20px;
  margin: 22px 0;
}
body.shopfront .sf-cards .card,
body.shopfront .sf-cards .sf-panel { margin: 0; }

body.shopfront .sf-head { margin: 66px 0 22px; max-width: 60ch; }
body.shopfront .sf-head h2 { margin: 0 0 8px; }
body.shopfront .sf-head p { margin: 0; color: var(--sf-dim); }

/* ---- buttons -----------------------------------------------------------
   Same gesture as the hub: a pill with a real border and a hard offset
   that presses in when clicked. There the fill is gold on paper; here it
   is this product's accent on black. */
body.shopfront button,
body.shopfront .go,
body.shopfront .btn,
body.shopfront .say-btn,
body.shopfront input[type="submit"] {
  font-family: "Bricolage Grotesque", Archivo, sans-serif;
  font-weight: 800;
  letter-spacing: -.01em;
  font-size: 16px;
  padding: 14px 24px;
  border-radius: 999px;
  border: 2px solid var(--sf-accent);
  background: var(--sf-accent);
  color: #06120b;
  text-decoration: none;
  display: inline-block;
  cursor: pointer;
  box-shadow: var(--sf-shadow);
  transition: transform .12s, box-shadow .12s, filter .12s;
}
body.shopfront button:hover,
body.shopfront .go:hover,
body.shopfront .btn:hover,
body.shopfront .say-btn:hover {
  transform: translate(-2px, -2px);
  box-shadow: 8px 8px 0 rgba(0, 0, 0, .62);
  filter: brightness(1.06);
}
body.shopfront button:active,
body.shopfront .go:active,
body.shopfront .btn:active,
body.shopfront .say-btn:active {
  transform: translate(3px, 3px);
  box-shadow: 2px 2px 0 rgba(0, 0, 0, .62);
}
body.shopfront .btn-quiet,
body.shopfront button.quiet {
  background: transparent;
  color: var(--sf-ink);
  border-color: var(--sf-edge);
  box-shadow: none;
}
body.shopfront .btn-quiet:hover,
body.shopfront button.quiet:hover {
  background: var(--sf-panel);
  box-shadow: none;
  transform: none;
}
/* The header's own buttons are nav, not calls to action -- they must not
   grow a hard shadow and start shouting at the top of the page. */
body.shopfront header.top .say-btn,
body.shopfront .sf-nav a {
  box-shadow: none;
  padding: 9px 14px;
  font-size: 15px;
  font-family: Archivo, sans-serif;
  font-weight: 600;
  letter-spacing: 0;
}
body.shopfront header.top .say-btn:hover,
body.shopfront .sf-nav a:hover { transform: none; box-shadow: none; }

body.shopfront a.linkish,
body.shopfront .linkish {
  color: var(--sf-accent);
  background: none;
  border: 0;
  box-shadow: none;
  padding: 0;
  font: inherit;
  text-decoration: underline;
  text-underline-offset: 3px;
}
body.shopfront a.linkish:hover { transform: none; box-shadow: none; }

/* ---- forms ------------------------------------------------------------- */
body.shopfront input[type="text"],
body.shopfront input[type="email"],
body.shopfront input[type="password"],
body.shopfront input:not([type]),
body.shopfront select,
body.shopfront textarea {
  background: var(--sf-bg);
  border: 2px solid var(--sf-edge);
  border-radius: 10px;
  color: var(--sf-ink);
  font: 16px Archivo, "Segoe UI", sans-serif;
  padding: 11px 13px;
}
body.shopfront input:focus-visible,
body.shopfront select:focus-visible,
body.shopfront textarea:focus-visible,
body.shopfront button:focus-visible,
body.shopfront a:focus-visible {
  outline: 3px solid var(--sf-accent);
  outline-offset: 2px;
}

/* ---- the rest of the family -------------------------------------------
   The way back to the shop, at the foot of every public page. It is also
   the honest answer to "what else is there?" without making the page about
   the other products. */
body.shopfront .sf-family { margin: 70px 0 0; }
body.shopfront .sf-family-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 250px), 1fr));
  gap: 16px;
}
body.shopfront .sf-sib {
  display: flex;
  flex-direction: column;
  text-decoration: none;
  color: var(--sf-ink);
  border: 2px solid var(--sf-edge);
  border-radius: var(--sf-r);
  overflow: hidden;
  background: var(--sf-panel);
  transition: transform .14s, box-shadow .14s, border-color .14s;
}
body.shopfront .sf-sib:hover {
  transform: translate(-3px, -3px);
  box-shadow: 7px 7px 0 rgba(0, 0, 0, .62);
  border-color: var(--sf-c);
}
body.shopfront .sf-sib-art {
  background: var(--sf-c);
  color: #fff;
  padding: 14px 16px 16px;
  min-height: 104px;
  display: flex;
  flex-direction: column;
  border-bottom: 2px solid var(--sf-edge);
}
body.shopfront .sf-sib-who {
  font-size: 10.5px; font-weight: 700; letter-spacing: .12em;
  text-transform: uppercase; opacity: .85;
}
body.shopfront .sf-sib-say {
  margin-top: auto;
  font-family: "Bricolage Grotesque", Archivo, sans-serif;
  font-weight: 800;
  letter-spacing: -.02em;
  font-size: 15.5px;
  line-height: 1.15;
}
body.shopfront .sf-sib-body {
  padding: 13px 16px 15px;
  display: flex;
  align-items: baseline;
  gap: 10px;
}
body.shopfront .sf-sib-body b {
  font-family: "Bricolage Grotesque", Archivo, sans-serif;
  font-weight: 800;
  font-size: 18px;
  letter-spacing: -.02em;
}
body.shopfront .sf-sib-go {
  margin-left: auto; font-size: 14px; color: var(--sf-c); font-weight: 700;
}
body.shopfront .sf-all {
  display: inline-block;
  margin-top: 18px;
  font-weight: 700;
  color: var(--sf-accent);
  text-decoration: none;
  border-bottom: 2px solid var(--sf-accent);
  padding-bottom: 2px;
}

/* ---- foot -------------------------------------------------------------- */
/* Chalkline's header puts its Sign in link OUTSIDE the nav, so the order is
   set here rather than by markup: mark, then the way out to the shop, then
   whatever that page's own link is. */
body.shopfront header.top .brand { order: -2; }
body.shopfront header.top .sf-nav { order: -1; }
body.shopfront header.top .top-link {
  order: 0;
  text-decoration: none;
  color: var(--sf-ink);
  font-size: 15px;
  font-weight: 600;
  padding: 9px 14px;
  border-radius: 999px;
  border: 2px solid var(--sf-accent);
  background: none;
  box-shadow: none;
  white-space: nowrap;
}
body.shopfront header.top .top-link:hover {
  background: var(--sf-accent); color: #06120b; transform: none;
}

body.shopfront p.foot,
body.shopfront footer.foot {
  margin-top: 64px;
  padding: 22px 0 54px;
  border-top: 2px solid var(--sf-edge);
  color: var(--sf-dim);
  font-size: 14px;
}
body.shopfront footer.foot a { color: var(--sf-dim); }
body.shopfront footer.foot a:hover { color: var(--sf-accent); }

/* ---- notices ----------------------------------------------------------- */
body.shopfront .notice,
body.shopfront .strip {
  border: 2px solid var(--sf-edge);
  border-radius: 12px;
  background: var(--sf-panel);
  padding: 11px 16px;
  margin: 12px 0;
  font-size: 15px;
}
body.shopfront .notice a,
body.shopfront .strip a { color: var(--sf-accent); font-weight: 700; }

/* Tables keep their own scroller so a wide one never makes the whole page
   slide sideways. */
body.shopfront .tbl { width: 100%; }
body.shopfront .sf-scroll { overflow-x: auto; }

/* EZ MOVE'S NAV HAS NO CLASS OF ITS OWN, and it is the same element its app
   screens use, so it cannot be given one without reaching into the app.
   It is matched by position instead -- and only under body.shopfront, so a
   working screen is never touched. */
body.shopfront header.top nav {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  justify-content: flex-end;
}
body.shopfront header.top nav a {
  text-decoration: none;
  color: var(--sf-ink);
  font-size: 15px;
  font-weight: 600;
  padding: 9px 14px;
  border-radius: 999px;
  border: 2px solid transparent;
  white-space: nowrap;
  background: none;
  box-shadow: none;
}
body.shopfront header.top nav a:hover {
  background: var(--sf-panel); transform: none; box-shadow: none;
}
body.shopfront header.top nav a.on { color: var(--sf-accent); }
