/* ===========================================================
   css/main.css  -  every style for the public site
   ===========================================================
   One file, loaded once, cached between pages. It cannot live
   in the section files: each would have to redeclare :root and
   you would have four copies of the same variables.

   The palette is at the top. Change --paper, --ink and --copper
   and the whole site follows.
   =========================================================== */

:root {
      --paper: #EFEEE9;
      --ink: #16181A;
      --muted: #6E6F6B;
      --rule: #D3D2CC;
      --copper: #B4602F;
      --font: 'Space Grotesk', sans-serif;
      --gutter: 34px;
      --max: 1480px;
    }

    * { margin: 0; padding: 0; box-sizing: border-box; }

    body {
      background: var(--paper);
      color: var(--ink);
      font-family: var(--font);
      line-height: 1.45;
      -webkit-font-smoothing: antialiased;
      overflow-x: hidden;
    }

    /* The page sits inside a ruled column, so content has a visible
   edge to hang off instead of drifting into the browser chrome.
   The hairlines are what make it read as a document. */
.wrap {
  max-width: var(--max);
  margin: 0 auto;
  padding: 0 var(--gutter);
  border-left: 1px solid var(--rule);
  border-right: 1px solid var(--rule);
}

    .label {
      font-size: 0.66rem;
      font-weight: 500;
      letter-spacing: 0.16em;
      text-transform: uppercase;
      color: var(--muted);
    }

    .label .idx { color: var(--ink); margin-right: 12px; }

    /* =========================================================
       LOADER
       The images fill the whole screen and the counter sits on
       top of them, centred. A framed photo with the number off
       to one side read as two separate things; this reads as one.

       The counter still follows how many images have actually
       downloaded - see js/main.js - so 100 means ready.
       ========================================================= */
    #loader {
      position: fixed;
      inset: 0;
      z-index: 200;
      background: #0C0D0F;
      overflow: hidden;
      transition: opacity .7s ease, visibility .7s;
    }

    #loader.done {
      opacity: 0;
      visibility: hidden;
      pointer-events: none;
    }

    /* Full bleed. object-fit: cover crops rather than squashes,
       so the frame is filled at any window shape. */
    .load-frame {
      position: absolute;
      inset: 0;
    }

    .load-frame img {
      position: absolute;
      inset: 0;
      width: 100%;
      height: 100%;
      object-fit: cover;
      opacity: 0;
      /* In colour now, just dimmed. The number still needs
         something dark behind it whichever frame is showing, so
         the brightness stays down - but the boards keep their
         blues and oranges. */
      filter: contrast(1.05) brightness(0.55);
      transform: scale(1.04);
      transition: opacity .35s ease;
    }

    .load-frame img.on { opacity: 1; }

    /* THE COUNTER - centred over the images. */
    #count {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      z-index: 3;
      font-size: clamp(6rem, 27vw, 24rem);
      font-weight: 500;
      letter-spacing: -0.055em;
      line-height: 0.78;
      color: var(--paper);
      font-variant-numeric: tabular-nums;   /* stops digits jittering */
      text-shadow: 0 8px 60px rgba(0, 0, 0, 0.45);
      pointer-events: none;
    }

    /* Small marks in the corners. Deliberately quiet - the number
       is the thing. */
    .load-top,
    .load-bottom {
      position: absolute;
      left: 0;
      right: 0;
      z-index: 3;
      display: flex;
      justify-content: space-between;
      gap: 20px;
      padding: 0 var(--gutter);
      pointer-events: none;
    }

    .load-top { top: var(--gutter); }
    .load-bottom { bottom: calc(var(--gutter) + 8px); }

    .load-top .label,
    .load-bottom .label { color: rgba(239, 238, 233, 0.62); }

    /* Skip. Quiet, but always reachable - the whole loader is
       clickable too, and Escape works. Three ways out, because
       someone who wants past this should never have to hunt. */
    .load-bottom {
      pointer-events: none;
    }

    .skip-intro {
      pointer-events: auto;
      background: none;
      border: 0;
      padding: 4px 0;
      cursor: pointer;
      font-family: var(--font);
      font-size: 0.66rem;
      font-weight: 500;
      letter-spacing: 0.16em;
      text-transform: uppercase;
      color: rgba(239, 238, 233, 0.62);
      transition: color .25s;
    }

    .skip-intro:hover {
      color: var(--paper);
    }

    /* Fills across the very bottom of the screen. */
    .load-bar {
      position: absolute;
      left: 0;
      bottom: 0;
      height: 2px;
      width: 0;
      background: var(--paper);
      z-index: 4;
      transition: width .25s ease;
    }

    /* ========== HEADER ========== */
    header {
      position: fixed;
      top: 0; left: 0; right: 0;
      z-index: 100;
      background: var(--paper);
      border-bottom: 1px solid var(--rule);
    }

    .head {
      max-width: var(--max);
      margin: 0 auto;
      padding: 0 var(--gutter);
      height: 54px;
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 26px;
    }

    .mark {
      display: flex;
      align-items: center;
      text-decoration: none;
      flex-shrink: 0;
    }

    /* Height, not width. The header bar is a fixed height, so
       sizing by height keeps the wordmark in proportion to it
       whatever the image's own dimensions are. */
    .mark img {
      height: 18px;
      width: auto;
      display: block;
    }

    .mark sup { color: var(--copper); font-size: 0.6em; }

    nav.top { display: flex; gap: 24px; margin-left: auto; }

    nav.top a, .bag {
      font-size: 0.72rem;
      letter-spacing: 0.12em;
      text-transform: uppercase;
      color: var(--ink);
      text-decoration: none;
      position: relative;
      padding-bottom: 3px;
      white-space: nowrap;
    }

    /* Underline grows from the left rather than appearing. */
    nav.top a::after, .bag::after {
      content: "";
      position: absolute;
      left: 0; bottom: 0;
      width: 100%; height: 1px;
      background: var(--ink);
      transform: scaleX(0);
      transform-origin: left;
      transition: transform .35s cubic-bezier(0.22, 1, 0.36, 1);
    }

    nav.top a:hover::after, .bag:hover::after { transform: scaleX(1); }

    /* =========================================================
       SHOP NOW
       The only filled shape in the header. Everything else is a
       link, so this reads as the action without needing to be
       loud about it.
       ========================================================= */
    .shop-now {
      font-size: 0.72rem;
      letter-spacing: 0.12em;
      text-transform: uppercase;
      text-decoration: none;
      white-space: nowrap;
      padding: 9px 18px;
      background: var(--ink);
      color: var(--paper);
      transition: background-color .3s;
    }

    .shop-now:hover {
      background: var(--copper);
    }

    /* On a phone the nav links are already hidden, so this and
       the account icon are all that is left - which is the right
       pair to keep. */
    @media (max-width: 700px) {
      .shop-now {
        padding: 8px 13px;
        font-size: 0.68rem;
      }

      .bag {
        display: none;
      }
    }

    /* =========================================================
       ACCOUNT MENU
       An icon rather than two text buttons - at this size the
       header cannot carry "Log in" and "Sign up" without going
       cluttered. The panel opens beneath it.
       ========================================================= */
    .account {
      position: relative;
      margin-left: 4px;
    }

    .account-btn {
      display: flex;
      align-items: center;
      gap: 7px;
      background: none;
      border: 0;
      padding: 6px 2px;
      cursor: pointer;
      font-family: var(--font);
      font-size: 0.72rem;
      letter-spacing: 0.12em;
      text-transform: uppercase;
      color: var(--ink);
    }

    .account-btn svg {
      width: 15px;
      height: 15px;
      stroke: currentColor;
      fill: none;
      stroke-width: 1.8;
      stroke-linecap: round;
      stroke-linejoin: round;
    }

    .account-btn:hover { color: var(--copper); }

    /* The panel. Hidden by height rather than display:none, so it
       can animate - display cannot be transitioned. */
    /* display:none as well as the transition properties. If this
       stylesheet ever fails to load, the menu shows as two plain
       links stacked in the header - ugly, but it also means a
       broken CSS load looks broken rather than subtly wrong. */
    .account-menu {
      position: absolute;
      top: calc(100% + 14px);
      right: 0;
      min-width: 190px;
      background: var(--paper);
      border: 1px solid var(--rule);
      opacity: 0;
      visibility: hidden;
      transform: translateY(-6px);
      transition: opacity .25s ease, transform .25s cubic-bezier(0.22, 1, 0.36, 1),
        visibility .25s;
    }

    .account.open .account-menu {
      opacity: 1;
      visibility: visible;
      transform: none;
    }

    .account-menu .who {
      padding: 12px 16px;
      border-bottom: 1px solid var(--rule);
      font-size: 0.72rem;
      letter-spacing: 0.1em;
      text-transform: uppercase;
      color: var(--muted);
    }

    .account-menu a {
      display: flex;
      justify-content: space-between;
      align-items: center;
      gap: 14px;
      padding: 13px 16px;
      font-size: 0.82rem;
      color: var(--ink);
      text-decoration: none;
      border-top: 1px solid var(--rule);
      transition: background-color .2s, padding-left .25s;
    }

    .account-menu a:first-of-type { border-top: 0; }
    .account-menu a:hover { background: #E7E6E0; padding-left: 20px; }

    .account-menu a .arrow { color: var(--copper); opacity: 0; transition: opacity .2s; }
    .account-menu a:hover .arrow { opacity: 1; }

    .account-menu a.out { color: var(--copper); }

    /* =========================================================
       THE WORDMARK
       Sized in vw so it always spans the screen. Bottom-anchored
       with empty space above - centred large type reads as a
       poster, bottom-anchored reads as a publication.
       ========================================================= */
    .hero {
      /* Not a full screen any more. At the smaller type size all
         that height was empty, and it buried everything below. */
      min-height: 76vh;
      display: flex;
      flex-direction: column;
      justify-content: flex-end;
      /* 54px clears the fixed header; the rest is breathing room.
         Without this the wordmark slides up underneath the bar on
         a wide, short screen. */
      padding-top: calc(54px + 4vh);
      padding-bottom: 3vh;
    }

    .wordmark {
      font-weight: 700;
      /* One line, so it can run larger than the two-line version
         did. Sized in vw to span the column, capped in rem so it
         stops growing on a very wide monitor. The vw figure is
         what to change if it does not reach the edges. */
      font-size: clamp(1.9rem, 14vw, 13.5rem);
      white-space: nowrap;
      line-height: 0.82;
      letter-spacing: -0.05em;
      margin-bottom: 6vh;
    }

    /* The accent moved off the wordmark and onto the index
       numbers, so copper still appears - just not as a big R
       hanging off the name. */
    .label .idx { color: var(--copper); }

    .meta {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
      gap: 26px;
      padding-top: 22px;
      border-top: 1px solid var(--rule);
    }

    .meta p.body { font-size: 0.95rem; margin-top: 8px; max-width: 30ch; }

    /* ========== REVEALS ========== */
    .line { display: block; overflow: hidden; }

    .line > span {
      display: block;
      transform: translateY(102%);
      transition: transform 1.15s cubic-bezier(0.22, 1, 0.36, 1);
    }

    .line.in > span { transform: translateY(0); }
    .wordmark .line:nth-child(2) > span { transition-delay: .1s; }

    .fade {
      opacity: 0;
      transform: translateY(16px);
      transition: opacity .9s ease, transform .9s cubic-bezier(0.22, 1, 0.36, 1);
    }

    .fade.in { opacity: 1; transform: none; }

    /* =========================================================
       MARQUEE
       Slow, constant, unremarkable. Stops the page ever feeling
       frozen without asking to be looked at.
       ========================================================= */
    .marquee {
      border-top: 1px solid var(--rule);
      border-bottom: 1px solid var(--rule);
      overflow: hidden;
      padding: 16px 0;
      white-space: nowrap;
    }

    .marquee-track { display: inline-flex; animation: slide 38s linear infinite; }

    .marquee span {
      font-size: 0.82rem;
      letter-spacing: 0.12em;
      text-transform: uppercase;
      color: var(--muted);
      padding-right: 40px;
    }

    .marquee b { color: var(--copper); font-weight: 400; padding: 0 40px 0 0; }

    @keyframes slide { to { transform: translateX(-50%); } }

    /* ========== SECTION HEADS ========== */
    .section-head {
      display: flex;
      justify-content: space-between;
      align-items: baseline;
      gap: 20px;
      padding: 5vh 0 18px;
      border-bottom: 1px solid var(--rule);
    }

    /* =========================================================
       KIT GRID
       The 1px gaps over a grey background become the grid lines,
       which beats borders - those double up where cards meet.
       ========================================================= */
    .grid {
      display: grid;
      /* auto-FIT, not auto-fill. auto-fill leaves empty columns
         when there are fewer items than fit; auto-fit collapses
         them so the real cards stretch across the whole width. */
      grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
      gap: 1px;
      background: var(--rule);
      border-bottom: 1px solid var(--rule);
    }

    .kit {
      background: var(--paper);
      padding: 20px 20px 26px;
      text-decoration: none;
      color: inherit;
      display: flex;
      flex-direction: column;
      transition: background-color .3s;
    }

    .kit:hover { background: #E7E6E0; }

    .kit-img {
      aspect-ratio: 1 / 1;
      background: #E3E2DC;
      overflow: hidden;
      margin-bottom: 18px;
    }

    .kit-img img {
      width: 100%; height: 100%;
      object-fit: cover;
      display: block;
      /* Full colour. Draining it made the photographs read as
         one set, but it also made real product photos look
         drab - and a kit is bought on how it looks. */
      transition: transform .5s cubic-bezier(0.22, 1, 0.36, 1);
    }

    .kit:hover .kit-img img { transform: none; }

    .kit-name {
      font-size: 1.12rem;
      font-weight: 500;
      letter-spacing: -0.015em;
      margin-bottom: 5px;
    }

    .kit-cat {
      font-size: 0.72rem;
      letter-spacing: 0.1em;
      text-transform: uppercase;
      color: var(--muted);
      margin-bottom: 14px;
    }

    .kit-price {
      font-size: 1.05rem;
      margin-top: auto;
      display: flex;
      justify-content: space-between;
      align-items: baseline;
    }

    .kit-price s { color: var(--muted); margin-left: 8px; font-size: .85em; }

    .kit-price .go {
      color: var(--copper);
      font-size: 0.8rem;
      opacity: 0;
      transform: translateX(-8px);
      transition: opacity .3s, transform .3s;
    }

    .kit:hover .kit-price .go { opacity: 1; transform: none; }

    /* =========================================================
       IN EVERY BOX
       Parents need detail. Set as a document, not icon cards.
       ========================================================= */
    .rows { padding-bottom: 9vh; }

    .row {
      display: grid;
      grid-template-columns: 70px 1fr 1.3fr;
      gap: 28px;
      padding: 30px 0;
      border-top: 1px solid var(--rule);
      align-items: start;
    }

    .row:last-child { border-bottom: 1px solid var(--rule); }
    .row h3 { font-size: 1.1rem; font-weight: 500; }
    .row p.body { font-size: 0.93rem; color: var(--muted); max-width: 46ch; }

    /* =========================================================
       COURSES
       Rows rather than cards. A course is a commitment, so it
       gets a line of its own with room to explain itself.
       ========================================================= */
    .course {
      display: grid;
      grid-template-columns: 70px 1.4fr 1fr auto;
      gap: 28px;
      padding: 30px 0;
      border-top: 1px solid var(--rule);
      align-items: center;
      text-decoration: none;
      color: inherit;
      transition: padding-left .35s cubic-bezier(0.22, 1, 0.36, 1);
    }

    .course:last-of-type { border-bottom: 1px solid var(--rule); }
    .course:hover { padding-left: 12px; }
    .course h3 { font-size: 1.15rem; font-weight: 500; }
    .course p { font-size: .9rem; color: var(--muted); max-width: 40ch; }

    .course .price {
      font-size: .95rem;
      white-space: nowrap;
      display: flex;
      align-items: baseline;
      gap: 14px;
    }

    .course .price .go { color: var(--copper); font-size: .8rem; opacity: 0; transition: opacity .3s; }
    .course:hover .price .go { opacity: 1; }

    /* =========================================================
       SCHOOLS
       An enquiry, not a checkout. Schools want a quote, a PO and
       a GST invoice - never a payment button.
       ========================================================= */
    .schools {
      display: grid;
      grid-template-columns: 1.2fr 1fr;
      gap: 60px;
      align-items: start;
      /* Less at the bottom than the top: the footer supplies its
         own space, and doubling them left a screen of nothing
         between this section and "Built in Pune". */
      padding: 9vh 0 5vh;
      border-top: 1px solid var(--rule);
    }

    .schools h2 {
      font-size: clamp(1.8rem, 5vw, 3.6rem);
      font-weight: 500;
      line-height: 1.02;
      letter-spacing: -0.035em;
      margin-bottom: 20px;
    }

    .schools p { font-size: .98rem; color: var(--muted); max-width: 44ch; }

    .schools-list { list-style: none; }

    .schools-list li {
      display: flex;
      justify-content: space-between;
      gap: 16px;
      padding: 13px 0;
      border-top: 1px solid var(--rule);
      font-size: .9rem;
    }

    .schools-list li span:last-child { color: var(--muted); text-align: right; }

    .cta {
      display: inline-block;
      margin-top: 26px;
      padding: 15px 30px;
      background: var(--ink);
      color: var(--paper);
      text-decoration: none;
      font-size: .82rem;
      letter-spacing: 0.12em;
      text-transform: uppercase;
      transition: background-color .3s;
    }

    .cta:hover { background: var(--copper); }

    /* ========== FOOTER ========== */
    footer { border-top: 1px solid var(--rule); padding-top: 40px; }

    /* Stops the big footer line running to the browser edge. */
    footer .wrap { padding-bottom: 0; }

    .foot {
      display: grid;
      grid-template-columns: 2fr 1fr 1fr 1fr;
      gap: 30px;
      padding-bottom: 50px;
    }

    .foot h4 {
      font-size: 0.66rem;
      font-weight: 500;
      letter-spacing: 0.16em;
      text-transform: uppercase;
      color: var(--muted);
      margin-bottom: 15px;
    }

    .foot a {
      display: block;
      color: var(--ink);
      text-decoration: none;
      font-size: 0.88rem;
      margin-bottom: 7px;
      transition: color .2s, transform .3s;
    }

    .foot a:hover { color: var(--copper); transform: translateX(4px); }

    .foot address {
      font-style: normal;
      font-size: 0.88rem;
      line-height: 1.75;
      color: var(--muted);
    }

    /* Now the first thing in the footer, not the last. Sized to
       match the wordmark so the page opens and closes on the same
       note. */
    .foot-big {
      font-size: clamp(2rem, 10.5vw, 9.5rem);
      font-weight: 500;
      letter-spacing: -0.05em;
      line-height: 0.88;
      padding-bottom: 48px;
      border-bottom: 1px solid var(--rule);
      margin-bottom: 44px;
    }

    .foot-bottom {
      display: flex;
      flex-wrap: wrap;
      gap: 14px;
      justify-content: space-between;
      padding: 20px 0 30px;
      border-top: 1px solid var(--rule);
    }

    a:focus-visible { outline: 2px solid var(--copper); outline-offset: 3px; }

    @media (max-width: 1000px) {
      :root { --gutter: 26px; }
      .schools { grid-template-columns: 1fr; gap: 34px; padding: 8vh 0; }
      .course { grid-template-columns: 50px 1fr; gap: 6px 20px; }
      .course .price { grid-column: 2; }
    }

    @media (max-width: 820px) {
      nav.top { display: none; }
      .wordmark { font-size: clamp(1.6rem, 12.4vw, 4rem); }
      .row { grid-template-columns: 1fr; gap: 8px; }
      .foot { grid-template-columns: 1fr 1fr; }
      .wordmark { font-size: 26vw; }
    }

    @media (prefers-reduced-motion: reduce) {
      .line > span { transform: none; }
      .fade { opacity: 1; transform: none; }
      .marquee-track { animation: none; }
    }


/* ===========================================================
   ACCOUNT PAGES  -  login, signup, account
   ===========================================================
   Same paper and ink as the rest of the site. The nav is
   deliberately stripped back to the wordmark: someone on a
   login page is doing one thing, and a full menu is just an
   invitation to wander off before finishing it.
   =========================================================== */
.auth-body {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

.auth-bar {
  border-bottom: 1px solid var(--rule);
  padding: 0 var(--gutter);
  height: 54px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
}

.auth-bar a {
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink);
  text-decoration: none;
}

.auth-bar .back {
  font-weight: 400;
  color: var(--muted);
}

.auth-bar .back:hover { color: var(--copper); }

.auth-main {
  flex: 1;
  max-width: var(--max);
  width: 100%;
  margin: 0 auto;
  padding: 0 var(--gutter);
  border-left: 1px solid var(--rule);
  border-right: 1px solid var(--rule);
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 80px;
  align-items: center;
}

/* The left side carries the type, the right the form. */
.auth-say h1 {
  font-weight: 500;
  font-size: clamp(2rem, 6vw, 4.6rem);
  line-height: 0.94;
  letter-spacing: -0.04em;
  margin: 18px 0 20px;
}

.auth-say p {
  color: var(--muted);
  max-width: 34ch;
  font-size: 0.98rem;
}

.auth-perks {
  list-style: none;
  margin-top: 32px;
  border-top: 1px solid var(--rule);
}

.auth-perks li {
  padding: 12px 0;
  border-bottom: 1px solid var(--rule);
  font-size: 0.9rem;
  color: var(--muted);
  display: flex;
  gap: 14px;
}

.auth-perks li b {
  color: var(--ink);
  font-weight: 500;
  min-width: 26px;
}

.auth-form { max-width: 400px; width: 100%; padding: 8vh 0; }

.auth-field { margin-bottom: 20px; }

.auth-field label {
  display: block;
  font-size: 0.66rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 8px;
}

/* Underlines rather than boxes. Boxed inputs would be the only
   rounded, filled shapes on the whole site. */
.auth-field input {
  width: 100%;
  font-family: var(--font);
  font-size: 1rem;
  color: var(--ink);
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--rule);
  padding: 10px 0;
  transition: border-color .25s;
}

.auth-field input:focus {
  outline: none;
  border-bottom-color: var(--ink);
}

.auth-field input::placeholder { color: #B9B8B2; }

.auth-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
  margin: 6px 0 26px;
  font-size: 0.84rem;
}

.auth-row a { color: var(--copper); text-decoration: none; }
.auth-row label { color: var(--muted); display: flex; gap: 8px; align-items: center; }

.auth-submit {
  width: 100%;
  font-family: var(--font);
  font-size: 0.82rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding: 16px;
  border: 0;
  background: var(--ink);
  color: var(--paper);
  cursor: pointer;
  transition: background-color .3s;
}

.auth-submit:hover { background: var(--copper); }

.auth-alt {
  margin-top: 24px;
  font-size: 0.88rem;
  color: var(--muted);
}

.auth-alt a { color: var(--ink); font-weight: 500; }

/* Messages */
.auth-msg {
  border: 1px solid var(--rule);
  border-left: 2px solid var(--copper);
  padding: 12px 16px;
  margin-bottom: 24px;
  font-size: 0.88rem;
}

.auth-msg.good { border-left-color: #2E7D5B; }
.auth-msg p + p { margin-top: 5px; }

.pw-wrap { position: relative; }
.pw-wrap input { padding-right: 54px; }

.pw-toggle {
  position: absolute;
  right: 0;
  bottom: 10px;
  background: none;
  border: 0;
  cursor: pointer;
  font-family: var(--font);
  font-size: 0.68rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
}

.pw-toggle:hover { color: var(--copper); }

/* ---------- the account page ---------- */
.acc-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 1px;
  background: var(--rule);
  border: 1px solid var(--rule);
  margin: 40px 0 12vh;
}

.acc-card { background: var(--paper); padding: 28px 26px; }

.acc-card h2 {
  font-size: 0.66rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 18px;
}

.acc-rows { list-style: none; }

.acc-rows li {
  display: flex;
  justify-content: space-between;
  gap: 14px;
  padding: 10px 0;
  border-top: 1px solid var(--rule);
  font-size: 0.9rem;
}

.acc-rows li:first-child { border-top: 0; }
.acc-rows li span:last-child { color: var(--muted); text-align: right; }

.acc-empty { color: var(--muted); font-size: 0.9rem; padding: 6px 0 18px; }

@media (max-width: 900px) {
  .auth-main { grid-template-columns: 1fr; gap: 0; }
  .auth-say { padding-top: 8vh; }
  .auth-form { padding: 4vh 0 10vh; max-width: none; }
  .auth-perks { display: none; }
}


/* ===========================================================
   SHOP PAGE
   ===========================================================
   No smooth scroll here, so the header is sticky rather than
   fixed over a transformed wrapper.
   =========================================================== */
.shop-page header {
  position: sticky;
}

.shop-main {
  min-height: 70vh;
  padding-top: 88px;
  padding-bottom: 12vh;
}

.shop-head {
  padding: 4vh 0 3vh;
}

.shop-head h1 {
  font-weight: 500;
  font-size: clamp(1.9rem, 6vw, 4rem);
  line-height: 0.96;
  letter-spacing: -0.04em;
  margin-top: 14px;
}

/* ---------- filters ---------- */
.filters {
  border-top: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
  padding: 18px 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px 26px;
  margin-bottom: 30px;
}

.filter-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
}

.filter-row .label {
  margin-right: 4px;
}

/* A chip, not a dropdown. Every option visible at once means a
   parent can see the whole shop is only three age groups wide,
   without opening anything. */
.chip {
  font-size: 0.78rem;
  letter-spacing: 0.06em;
  text-decoration: none;
  color: var(--ink);
  padding: 6px 13px;
  border: 1px solid var(--rule);
  border-radius: 100px;
  transition: border-color .2s, background-color .2s, color .2s;
}

.chip:hover {
  border-color: var(--ink);
}

.chip.on {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--paper);
}

.count-note {
  margin-left: auto;
}

/* ---------- empty states ----------
   An empty screen should say what to do next, not just report
   that there is nothing here. */
.shop-empty {
  padding: 10vh 0;
  max-width: 46ch;
}

.shop-empty h2 {
  font-weight: 500;
  font-size: clamp(1.4rem, 3.5vw, 2.2rem);
  letter-spacing: -0.03em;
  margin-bottom: 12px;
}

.shop-empty p {
  color: var(--muted);
  margin-bottom: 26px;
}

/* Out of stock reads as a fact, not as an error. */
.kit-price .sold {
  font-size: 0.78rem;
  color: var(--muted);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

@media (max-width: 700px) {
  .filters { gap: 10px 16px; }
  .count-note { margin-left: 0; width: 100%; }
}


/* ===========================================================
   ADD TO CART  -  on the shop grid
   ===========================================================
   The card is a link and the button is a form. A form cannot
   sit inside a link, so each cell holds the two as siblings.
   =========================================================== */
.kit-cell {
  background: var(--paper);
  display: flex;
  flex-direction: column;
}

.kit-cell .kit {
  flex: 1;
  padding-bottom: 16px;
}

.add-form {
  padding: 0 20px 22px;
}

.add-btn {
  width: 100%;
  font-family: var(--font);
  font-size: 0.74rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding: 12px;
  border: 1px solid var(--ink);
  background: transparent;
  color: var(--ink);
  cursor: pointer;
  transition: background-color .25s, color .25s;
}

.add-btn:hover {
  background: var(--ink);
  color: var(--paper);
}

/* ===========================================================
   CART PAGE
   =========================================================== */
.cart-layout {
  display: grid;
  grid-template-columns: 1fr 320px;
  gap: 50px;
  align-items: start;
  padding-bottom: 6vh;
}

.cart-lines {
  border-top: 1px solid var(--rule);
}

.cart-line {
  display: grid;
  grid-template-columns: 88px 1fr auto auto auto;
  gap: 20px;
  align-items: center;
  padding: 20px 0;
  border-bottom: 1px solid var(--rule);
}

.cart-img {
  width: 88px;
  aspect-ratio: 4 / 3;
  background: #E3E2DC;
  overflow: hidden;
}

.cart-img img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.cart-name {
  font-size: 1rem;
  font-weight: 500;
  color: var(--ink);
  text-decoration: none;
  display: block;
  margin-bottom: 3px;
}

.cart-name:hover { color: var(--copper); }

/* Flagged, not silently removed. Somebody has to be told why
   their cart changed. */
.cart-problem {
  font-size: 0.8rem;
  color: var(--copper);
  margin-top: 4px;
}

.cart-qty {
  display: flex;
  align-items: center;
  gap: 8px;
}

.cart-qty input {
  width: 58px;
  font-family: var(--font);
  font-size: 0.92rem;
  text-align: center;
  padding: 8px 4px;
  border: 1px solid var(--rule);
  background: var(--paper);
  color: var(--ink);
}

.cart-qty input:focus {
  outline: none;
  border-color: var(--ink);
}

.link-btn {
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  font-family: var(--font);
  font-size: 0.72rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
}

.link-btn:hover { color: var(--copper); }

.cart-price {
  font-size: 0.98rem;
  white-space: nowrap;
  min-width: 80px;
  text-align: right;
}

.cart-summary {
  border: 1px solid var(--rule);
  padding: 26px 24px;
  position: sticky;
  top: 80px;
}

.cart-summary h2 { margin-bottom: 16px; }

.cart-total {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding: 16px 0 22px;
  border-top: 1px solid var(--rule);
  margin-top: 12px;
}

.cart-total strong {
  font-size: 1.3rem;
  font-weight: 500;
  letter-spacing: -0.02em;
}

@media (max-width: 900px) {
  .cart-layout { grid-template-columns: 1fr; gap: 30px; }
  .cart-summary { position: static; }
}

@media (max-width: 640px) {
  .cart-line {
    grid-template-columns: 64px 1fr;
    gap: 12px;
  }
  .cart-img { width: 64px; }
  .cart-qty, .cart-price, .cart-remove { grid-column: 2; }
  .cart-price { text-align: left; }
}


/* ===========================================================
   HERO BACKGROUND
   ===========================================================
   A faint circuit routed behind the wordmark, reacting to the
   cursor. Deliberately quiet: at this contrast it reads as
   texture, and the type stays the thing you look at. Turn the
   opacity up and it starts competing.
   =========================================================== */
.hero {
  position: relative;
}

.trace-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  pointer-events: none;   /* never blocks a click */
}

/* Everything in the hero sits above the canvas. */
.hero .wordmark,
.hero .meta {
  position: relative;
  z-index: 1;
}

/* ---------- skip the intro ---------- */
.skip-intro {
  background: none;
  border: 0;
  padding: 4px 0;
  cursor: pointer;
  font-family: var(--font);
  font-size: 0.66rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(239, 238, 233, 0.62);
  transition: color .2s;
}

.skip-intro:hover {
  color: var(--paper);
}

@media (prefers-reduced-motion: reduce) {
  .trace-canvas { display: none; }
}


/* ===========================================================
   PRODUCT PAGE
   =========================================================== */
.crumbs {
  font-size: 0.78rem;
  color: var(--muted);
  padding: 4px 0 22px;
}

.crumbs a { color: var(--muted); text-decoration: none; }
.crumbs a:hover { color: var(--copper); }
.crumbs span { color: var(--ink); }

.kit-page {
  display: grid;
  grid-template-columns: 1.1fr 1fr;
  gap: 56px;
  align-items: start;
  padding-bottom: 8vh;
}

/* ---------- gallery ---------- */
.kit-main {
  aspect-ratio: 4 / 3;
  background: #E3E2DC;
  overflow: hidden;
  border: 1px solid var(--rule);
}

.kit-main img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.kit-thumbs {
  display: flex;
  gap: 10px;
  margin-top: 10px;
  flex-wrap: wrap;
}

.kit-thumb {
  width: 74px;
  aspect-ratio: 4 / 3;
  padding: 0;
  border: 1px solid var(--rule);
  background: #E3E2DC;
  cursor: pointer;
  overflow: hidden;
  transition: border-color .2s;
}

.kit-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.kit-thumb:hover { border-color: var(--muted); }

/* The one being shown. Without this you lose track of which
   thumbnail is live. */
.kit-thumb.on { border-color: var(--ink); }

/* ---------- details ---------- */
.kit-detail h1 {
  font-weight: 500;
  font-size: clamp(1.7rem, 4vw, 2.8rem);
  line-height: 1.02;
  letter-spacing: -0.035em;
  margin: 10px 0 14px;
}

.kit-lede {
  color: var(--muted);
  font-size: 1rem;
  max-width: 40ch;
  margin-bottom: 24px;
}

.kit-cost {
  display: flex;
  align-items: baseline;
  gap: 12px;
  padding: 18px 0 10px;
  border-top: 1px solid var(--rule);
}

.kit-cost .now {
  font-size: 1.8rem;
  font-weight: 500;
  letter-spacing: -0.03em;
}

.kit-cost s { color: var(--muted); }

.kit-cost .off {
  font-size: 0.76rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--copper);
}

.kit-stock { font-size: 0.88rem; color: var(--muted); margin-bottom: 26px; }
.kit-stock .in  { color: #2E7D5B; }
.kit-stock .low { color: var(--copper); }
.kit-stock .out { color: var(--copper); }

/* ---------- buying ---------- */
.kit-buy {
  display: flex;
  gap: 12px;
  align-items: flex-end;
  flex-wrap: wrap;
  padding-bottom: 26px;
  border-bottom: 1px solid var(--rule);
}

.kit-buy .qty { display: block; }
.kit-buy .qty .label { display: block; margin-bottom: 6px; }

.kit-buy input[type="number"] {
  width: 74px;
  font-family: var(--font);
  font-size: 0.98rem;
  text-align: center;
  padding: 13px 6px;
  border: 1px solid var(--rule);
  background: var(--paper);
  color: var(--ink);
}

.kit-buy input:focus { outline: none; border-color: var(--ink); }

.btn-add, .btn-buy {
  font-family: var(--font);
  font-size: 0.8rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding: 15px 26px;
  cursor: pointer;
  transition: background-color .25s, color .25s;
  flex: 1;
  min-width: 150px;
}

/* Outlined and filled: Buy now is the louder of the two, so
   there is never a question which is the main action. */
.btn-add {
  background: transparent;
  border: 1px solid var(--ink);
  color: var(--ink);
}

.btn-add:hover { background: var(--ink); color: var(--paper); }

.btn-buy {
  background: var(--ink);
  border: 1px solid var(--ink);
  color: var(--paper);
}

.btn-buy:hover { background: var(--copper); border-color: var(--copper); }

.kit-soldout {
  font-size: 0.92rem;
  color: var(--muted);
  padding-bottom: 24px;
  border-bottom: 1px solid var(--rule);
}

.kit-soldout a { color: var(--copper); }

/* ---------- outcome and syllabus ---------- */
.kit-outcome, .kit-syllabus {
  padding: 20px 0;
  border-bottom: 1px solid var(--rule);
}

.kit-outcome p:last-child { font-size: 1rem; margin-top: 8px; }

.kit-syllabus ul { list-style: none; margin-top: 8px; }

.kit-syllabus li {
  font-size: 0.9rem;
  color: var(--muted);
  padding: 5px 0;
}

/* ---------- lower half ---------- */
.kit-lower {
  display: grid;
  grid-template-columns: 1.2fr 1fr;
  gap: 56px;
  padding: 2vh 0 8vh;
  border-top: 1px solid var(--rule);
  padding-top: 40px;
}

.kit-body {
  font-size: 0.98rem;
  line-height: 1.7;
  color: var(--muted);
  margin-top: 12px;
  max-width: 60ch;
}

.kit-contents { list-style: none; margin-top: 12px; }

.kit-contents li {
  display: flex;
  gap: 14px;
  padding: 11px 0;
  border-bottom: 1px solid var(--rule);
  font-size: 0.93rem;
}

.kit-contents .q {
  color: var(--muted);
  min-width: 34px;
  font-variant-numeric: tabular-nums;
}

.kit-contents a { color: var(--ink); text-decoration: none; font-weight: 500; }
.kit-contents a:hover { color: var(--copper); }

/* ---------- related ---------- */
.kit-related { padding-bottom: 10vh; }

.kit-related .section-head {
  padding: 0 0 18px;
  border-bottom: 1px solid var(--rule);
  margin-bottom: 0;
}

@media (max-width: 900px) {
  .kit-page, .kit-lower { grid-template-columns: 1fr; gap: 30px; }
  .kit-lower { padding-top: 26px; }
}


/* ===========================================================
   ADMIN
   ===========================================================
   A fixed sidebar and a scrolling main area. Denser than the
   shop: this is a working tool, so information per screen
   matters more than air.
   =========================================================== */
.admin-body {
  background: var(--paper);
  color: var(--ink);
}

/* ---------- the sidebar ---------- */
.admin-side {
  position: fixed;
  top: 0;
  left: 0;
  width: 232px;
  height: 100vh;
  background: var(--ink);
  display: flex;
  flex-direction: column;
  z-index: 60;
}

.side-brand {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 18px 18px 16px;
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--paper);
  text-decoration: none;
  border-bottom: 1px solid rgba(239, 238, 233, 0.12);
  line-height: 1.5;
}

.side-brand span {
  display: block;
  color: var(--copper);
  font-size: 0.66rem;
  letter-spacing: 0.2em;
}

/* Drop a logo file in and use this instead of the wordmark. */
.side-logo { max-width: 150px; height: auto; display: block; }

.side-nav {
  flex: 1;
  overflow-y: auto;
  padding: 16px 12px;
}

.side-item {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 10px 12px;
  margin-bottom: 2px;
  border-radius: 4px;
  font-size: 0.86rem;
  color: rgba(239, 238, 233, 0.62);
  text-decoration: none;
  transition: background-color .18s, color .18s;
}

.side-item svg {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  stroke: currentColor;
  fill: none;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.side-item:hover { background: rgba(239, 238, 233, 0.07); color: var(--paper); }

/* The page you are on. A panel without this is disorienting. */
.side-item.on {
  background: rgba(239, 238, 233, 0.1);
  color: var(--paper);
  box-shadow: inset 2px 0 0 var(--copper);
}

/* ---------- a heading with children ---------- */
.side-heading {
  font-size: 0.62rem;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(239, 238, 233, 0.38);
  padding: 20px 12px 8px;
}

.side-sub {
  display: block;
  padding: 8px 12px 8px 24px;
  margin-bottom: 1px;
  border-radius: 4px;
  font-size: 0.84rem;
  color: rgba(239, 238, 233, 0.58);
  text-decoration: none;
  position: relative;
  transition: background-color .18s, color .18s;
}

/* A short rule joining each child to its heading. */
.side-sub::before {
  content: "";
  position: absolute;
  left: 12px;
  top: 50%;
  width: 6px;
  height: 1px;
  background: rgba(239, 238, 233, 0.25);
}

.side-sub:hover { background: rgba(239, 238, 233, 0.07); color: var(--paper); }

.side-sub.on {
  background: rgba(239, 238, 233, 0.1);
  color: var(--paper);
}

.side-sub.on::before { background: var(--copper); width: 10px; }

.side-foot {
  border-top: 1px solid rgba(239, 238, 233, 0.12);
  padding: 14px 22px 18px;
  display: grid;
  gap: 9px;
}

.side-foot a {
  font-size: 0.74rem;
  letter-spacing: 0.06em;
  color: rgba(239, 238, 233, 0.55);
  text-decoration: none;
}

.side-foot a:hover { color: var(--paper); }
.side-foot a.out:hover { color: var(--copper); }

/* ---------- the main area ---------- */
.admin-main {
  margin-left: 232px;
  min-height: 100vh;
  padding: 34px 38px 90px;
  max-width: 1420px;
}

.admin-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  padding-bottom: 20px;
  border-bottom: 1px solid var(--rule);
  margin-bottom: 28px;
}

.admin-head h1 {
  font-size: 1.5rem;
  font-weight: 500;
  letter-spacing: -0.025em;
}

.admin-head a { color: var(--muted); text-decoration: none; }
.admin-head a:hover { color: var(--copper); }

/* ---------- mobile ---------- */
.admin-menu-btn {
  display: none;
  position: fixed;
  top: 14px;
  left: 14px;
  z-index: 70;
  width: 40px;
  height: 40px;
  border: 0;
  border-radius: 5px;
  background: var(--ink);
  color: var(--paper);
  cursor: pointer;
  align-items: center;
  justify-content: center;
}

.admin-menu-btn svg {
  width: 19px; height: 19px;
  stroke: currentColor; fill: none; stroke-width: 2; stroke-linecap: round;
}

.admin-scrim {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(22, 24, 26, 0.5);
  z-index: 55;
}

.admin-scrim.show { display: block; }

@media (max-width: 900px) {
  .admin-menu-btn { display: flex; }
  .admin-side { transform: translateX(-100%); transition: transform .28s ease; }
  .admin-side.open { transform: none; }
  .admin-main { margin-left: 0; padding: 68px 20px 70px; }
}

/* ===========================================================
   ADMIN COMPONENTS
   =========================================================== */
.admin-btn {
  display: inline-block;
  font-family: var(--font);
  font-size: 0.74rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding: 11px 20px;
  background: var(--ink);
  color: var(--paper);
  border: 1px solid var(--ink);
  text-decoration: none;
  cursor: pointer;
  transition: background-color .25s, border-color .25s;
}

.admin-btn:hover { background: var(--copper); border-color: var(--copper); }
.admin-btn.ghost { background: transparent; color: var(--ink); }
.admin-btn.ghost:hover { background: var(--ink); color: var(--paper); }
.admin-btn.wide { width: 100%; text-align: center; }

/* ---------- tables ---------- */
.admin-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.88rem;
}

.admin-table th {
  text-align: left;
  font-size: 0.62rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
  padding: 10px 14px 10px 0;
  border-bottom: 1px solid var(--rule);
}

.admin-table td {
  padding: 13px 14px 13px 0;
  border-bottom: 1px solid var(--rule);
  vertical-align: middle;
}

.admin-table tbody tr:hover { background: rgba(22, 24, 26, 0.025); }
.admin-table td a { color: var(--ink); text-decoration: none; font-weight: 500; }
.admin-table td a:hover { color: var(--copper); }
.admin-table .num { text-align: right; padding-right: 0; }
.admin-table .mono { font-variant-numeric: tabular-nums; color: var(--muted); font-size: 0.8rem; }
.admin-table .bad { color: var(--copper); font-weight: 500; }
.row-actions form { display: flex; gap: 14px; justify-content: flex-end; }

/* ---------- status pills ---------- */
.pill {
  font-size: 0.62rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 3px 9px;
  border: 1px solid var(--rule);
  color: var(--muted);
  white-space: nowrap;
}

.pill.active   { border-color: #2E7D5B; color: #2E7D5B; }
.pill.draft    { border-color: var(--muted); }
.pill.archived { border-color: var(--rule); color: #A9A8A2; }
.pill.pending  { border-color: var(--copper); color: var(--copper); }
.pill.paid     { border-color: #2E7D5B; color: #2E7D5B; }

/* ---------- filters ---------- */
.admin-filters {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: center;
  margin-bottom: 18px;
}

.admin-filters input[type="search"],
.admin-filters select {
  font-family: var(--font);
  font-size: 0.88rem;
  padding: 9px 12px;
  border: 1px solid var(--rule);
  background: #fff;
  color: var(--ink);
}

.admin-filters input[type="search"] { min-width: 240px; }

.admin-empty { color: var(--muted); padding: 28px 0; font-size: 0.92rem; }
.admin-empty a { color: var(--copper); }

.admin-links { display: grid; gap: 10px; }

.admin-links a {
  display: block;
  padding: 13px 15px;
  border: 1px solid var(--rule);
  background: #fff;
  color: var(--ink);
  text-decoration: none;
  font-size: 0.9rem;
  transition: border-color .2s, padding-left .25s;
}

.admin-links a:hover { border-color: var(--ink); padding-left: 21px; }


/* ===========================================================
   ADMIN FORM
   =========================================================== */
.form-cols {
  display: grid;
  grid-template-columns: 1fr 320px;
  gap: 32px;
  align-items: start;
}

.admin-form fieldset {
  border: 1px solid var(--rule);
  background: #fff;
  padding: 20px 20px 12px;
  margin-bottom: 20px;
}

.admin-form legend { padding: 0 8px; }

.admin-form label {
  display: block;
  font-size: 0.68rem;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 16px;
}

/* Hides a repeated label visually but keeps it for screen
   readers, so row two onward is not a wall of "Item / Qty". */
.admin-form label.sr { font-size: 0; letter-spacing: 0; margin-bottom: 12px; }

.admin-form input[type="text"],
.admin-form input[type="number"],
.admin-form select,
.admin-form textarea {
  display: block;
  width: 100%;
  margin-top: 6px;
  font-family: var(--font);
  font-size: 0.94rem;
  text-transform: none;
  letter-spacing: 0;
  color: var(--ink);
  background: #fff;
  border: 1px solid var(--rule);
  padding: 10px 12px;
}

.admin-form textarea { resize: vertical; line-height: 1.55; }

.admin-form input:focus,
.admin-form select:focus,
.admin-form textarea:focus { outline: none; border-color: var(--ink); }

.admin-form .two { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.admin-form .two.narrow-second { grid-template-columns: 1fr 92px; }

.admin-form label.check {
  display: flex;
  align-items: center;
  gap: 9px;
  text-transform: none;
  letter-spacing: 0;
  font-size: 0.88rem;
  color: var(--ink);
}

.admin-form .hint {
  font-size: 0.82rem;
  color: var(--muted);
  text-transform: none;
  letter-spacing: 0;
  margin-bottom: 16px;
  line-height: 1.55;
}

.admin-form code { background: #EFEEE9; padding: 1px 5px; font-size: 0.9em; }

/* ---------- the type picker ----------
   Cards rather than a dropdown. This choice decides which
   sections below appear, so it deserves to be visible and
   explained rather than hidden in a select.
   ========================================================= */
.type-pick {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 10px;
  margin-bottom: 6px;
}

.type-opt {
  margin: 0;
  text-transform: none;
  letter-spacing: 0;
  cursor: pointer;
}

.type-opt input { position: absolute; opacity: 0; pointer-events: none; }

.type-opt span {
  display: block;
  border: 1px solid var(--rule);
  padding: 13px 14px;
  transition: border-color .2s, background-color .2s;
}

.type-opt strong {
  display: block;
  font-size: 0.92rem;
  font-weight: 500;
  color: var(--ink);
  margin-bottom: 3px;
}

.type-opt em {
  font-style: normal;
  font-size: 0.78rem;
  color: var(--muted);
  line-height: 1.45;
}

.type-opt:hover span { border-color: var(--muted); }

/* :has() lets the wrapper react to its own radio being checked,
   with no JavaScript. */
.type-opt:has(input:checked) span {
  border-color: var(--ink);
  background: #fff;
  box-shadow: inset 3px 0 0 var(--copper);
}


/* ===========================================================
   ANALYTICS
   =========================================================== */
.metrics {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(168px, 1fr));
  gap: 12px;
  margin-bottom: 28px;
}

.metric {
  background: #fff;
  border: 1px solid var(--rule);
  padding: 18px 18px 16px;
}

.metric .k {
  font-size: 0.62rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
  display: block;
  margin-bottom: 10px;
}

.metric .v {
  font-size: 1.7rem;
  font-weight: 500;
  letter-spacing: -0.03em;
  line-height: 1;
  display: block;
}

.metric .sub { font-size: 0.76rem; color: var(--muted); margin-top: 7px; display: block; }

/* Only the ones with something to act on. A dashboard where
   everything is highlighted highlights nothing. */
.metric.hot { border-color: var(--copper); }
.metric.hot .v { color: var(--copper); }

.panel {
  background: #fff;
  border: 1px solid var(--rule);
  padding: 20px 22px 18px;
  margin-bottom: 20px;
}

.panel-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 18px;
}

.panel-head h2 {
  font-size: 0.66rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
}

.panel-head .big {
  font-size: 1.1rem;
  font-weight: 500;
  letter-spacing: -0.02em;
  color: var(--ink);
}

.chart { width: 100%; height: auto; display: block; }

.chart .ct { font-family: var(--font); font-size: 10px; fill: var(--muted); }
.chart .grid-line { stroke: var(--rule); stroke-width: 1; }

/* Hovering a bar shows its date and figure through the <title>
   inside each rect - no tooltip code needed. */
.chart rect { transition: opacity .15s; }
.chart rect:hover { opacity: 0.68; }

.range { display: flex; gap: 6px; }

.range .chip {
  font-size: 0.72rem;
  padding: 6px 12px;
  border: 1px solid var(--rule);
  border-radius: 0;
  color: var(--ink);
  text-decoration: none;
  background: #fff;
}

.range .chip.on { background: var(--ink); border-color: var(--ink); color: var(--paper); }

.two-panels {
  display: grid;
  grid-template-columns: 1.25fr 1fr;
  gap: 20px;
  align-items: start;
}

/* A bar inside a table cell, showing share without a second
   chart. Cheap, and reads instantly. */
.inline-bar {
  display: block;
  height: 4px;
  background: var(--copper);
  opacity: 0.35;
  margin-top: 5px;
}

@media (max-width: 1000px) {
  .form-cols, .two-panels { grid-template-columns: 1fr; }
}

/* ---------- uploads ---------- */
.img-existing {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
  gap: 10px;
  margin-bottom: 14px;
}

.img-tile {
  margin: 0;
  text-transform: none;
  letter-spacing: 0;
  border: 1px solid var(--rule);
  overflow: hidden;
  cursor: pointer;
}

.img-tile img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  display: block;
}

.img-del {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 8px 10px;
  font-size: 0.76rem;
  color: var(--muted);
  border-top: 1px solid var(--rule);
}

/* The tile dims once it is marked for removal, so it is obvious
   at a glance what will disappear on save. */
.img-tile:has(input:checked) { border-color: var(--copper); }
.img-tile:has(input:checked) img { opacity: 0.35; }
.img-tile:has(input:checked) .img-del { color: var(--copper); }

.file-row { margin-bottom: 10px; }

.file-row input[type="file"] {
  width: 100%;
  font-family: var(--font);
  font-size: 0.86rem;
  padding: 9px 10px;
  border: 1px dashed var(--rule);
  background: #fff;
  color: var(--muted);
}

.file-row input[type="file"]:hover { border-color: var(--muted); }

.admin-btn.small {
  font-size: 0.68rem;
  padding: 8px 14px;
  margin-bottom: 12px;
}

.admin-btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

/* ---------- dimensions ---------- */
.dims {
  display: grid;
  grid-template-columns: 1fr auto 1fr auto 1fr;
  gap: 6px;
  align-items: center;
  margin-bottom: 10px;
}

.dims input {
  margin-top: 0 !important;
  text-align: center;
}

.dims span { color: var(--muted); font-size: 0.9rem; }

/* Turns copper when volumetric weight beats actual - that is the
   case where the courier charges more than you expect. */
.admin-form .hint.warn { color: var(--copper); }

/* ---------- see the shop ----------
   The one link the sidebar cannot replace, so it gets the whole
   panel rather than being a line in a list.
   ========================================================= */
.see-shop {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 8px;
  min-height: 100%;
  padding: 30px 26px;
  background: var(--ink);
  color: var(--paper);
  text-decoration: none;
  transition: background-color .3s;
}

.see-shop:hover { background: var(--copper); }

.see-shop .k {
  font-size: 0.62rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(239, 238, 233, 0.6);
}

.see-shop .v {
  font-size: 1.6rem;
  font-weight: 500;
  letter-spacing: -0.03em;
  line-height: 1.05;
}

.see-shop .sub {
  font-size: 0.8rem;
  color: rgba(239, 238, 233, 0.6);
  max-width: 30ch;
}


/* ===========================================================
   COURSES
   ===========================================================
   Rows, not cards. A course is a commitment rather than an
   impulse buy, so each one gets a full line with room to
   explain itself.
   =========================================================== */
.page-lede {
  color: var(--muted);
  max-width: 52ch;
  margin-top: 14px;
  font-size: 1rem;
}

.course-list { border-top: 1px solid var(--rule); }

.course-row {
  display: grid;
  grid-template-columns: 130px 1fr 160px;
  gap: 30px;
  align-items: start;
  padding: 26px 0;
  border-bottom: 1px solid var(--rule);
  text-decoration: none;
  color: inherit;
  transition: padding-left .3s cubic-bezier(0.22, 1, 0.36, 1);
}

.course-row:hover { padding-left: 12px; }

.course-meta { display: grid; gap: 5px; }

.course-body h2 {
  font-size: 1.25rem;
  font-weight: 500;
  letter-spacing: -0.02em;
  margin-bottom: 7px;
}

.course-body p { color: var(--muted); font-size: 0.95rem; max-width: 52ch; }

.course-facts {
  font-size: 0.8rem !important;
  color: var(--muted);
  margin-top: 12px;
}

.course-facts .cert { color: var(--copper); }

.course-cost { text-align: right; display: grid; gap: 4px; }

.course-cost .now {
  font-size: 1.25rem;
  font-weight: 500;
  letter-spacing: -0.02em;
}

.course-cost s { color: var(--muted); font-size: 0.86rem; }

.course-cost .go {
  font-size: 0.76rem;
  color: var(--copper);
  opacity: 0;
  transition: opacity .25s;
}

.course-row:hover .course-cost .go { opacity: 1; }

/* ===========================================================
   ONE COURSE
   =========================================================== */
.course-page {
  display: grid;
  grid-template-columns: 1fr 330px;
  gap: 56px;
  align-items: start;
  padding-bottom: 10vh;
}

.course-main h1 {
  font-weight: 500;
  font-size: clamp(1.8rem, 4.4vw, 3rem);
  line-height: 1.02;
  letter-spacing: -0.035em;
  margin: 10px 0 16px;
}

.course-lede { font-size: 1.05rem; max-width: 46ch; margin-bottom: 18px; }

.course-desc {
  color: var(--muted);
  line-height: 1.7;
  max-width: 60ch;
  margin-bottom: 40px;
}

/* ---------- the syllabus ---------- */
.syllabus .section-head { padding: 0 0 16px; margin-bottom: 0; }

/* <details> gives open and close with no JavaScript at all. */
.mod {
  border-bottom: 1px solid var(--rule);
}

.mod summary {
  display: grid;
  grid-template-columns: 34px 1fr auto;
  gap: 14px;
  align-items: baseline;
  padding: 16px 0;
  cursor: pointer;
  list-style: none;
}

/* Hides the default triangle in every browser. */
.mod summary::-webkit-details-marker { display: none; }
.mod summary::marker { content: ''; }

.mod-n {
  font-size: 0.76rem;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.mod-t strong {
  display: block;
  font-size: 1rem;
  font-weight: 500;
  margin-bottom: 3px;
}

.mod-t em {
  font-style: normal;
  font-size: 0.86rem;
  color: var(--muted);
}

.mod-c { font-size: 0.76rem; color: var(--muted); white-space: nowrap; }

.mod[open] .mod-n { color: var(--copper); }

.lessons { list-style: none; padding: 0 0 16px 48px; }

.lessons li {
  display: flex;
  align-items: baseline;
  gap: 12px;
  padding: 8px 0;
  font-size: 0.9rem;
  border-top: 1px solid var(--rule);
}

.lessons li:first-child { border-top: 0; }
.l-t { flex: 1; }

.l-free {
  font-size: 0.66rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--copper);
  border: 1px solid var(--copper);
  padding: 2px 7px;
}

.l-m { color: var(--muted); font-size: 0.8rem; white-space: nowrap; }

/* ---------- enrolling ---------- */
.course-side { position: sticky; top: 80px; display: grid; gap: 18px; }

.enrol-box { border: 1px solid var(--rule); padding: 24px 22px; background: #fff; }

.enrol-price {
  font-size: 2rem;
  font-weight: 500;
  letter-spacing: -0.03em;
  margin-bottom: 20px;
}

.enrol-price s { font-size: 1rem; color: var(--muted); margin-left: 10px; }

.enrol-facts { list-style: none; margin-bottom: 22px; }

.enrol-facts li {
  display: flex;
  justify-content: space-between;
  gap: 14px;
  padding: 9px 0;
  border-top: 1px solid var(--rule);
  font-size: 0.88rem;
}

.enrol-facts li span:first-child { color: var(--muted); }

.enrol-note { font-size: 0.8rem; color: var(--muted); margin-top: 12px; line-height: 1.5; }
.enrol-done { color: #2E7D5B; font-size: 0.92rem; margin-bottom: 14px; }

/* ---------- the kit it needs ---------- */
.needs-kit { border: 1px solid var(--rule); padding: 20px 20px 18px; background: #fff; }

.needs-row {
  display: flex;
  gap: 14px;
  align-items: center;
  text-decoration: none;
  color: inherit;
  margin: 12px 0 14px;
}

.needs-row img {
  width: 68px;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border: 1px solid var(--rule);
}

.needs-row strong { display: block; font-size: 0.94rem; font-weight: 500; }
.needs-row em { font-style: normal; font-size: 0.86rem; color: var(--muted); }

@media (max-width: 900px) {
  .course-page { grid-template-columns: 1fr; gap: 30px; }
  .course-side { position: static; }
  .course-row { grid-template-columns: 1fr; gap: 10px; }
  .course-cost { text-align: left; grid-auto-flow: column; justify-content: start; gap: 14px; }
}

/* ===========================================================
   CURRICULUM BUILDER
   =========================================================== */
.quick-add {
  border: 1px solid var(--rule);
  background: #fff;
  padding: 16px 18px;
  margin-bottom: 22px;
}

.qa-row {
  display: flex;
  gap: 12px;
  align-items: flex-end;
  flex-wrap: wrap;
}

.qa-row label { flex: 1; min-width: 180px; margin-bottom: 0; }
.qa-row .admin-btn { flex-shrink: 0; }

.qa-row.sub {
  border-top: 1px solid var(--rule);
  margin-top: 14px;
  padding-top: 14px;
  align-items: center;
}

.qa-row.sub input[type="text"],
.qa-row.sub input[type="number"] {
  margin-top: 0;
  font-family: var(--font);
  font-size: 0.9rem;
  padding: 9px 11px;
  border: 1px solid var(--rule);
  background: #fff;
  color: var(--ink);
}

.qa-row.sub input[type="text"]:first-child { flex: 1.4; min-width: 180px; }
.qa-row.sub input[type="text"]:nth-child(2) { flex: 1.6; min-width: 200px; }

.mod-block { margin-bottom: 20px; }

.mod-title-row { margin-bottom: 14px; }
.mod-title-row strong { font-size: 1rem; font-weight: 500; }
.mod-title-row em {
  font-style: normal;
  display: block;
  font-size: 0.86rem;
  color: var(--muted);
  margin-top: 3px;
}

.lesson-table { width: 100%; border-collapse: collapse; font-size: 0.86rem; }

.lesson-table th {
  text-align: left;
  font-size: 0.6rem;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
  padding: 0 8px 8px 0;
  border-bottom: 1px solid var(--rule);
}

.lesson-table td { padding: 7px 8px 7px 0; border-bottom: 1px solid var(--rule); }
.lesson-table td.mid { text-align: center; }

.lesson-table input[type="text"],
.lesson-table input[type="number"] {
  width: 100%;
  margin-top: 0;
  font-family: var(--font);
  font-size: 0.86rem;
  padding: 7px 9px;
  border: 1px solid var(--rule);
  background: #fff;
  color: var(--ink);
}

.lesson-table input:focus { outline: none; border-color: var(--ink); }

/* A lesson with no video is the one thing that will disappoint
   a student who has paid, so it is marked while you edit. */
.lesson-table input.needs {
  border-color: var(--copper);
  background: rgba(180, 96, 47, 0.04);
}

/* A form cannot be nested in another, so the delete and add
   forms live at the end of the page and are reached by id. */
.hidden-form { display: none; }

/* ---------- courses on a kit page ----------
   Reuses the course row from courses.php, so a course looks the
   same wherever it appears. */
.kit-courses {
  border-top: 1px solid var(--rule);
  padding-top: 34px;
  margin-bottom: 4vh;
}

.kit-courses .section-head {
  padding: 0 0 14px;
  border-bottom: 1px solid var(--rule);
  margin-bottom: 0;
}

.kit-courses .course-row { border-bottom: 1px solid var(--rule); }

/* ---------- courses in the cart ---------- */
.cart-line.is-course .cart-img { background: transparent; }

/* A course has no photograph, so it gets a mark rather than an
   empty grey rectangle. */
.course-mark {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  border: 1px solid var(--rule);
}

.course-mark svg {
  width: 26px;
  height: 26px;
  stroke: var(--muted);
  fill: none;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.cart-qty-fixed { text-align: center; min-width: 58px; }

.enrol-buy { display: grid; gap: 9px; }
.enrol-buy .btn-add, .enrol-buy .btn-buy { width: 100%; min-width: 0; }

/* ===========================================================
   KITS BY AGE
   =========================================================== */
.band-block { padding-bottom: 6vh; }

.band-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 20px;
  padding: 5vh 0 18px;
  border-bottom: 1px solid var(--rule);
}

.band-head h2 {
  font-size: clamp(1.4rem, 3.2vw, 2.2rem);
  font-weight: 500;
  letter-spacing: -0.03em;
}

.band-head .label { margin-top: 5px; }

/* Anchors land under the sticky header without this. */
.band-block { scroll-margin-top: 78px; }

/* The outcome line on a card. What a child ends up with is more
   persuasive than what is in the box, and it fits. */
.kit-outcome-line {
  font-size: 0.84rem;
  color: var(--muted);
  line-height: 1.45;
  margin: 2px 0 10px;
}

/* ---------- through to the shop ---------- */
.to-shop {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 30px;
  flex-wrap: wrap;
  border: 1px solid var(--rule);
  padding: 34px 32px;
  margin: 4vh 0 10vh;
}

.to-shop h2 {
  font-size: clamp(1.2rem, 2.6vw, 1.7rem);
  font-weight: 500;
  letter-spacing: -0.025em;
  margin: 10px 0 8px;
}

.to-shop p { color: var(--muted); font-size: 0.94rem; max-width: 44ch; }

@media (max-width: 700px) {
  .to-shop { padding: 24px 20px; }
}

/* ---------- the mark in the sidebar ---------- */
.side-mark { width: 30px; height: 30px; flex-shrink: 0; }

.side-name {
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  line-height: 1.35;
}

.side-name em {
  display: block;
  font-style: normal;
  color: var(--copper);
  font-size: 0.62rem;
  letter-spacing: 0.2em;
}

/* ---------- the wordmark ---------- */
.mark {
  display: flex;
  align-items: center;
  text-decoration: none;
  flex-shrink: 0;
}

.mark img {
  height: 18px;
  width: auto;
  display: block;
}

.auth-mark { display: flex; align-items: center; }
.auth-mark img { height: 18px; width: auto; display: block; }

@media (max-width: 700px) {
  .mark img { height: 15px; }
}

/* ===========================================================
   HOMEPAGE SECTIONS
   ===========================================================
   Kits, bundles, components, courses - one after another, each
   with its own heading and a way through to the full list.
   =========================================================== */
.home-sec { padding-bottom: 4vh; }

.home-sec .section-head {
  padding: 4vh 0 16px;
  border-bottom: 1px solid var(--rule);
  margin-bottom: 0;
}

.see-all {
  color: var(--copper) !important;
  text-decoration: none;
  transition: opacity .2s;
}

.see-all:hover { opacity: 0.7; }

/* Four across for components. A resistor pack needs less room
   to explain itself than a kit does. */
/* Exactly three across on the homepage. auto-fit would give
   four on a wide monitor, and the sketch says three. */
.home-sec .grid { grid-template-columns: repeat(3, 1fr); }

.home-empty {
  color: var(--muted);
  font-size: 0.94rem;
  padding: 34px 0;
}

/* The homepage course rows sit inside the ruled column, so they
   need the top border the standalone list already has. */
.home-sec .course-list { border-top: 0; }

/* Anchors land under the fixed header without this. */
.home-sec { scroll-margin-top: 70px; }

/* ---------- filling the page ----------
   Bigger images, tighter gaps between sections. The page was
   not short of content - the grid was leaving empty columns
   beside it. */
.kit-img { aspect-ratio: 1 / 1; }

/* The gallery on a product page stays landscape: a photograph
   of a wide box in a square frame gets cropped badly. */
.kit-main { aspect-ratio: 4 / 3; }
.kit-thumb { aspect-ratio: 4 / 3; }
.cart-img { aspect-ratio: 4 / 3; }
.needs-row img { aspect-ratio: 4 / 3; }

.kit-outcome-line { font-size: 0.88rem; }

@media (max-width: 640px) {
  /* One per row on a phone, so the image is as big as it can be
     rather than two cramped columns. */
  .grid, .grid-4 { grid-template-columns: 1fr; }
}

/* ===========================================================
   THE HOVER WIPE
   ===========================================================
   A copper panel sweeps across the image and the second photo
   is behind it when it passes. The swap happens at the exact
   midpoint, so you never see both images at once - the wipe
   hides the change, which is what makes it read as one motion
   rather than a crossfade.

   A card with only one photo gets no wipe: .has-two is only
   added when a second image exists. Sweeping copper to reveal
   the same picture would look broken.
   =========================================================== */
.kit-img {
  position: relative;
  overflow: hidden;
}

.kit-img img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* A hard-edged reveal, not a fade. The second photo is clipped
   to nothing and the clip opens left to right, so there is a
   crisp vertical edge travelling across - both images are
   visible at once, each on its own side of the line.

   clip-path rather than width, because clipping does not
   re-lay-out the image: it stays the same size and you see more
   of it, instead of a squashed picture stretching open. */
/* OPENING and CLOSING run at different speeds, and that is the
   fix for two cards looking revealed at once.

   A transition is read from the state being moved TO. The rule
   below applies when leaving - 140ms, so the card is closed
   almost before the pointer has left it. The :hover rule
   applies when entering, at the full 450ms.

   With both at 450ms, moving from one card to the next left the
   first still closing while the second opened, and both looked
   revealed. */
.kit-img .img-b {
  opacity: 1;
  clip-path: inset(0 100% 0 0);
  transition: clip-path .14s ease-in;
}

.kit:hover .has-two .img-b {
  clip-path: inset(0 0 0 0);
  transition: clip-path .45s cubic-bezier(0.65, 0, 0.35, 1);
}

/* A copper bar riding the leading edge. Same duration and
   easing as the clip, so the two stay locked together - a
   fraction out and it looks like two separate effects. */
.wipe {
  display: block;
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 6px;
  background: var(--copper);
  opacity: 0;
  pointer-events: none;
  z-index: 2;
}

/* Animated on `left` rather than translateX. A percentage
   translate is a percentage of the element's OWN width - six
   pixels here - so it would barely move. left:100% is a
   percentage of the card, which is what we want. */
.kit:hover .has-two .wipe {
  animation: edge-across .45s cubic-bezier(0.65, 0, 0.35, 1) forwards;
}

@keyframes edge-across {
  0%   { left: 0;    opacity: 1; }
  99%  { left: 100%; opacity: 1; }
  100% { left: 100%; opacity: 0; }
}

/* ---------- the cursor badge ----------
   Follows the pointer across the image. The lag is deliberate:
   moving exactly with the cursor looks stuck to it, a little
   behind looks like it is being carried. */
.peek {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 3;
  width: 92px;
  height: 92px;
  /* Centred on the pointer. The script sets a translate for
     position, so the offset has to be margin - a second
     transform would overwrite the first. */
  margin: -46px 0 0 -46px;
  border-radius: 50%;
  background: var(--copper);
  color: var(--paper);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.62rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  text-align: center;
  pointer-events: none;
  opacity: 0;
  /* Quick out, so the badge is gone before the pointer reaches
     the next card. */
  transition: opacity .1s ease;
}

/* Only opacity here. The script owns transform, because it
   carries both the position and the scale - two rules setting
   transform would cancel each other out. */
.kit-img.peeking .peek {
  opacity: 1;
  transition: opacity .22s ease;
}

@media (max-width: 900px) {
  /* No cursor to follow on a phone. */
  .peek { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .kit-img .img-b { transition: clip-path .15s linear; }
  .wipe { display: none; }
  .peek { transition: opacity .15s; }
}

/* No zoom. A crossfade and a zoom at once read as a wobble
   rather than one effect. */
.kit:hover .kit-img img {
  transform: none;
}



@media (max-width: 900px) {
  .home-sec .grid { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 640px) {
  .home-sec .grid { grid-template-columns: 1fr; }
}

/* ---------- the wordmark, one line ----------
   nowrap stops it breaking onto two lines at any width. The vw
   size shrinks it instead, which is the behaviour you want from
   a name that has to stay whole.

   The second .line rule is gone because there is only one line
   now - the delay that staggered them has nothing to stagger. */
.wordmark { white-space: nowrap; }

/* ---------- homepage image height ----------
   4:3 rather than square. The cards stay the same width, so the
   grid still fills the row - only the image gets shorter. The
   kits and shop pages keep square images, where browsing is the
   whole point of the page.
   ========================================================= */
.home-sec .kit-img { aspect-ratio: 4 / 3; }

/* The card WIDTH is what sets the image size - three across a
   1412px column is 471px each, and no aspect ratio makes that
   small. Capping the grid and centring it is the only thing
   that actually shrinks them while keeping three in a row.

   The section heading still spans the full column, so the page
   keeps its structure - only the cards pull in. */
.home-sec .grid {
  max-width: 1080px;
  margin-left: auto;
  margin-right: auto;
}

/* ===========================================================
   SCROLLING
   ===========================================================
   The transformed wrapper is gone. Two lines replace it:
   scroll-behavior for the easing, and scroll-margin-top so a
   heading does not land underneath the fixed header.
   =========================================================== */
section[id],
.home-sec,
.band-block { scroll-margin-top: 76px; }

/* Anchor jumps stay instant, then the script eases from there.
   scroll-margin-top keeps a heading clear of the fixed header
   whichever way it is reached. */

/* ---------- the wipe, quicker and in colour ----------
   0.3s rather than 0.62s. The swap sits at 0.145s, the exact
   midpoint, so the second photo is still hidden underneath the
   copper when it changes - move one number and the other has to
   follow or you see both images at once.

   No greyscale anywhere on a product card. Draining the colour
   unified a set of mismatched stock photos; with real product
   photography it just makes the kits look drab, and a kit is
   bought on how it looks.
   ========================================================= */
.kit-img img,
.kit:hover .kit-img img {
  filter: none;
}

.kit-img img { transition: none; }

/* ---------- live cart ---------- */
.cart-line { transition: opacity .2s ease; }

/* While a request is in flight. Dimmed rather than disabled -
   the number the customer typed stays visible and editable. */
.cart-line.busy { opacity: 0.5; }

.cart-line.going { opacity: 0; }

.cart-problem[hidden] { display: none; }

/* ===========================================================
   ADDING TO THE CART
   =========================================================== */

/* The clone that flies. position:fixed so it is measured
   against the screen, and pointer-events:none so it can never
   swallow a click on its way past something.

   No transition here - the arc is driven by Web Animations in
   the script, because a transition can only go between two
   states and an arc needs a point in the middle. */
.fly-ghost {
  position: fixed;
  z-index: 300;
  object-fit: cover;
  border: 2px solid var(--copper);
  box-shadow: 0 18px 50px rgba(22, 24, 26, 0.28);
  pointer-events: none;
  will-change: transform, opacity;
}

/* A ring left where the image lifted off, so the card
   acknowledges the click as well as the header. */
.lift-ring {
  position: fixed;
  z-index: 299;
  border: 2px solid var(--copper);
  pointer-events: none;
  animation: lift-off .6s cubic-bezier(0.22, 1, 0.36, 1) forwards;
}

@keyframes lift-off {
  0%   { transform: scale(1);    opacity: 0.9; }
  100% { transform: scale(1.12); opacity: 0; }
}

/* The count jumps once, so the eye follows where the image
   went. Copper for a moment, then back. */
.bag.bumped {
  animation: cart-bump .62s cubic-bezier(0.34, 1.4, 0.64, 1);
  display: inline-block;   /* transform needs this on an inline link */
}

/* Two beats rather than one. A single pop reads as a glitch;
   a second smaller one reads as a landing. */
@keyframes cart-bump {
  0%   { transform: scale(1)    translateY(0);    color: var(--ink); }
  25%  { transform: scale(1.32) translateY(-3px); color: var(--copper); }
  50%  { transform: scale(0.96) translateY(1px);  color: var(--copper); }
  72%  { transform: scale(1.1)  translateY(-1px); color: var(--copper); }
  100% { transform: scale(1)    translateY(0);    color: var(--ink); }
}

/* The button confirms in place, so nobody has to look up at the
   header to know it worked. */
.add-btn.added,
.btn-add.added {
  background: var(--copper);
  border-color: var(--copper);
  color: var(--paper);
}

.add-btn:disabled,
.btn-add:disabled,
.btn-buy:disabled {
  cursor: default;
}

@media (prefers-reduced-motion: reduce) {
  .fly-ghost { display: none; }
  .bag.bumped { animation: none; }
}

/* The tick that appears on the button. Drawn in, so it reads as
   a confirmation rather than a label swap. */
.add-btn .tick,
.btn-add .tick {
  display: inline-block;
  animation: tick-in .32s cubic-bezier(0.34, 1.56, 0.64, 1);
}

@keyframes tick-in {
  0%   { transform: scale(0) rotate(-30deg); opacity: 0; }
  100% { transform: scale(1) rotate(0);      opacity: 1; }
}

.add-btn.added,
.btn-add.added {
  transition: background-color .2s, border-color .2s, color .2s;
}

@media (prefers-reduced-motion: reduce) {
  .lift-ring { display: none; }
  .add-btn .tick, .btn-add .tick { animation: none; }
}

/* ===========================================================
   CHECKOUT AND ORDERS
   =========================================================== */
.checkout {
  display: grid;
  grid-template-columns: 1fr 340px;
  gap: 44px;
  align-items: start;
  padding-bottom: 10vh;
}

.ck-form fieldset {
  border: 1px solid var(--rule);
  background: #fff;
  padding: 20px 20px 10px;
  margin-bottom: 18px;
}

.ck-form legend { padding: 0 8px; }

.ck-form label {
  display: block;
  font-size: 0.68rem;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 16px;
}

.ck-form input,
.ck-form textarea {
  display: block;
  width: 100%;
  margin-top: 6px;
  font-family: var(--font);
  font-size: 0.96rem;
  text-transform: none;
  letter-spacing: 0;
  color: var(--ink);
  background: #fff;
  border: 1px solid var(--rule);
  padding: 11px 12px;
}

.ck-form input:focus,
.ck-form textarea:focus { outline: none; border-color: var(--ink); }

.ck-form .two { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.ck-form .three { display: grid; grid-template-columns: 1fr 1fr 130px; gap: 14px; }

.ck-form .hint {
  font-size: 0.84rem;
  color: var(--muted);
  text-transform: none;
  letter-spacing: 0;
  margin-bottom: 14px;
}

/* ---------- the summary ---------- */
.ck-summary {
  border: 1px solid var(--rule);
  background: #fff;
  padding: 24px 22px;
  position: sticky;
  top: 78px;
}

.ck-lines { list-style: none; margin: 14px 0 4px; }

.ck-lines li {
  display: grid;
  grid-template-columns: 34px 1fr auto;
  gap: 10px;
  padding: 9px 0;
  border-bottom: 1px solid var(--rule);
  font-size: 0.9rem;
  align-items: baseline;
}

.ck-lines .q { color: var(--muted); font-variant-numeric: tabular-nums; }
.ck-lines .n em {
  display: block;
  font-style: normal;
  font-size: 0.74rem;
  color: var(--copper);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.ck-lines .p { white-space: nowrap; }

/* Says plainly where payment stands. Promising a card screen
   that does not exist would be worse than admitting it. */
.ck-note {
  font-size: 0.8rem;
  color: var(--muted);
  line-height: 1.55;
  margin-top: 14px;
}

/* ---------- after it is placed ---------- */
.placed { padding: 4vh 0 5vh; border-bottom: 1px solid var(--rule); margin-bottom: 34px; }

.placed h1 {
  font-weight: 500;
  font-size: clamp(1.7rem, 4.4vw, 3rem);
  letter-spacing: -0.035em;
  margin: 10px 0 14px;
}

.placed p { color: var(--muted); max-width: 46ch; }

.order-page {
  display: grid;
  grid-template-columns: 1fr 330px;
  gap: 44px;
  align-items: start;
  padding-bottom: 10vh;
}

.panel-plain {
  border: 1px solid var(--rule);
  background: #fff;
  padding: 22px 22px 18px;
  margin-bottom: 18px;
}

.panel-plain address { font-style: normal; line-height: 1.75; margin-top: 12px; }

.order-status { margin: 12px 0 18px; }

.order-events { list-style: none; }

.order-events li {
  padding: 10px 0 10px 16px;
  border-left: 2px solid var(--rule);
  font-size: 0.88rem;
}

/* The most recent step, marked so the eye finds it. */
.order-events li:last-child { border-left-color: var(--copper); }

.order-events strong { font-weight: 500; }
.order-events em { font-style: normal; color: var(--muted); display: block; font-size: 0.8rem; }
.order-events span { display: block; color: var(--muted); font-size: 0.84rem; margin-top: 2px; }

@media (max-width: 900px) {
  .checkout, .order-page { grid-template-columns: 1fr; gap: 26px; }
  .ck-summary { position: static; }
  .ck-form .three { grid-template-columns: 1fr 1fr; }
}

/* ---------- one order, in the admin ---------- */
.ship-to {
  font-style: normal;
  line-height: 1.75;
  font-size: 0.92rem;
  background: #EFEEE9;
  border-left: 2px solid var(--copper);
  padding: 12px 14px;
}

/* What the customer asked for, marked so it is not skimmed
   past while packing. */
.cust-note {
  font-size: 0.9rem;
  line-height: 1.6;
  background: #EFEEE9;
  border-left: 2px solid var(--ink);
  padding: 12px 14px;
}

.admin-filters input[type="date"] {
  font-family: var(--font);
  font-size: 0.88rem;
  padding: 8px 11px;
  border: 1px solid var(--rule);
  background: #fff;
  color: var(--ink);
}

.panel .order-events { margin-top: 4px; }
.panel .admin-form fieldset { border: 0; padding: 0; margin: 0; }

/* ===========================================================
   PAYMENT
   =========================================================== */
.pay-box {
  max-width: 440px;
  margin: 8vh auto 14vh;
  border: 1px solid var(--rule);
  background: #fff;
  padding: 34px 32px 30px;
}

.pay-box h1 {
  font-weight: 500;
  font-size: clamp(1.8rem, 5vw, 2.6rem);
  letter-spacing: -0.035em;
  margin: 10px 0 20px;
}

.pay-box .acc-rows { margin-bottom: 24px; }

/* Impossible to miss that a test payment is not a real one. */
.test-flag {
  font-size: 0.82rem;
  line-height: 1.55;
  color: var(--copper);
  border: 1px dashed var(--copper);
  padding: 10px 12px;
  margin-bottom: 20px;
}

.pay-note {
  font-size: 0.82rem;
  color: var(--muted);
  line-height: 1.55;
  margin-top: 14px;
}

/* ---------- choosing how to pay ---------- */
.pay-pick { display: grid; gap: 10px; margin-bottom: 8px; }

.pay-opt {
  margin: 0;
  text-transform: none;
  letter-spacing: 0;
  cursor: pointer;
}

.pay-opt input { position: absolute; opacity: 0; pointer-events: none; }

.pay-opt span {
  display: block;
  border: 1px solid var(--rule);
  padding: 14px 16px;
  transition: border-color .2s, box-shadow .2s;
}

.pay-opt strong {
  display: block;
  font-size: 0.98rem;
  font-weight: 500;
  color: var(--ink);
  margin-bottom: 3px;
}

.pay-opt em {
  font-style: normal;
  font-size: 0.82rem;
  color: var(--muted);
  line-height: 1.5;
}

.pay-opt:hover span { border-color: var(--muted); }

.pay-opt:has(input:checked) span {
  border-color: var(--ink);
  box-shadow: inset 3px 0 0 var(--copper);
}

/* Not available, and it says why rather than disappearing. */
.pay-opt.off { cursor: not-allowed; }
.pay-opt.off span { background: #E7E6E0; }
.pay-opt.off strong { color: var(--muted); }

.cod-line[hidden] { display: none; }

/* ---------- the admin link ---------- */
.account-menu a.admin-link {
  color: var(--copper);
  font-weight: 500;
}

.account-menu a.admin-link .arrow { opacity: 1; }

/* Marked out from the customer cards around it, so an admin
   spots it without hunting. */
.admin-card {
  box-shadow: inset 3px 0 0 var(--copper);
}