/* style.css — shelfkeeper.co.uk public page.
 *
 * Tokens copied verbatim from cmd/shelfkeeperd/static/app.css (the palette
 * and type are binding, already contrast-measured — nothing here re-picks
 * them). Only the token block and base/typography rules are taken; the
 * tables, chips and stamp machinery stay in app.css, which this page does
 * not need.
 */

/* ---- fonts --------------------------------------------------------------
 * Four @font-face rules, not five: Space Grotesk 400 (body display weight)
 * is dropped, ~13 KB. Body prose stays on the system UI stack.
 */
@font-face {
  font-family: "Space Grotesk";
  src: url("fonts/space-grotesk-500.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Space Grotesk";
  src: url("fonts/space-grotesk-700.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "IBM Plex Mono";
  src: url("fonts/ibm-plex-mono-400.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "IBM Plex Mono";
  src: url("fonts/ibm-plex-mono-500.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

/* ---- tokens (verbatim from app.css; TestSiteTokensMatchAppCSS pins it) -- */
:root {
  --ink-green: #1f4738;
  --paper: #f3f7ef;
  --stamp-red: #c0392b;
  --amber: #b9770e;
  --leaf: #3e7c4f;
  --slate: #5d6d7e;

  --amber-ink: #805107;
  --leaf-ink: #2f6440;
  --slate-ink: #46545f;

  --chrome: var(--ink-green);
  --chrome-ink: #f7f5f0;   /* header text: always light, on both themes */
  --btn-hover: #17362a;
  --danger-ink: #8c2318;
  --danger-line: #c9a3a3;
  --error-container: #f9dedc;
  --on-error-container: #410e0b;

  --ink: #23281f;
  --ink-muted: #5a635a;
  --card: #f3f7ef;
  --line: #dce3d7;
  --line-strong: #c2ccbd;
  --field-line: #7a8676;   /* control borders: 3:1 (SHE-2464) */

  --font-display: "Space Grotesk", "Trebuchet MS", "Segoe UI", system-ui, sans-serif;
  --font-mono: "IBM Plex Mono", ui-monospace, "SFMono-Regular", "Cascadia Mono",
    "Roboto Mono", Menlo, Consolas, monospace;
  --font-body: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue",
    Arial, sans-serif;

  --radius: 12px;
  --tap: 48px;
  --shadow: 0 1px 2px rgba(31, 71, 56, .06), 0 8px 24px -16px rgba(31, 71, 56, .35);

  --s1: .25rem;
  --s2: .5rem;
  --s3: .75rem;
  --s4: 1rem;
  --s6: 1.5rem;
  --s8: 2rem;
  --page: 64rem;
}

@media (prefers-color-scheme: dark) {
  :root {
    --chrome: #16302a;
    --ink-green: #86c9a6;
    --btn-hover: #9ad6b6;
    --paper: #111916;
    --card: #1d2924;
    --ink: #edeae3;
    --ink-muted: #a9b2aa;
    --line: #2e3d36;
    --line-strong: #3e4a4e;
    --field-line: #6b787c;

    --stamp-red: #e07a6e;
    --amber: #d9a94a;
    --leaf: #7fb58c;
    --slate: #9aa8b4;

    --amber-ink: var(--amber);
    --leaf-ink: #8cc199;   /* = app.css: lifted a step for the stamp (SHE-3268) */
    --slate-ink: var(--slate);

    --danger-ink: #ef9c8f;
    --danger-line: #6b4640;
    --error-container: #8c1d18;
    --on-error-container: #f9dedc;

    --shadow: 0 0 0 1px var(--line);
  }
}

/* ---- base ----------------------------------------------------------- */
*,
*::before,
*::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  color-scheme: light dark;
}

body {
  margin: 0;
  min-height: 100vh;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 1rem;
  line-height: 1.55;
}

a { color: var(--ink-green); text-underline-offset: .18em; overflow-wrap: anywhere; }
a:hover { text-decoration-thickness: 2px; }

h1, h2, h3, .brand { font-family: var(--font-display); color: var(--ink-green); letter-spacing: -.01em; overflow-wrap: break-word; }

/* Type scale: h1 clamps 1.75-2.5rem, h2 1.4rem/700, h3 1.1rem/500. No vw cap:
   the h1 grows with the user's text size, and at 200% on a narrow phone
   "ShelfKeeper:" breaks at its soft hyphen instead of scrolling. */
h1 {
  margin: 0 0 var(--s3);
  font-size: clamp(1.75rem, 1.2rem + 2.4vw, 2.5rem);
  font-weight: 700;
  line-height: 1.12;
  text-wrap: balance;
}
h2 { font-size: 1.4rem; font-weight: 700; line-height: 1.2; margin: var(--s8) 0 var(--s3); text-wrap: balance; }
h3 { font-size: 1.1rem; font-weight: 500; line-height: 1.3; margin: var(--s6) 0 var(--s2); }
/* A bare domain or path in prose (www.shelfkeeper.co.uk/dump/…) wraps at
   200% text on a 320px screen instead of scrolling the page sideways. */
p, li { max-width: 42em; overflow-wrap: break-word; }

code, pre { font-family: var(--font-mono); }
pre {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--s3) var(--s4);
  overflow-x: auto;
}
code { background: var(--card); border: 1px solid var(--line); border-radius: 4px; padding: 0 var(--s1); overflow-wrap: anywhere; font-size: .92em; }   /* 4px kept: inline code sits in a line of text */
/* A block of code is one box, not a box in a box; long lines (hashes) wrap. */
pre code { background: none; border: 0; padding: 0; font-size: .9rem; white-space: pre-wrap; word-break: break-all; }

ul { padding-left: var(--s6); }
li { margin: var(--s1) 0; }

:focus-visible {
  outline: 3px solid var(--ink-green);
  outline-offset: 2px;
}
/* The ring follows the element's own corner; only a plain link takes 8px.
 * Links only: border-radius rounds the element, not just its ring, so a
 * square box with a ground or border keeps its corners (SHE-3717).
 * :where() keeps this under every class rule. */
:where(a:focus-visible, summary:focus-visible) { border-radius: 8px; }

/* ---- skip link -------------------------------------------------------- */
.skip-link {
  position: absolute;
  left: -999px;
  top: var(--s2);
  background: var(--card);
  color: var(--ink);
  padding: var(--s2) var(--s4);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  z-index: 10;
}
.skip-link:focus { left: var(--s2); }

/* The report form's honeypot: off screen, never shown to a person. A class,
   not a style attribute, because /report's CSP allows no inline styles. */
.honeypot { position: absolute; left: -9999px; }

/* ---- header ------------------------------------------------------------ */
.site-header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s2) var(--s4);
  padding: var(--s3) clamp(var(--s3), 3vw, var(--s8));
  background: var(--chrome);
  color: var(--chrome-ink);
}
.site-header :focus-visible { outline-color: #fff; }

.brand {
  display: flex;
  align-items: center;
  gap: var(--s2);
  color: var(--chrome-ink);
  text-decoration: none;
  font-weight: 700;
  font-size: 1.1rem;
}
.brand-mark { width: 32px; height: 32px; flex: none; }

.site-nav {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s1) var(--s3);
  margin-left: auto;
  font-family: var(--font-display);
  font-size: .9rem;
}
.site-nav a {
  color: var(--chrome-ink);
  text-decoration: none;
  padding: var(--s1) 0;
  min-height: var(--tap);
  display: inline-flex;
  align-items: center;
}
/* Narrow screens: the nav drops under the brand and wraps. */
@media (max-width: 39.99rem) {
  .site-header { row-gap: 0; }
  .site-nav { margin-left: 0; gap: 0 var(--s4); }
  .hero p { font-size: 1.05rem; }  /* dead: the later .hero p (1.15rem) wins */
}
.site-nav a:hover,
.site-nav a[aria-current="page"] { text-decoration: underline; text-decoration-thickness: 2px; text-underline-offset: .35em; }

/* ---- layout ------------------------------------------------------------ */
main {
  max-width: var(--page);
  margin: 0 auto;
  padding: var(--s8) clamp(var(--s3), 3vw, var(--s8));
}

section { margin-bottom: var(--s8); }
section > :last-child { margin-bottom: 0; }

/* ---- hero ---------------------------------------------------------- */
.hero {
  display: grid;
  grid-template-columns: minmax(0, 1fr);  /* never wider than the screen, even
     with large text: the stamp below wraps to fit instead */
  gap: var(--s6);
  padding: var(--s4) 0 var(--s8);
  align-items: center;
}
@media (min-width: 40rem) {
  .hero { grid-template-columns: minmax(0, 1fr) auto; padding-top: var(--s8); }
  .hero .stamp { margin-right: var(--s6); }
}
/* The header mark again, read with the name: above the headline on phones
   (72px), beside it from 40rem (104px). */
.hero-mark { display: block; width: 72px; height: 72px; margin-bottom: var(--s3); }
@media (min-width: 40rem) {
  .hero-title { display: flex; align-items: center; gap: var(--s4); margin-bottom: var(--s3); }
  .hero-title h1 { margin: 0; }
  .hero-mark { flex: none; width: 104px; height: 104px; margin: 0; }
}
/* The hero mark stocks its own shelf once on load: the board grows, the box,
   jar and can drop on it with a squash, the lid wobbles, a sheen crosses the
   tile. A tap or click replays it with no script: the logo is a <label> for
   a hidden checkbox, and each toggle swaps every animation to its identical
   "-b" twin, which a browser starts from the top. Reduced motion: still mark.
   Individual translate/scale/rotate so two animations never fight over one
   transform. */
.hero-replay { display: contents; }
.hero-mark { cursor: pointer; -webkit-tap-highlight-color: transparent; }
@media (prefers-reduced-motion: no-preference) {
  :is(.hm-shelf, .hm-box, .hm-jar, .hm-lid, .hm-can, .hm-glint, .hm-sheen) { transform-box: fill-box; }
  .hm-shelf {
    transform-origin: 50% 50%;
    animation: hm-grow .5s cubic-bezier(.3, .8, .3, 1.1) both,
               hm-dip 1.3s linear both;
  }
  .hm-box, .hm-jar, .hm-can {
    transform-origin: 50% 100%;
    animation: hm-drop .7s both;
  }
  .hm-box { animation-delay: .3s; }
  .hm-jar { animation-delay: .45s; }
  .hm-can { animation-delay: .6s; }
  .hm-lid { transform-origin: 50% 100%; animation: hm-wobble .45s .86s ease-out both; }
  .hm-glint { animation: hm-glint .5s 1.25s ease-in-out both; }
  .hm-sheen { animation: hm-sheen .8s 1.2s cubic-bezier(.45, 0, .25, 1) both; }
  :checked + .hero-mark .hm-shelf { animation-name: hm-grow-b, hm-dip-b; }
  :checked + .hero-mark :is(.hm-box, .hm-jar, .hm-can) { animation-name: hm-drop-b; }
  :checked + .hero-mark .hm-lid { animation-name: hm-wobble-b; }
  :checked + .hero-mark .hm-glint { animation-name: hm-glint-b; }
  :checked + .hero-mark .hm-sheen { animation-name: hm-sheen-b; }
}
@keyframes hm-grow {
  from { scale: 0 1; opacity: 0; }
  40% { opacity: 1; }
  to { scale: 1 1; }
}
/* A small give in the board as each item lands (box .69 s, jar .84 s, can .99 s). */
@keyframes hm-dip {
  0%, 51%, 58%, 63%, 70%, 74%, 82%, 100% { translate: 0 0; }
  53.5%, 65.5%, 77% { translate: 0 .8px; }
}
@keyframes hm-drop {
  0% { translate: 0 -78px; scale: .96 1.07; opacity: 0; animation-timing-function: cubic-bezier(.55, 0, .85, .45); }
  12% { opacity: 1; }
  55% { translate: 0 0; scale: .96 1.07; animation-timing-function: ease-out; }
  67% { translate: 0 0; scale: 1.08 .9; animation-timing-function: ease-in-out; }
  81% { translate: 0 -2.5px; scale: .98 1.03; animation-timing-function: ease-in; }
  91% { translate: 0 0; scale: 1.02 .98; }
  100% { translate: 0 0; scale: 1 1; opacity: 1; }
}
@keyframes hm-wobble {
  0% { rotate: 0deg; }
  30% { rotate: -9deg; }
  60% { rotate: 5deg; }
  82% { rotate: -2deg; }
  100% { rotate: 0deg; }
}
@keyframes hm-glint {
  0%, 100% { fill-opacity: .75; }
  50% { fill-opacity: 1; }
}
@keyframes hm-sheen {
  from { translate: 0 0; }
  to { translate: 175px 0; }
}
/* The replay twins: the same frames under a second name. */
@keyframes hm-grow-b {
  from { scale: 0 1; opacity: 0; }
  40% { opacity: 1; }
  to { scale: 1 1; }
}
@keyframes hm-dip-b {
  0%, 51%, 58%, 63%, 70%, 74%, 82%, 100% { translate: 0 0; }
  53.5%, 65.5%, 77% { translate: 0 .8px; }
}
@keyframes hm-drop-b {
  0% { translate: 0 -78px; scale: .96 1.07; opacity: 0; animation-timing-function: cubic-bezier(.55, 0, .85, .45); }
  12% { opacity: 1; }
  55% { translate: 0 0; scale: .96 1.07; animation-timing-function: ease-out; }
  67% { translate: 0 0; scale: 1.08 .9; animation-timing-function: ease-in-out; }
  81% { translate: 0 -2.5px; scale: .98 1.03; animation-timing-function: ease-in; }
  91% { translate: 0 0; scale: 1.02 .98; }
  100% { translate: 0 0; scale: 1 1; opacity: 1; }
}
@keyframes hm-wobble-b {
  0% { rotate: 0deg; }
  30% { rotate: -9deg; }
  60% { rotate: 5deg; }
  82% { rotate: -2deg; }
  100% { rotate: 0deg; }
}
@keyframes hm-glint-b {
  0%, 100% { fill-opacity: .75; }
  50% { fill-opacity: 1; }
}
@keyframes hm-sheen-b {
  from { translate: 0 0; }
  to { translate: 175px 0; }
}
/* The hero stamp takes .hero p's size, 1.15rem at every width (the phone
   1.05rem rule above loses to the later .hero p). At 200% text on a 320px
   phone its date wraps to two lines rather than shrinking. */
.hero .stamp { font-size: 1.15rem; padding: var(--s2) var(--s4); }
.hero p {
  font-size: 1.15rem;
  max-width: 36em;
}
/* The home page's same-page jump links, under the Play badge (not in the
   header, which is the same on every page). */
.hero-links {
  display: flex;
  flex-wrap: wrap;
  gap: 0 var(--s4);
  margin-top: var(--s4);
  font-family: var(--font-display);
  font-size: .9rem;
}
.hero-links a {
  min-height: var(--tap);
  display: inline-flex;
  align-items: center;
}

/* The one loud element: a best-before date stamp, inked like the tin mark. */
.stamp {
  justify-self: start;
  display: inline-block;
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: 1.4rem;
  letter-spacing: .04em;
  color: var(--stamp-red);
  border: 3px solid var(--stamp-red);
  border-radius: var(--radius);
  padding: var(--s2) var(--s4);
  transform: rotate(-3deg);
  background: var(--card);
}
.stamp small {
  display: block;
  font-size: .55rem;
  font-weight: 400;
  letter-spacing: .12em;
  color: var(--ink-muted);
  text-transform: uppercase;
}

/* ---- cards / feature lists ---------------------------------------- */
.card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: var(--s4) var(--s6);
}

.feature-list {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--s2) var(--s6);
  list-style: none;
  padding: 0;
  margin: var(--s4) 0;
}
@media (min-width: 40rem) {
  .feature-list { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
/* Free and Plus side by side; their lists stay one column inside a card. */
.plans {
  display: grid;
  gap: var(--s4) var(--s6);
  grid-template-columns: minmax(0, 1fr);
  margin: var(--s4) 0;
}
@media (min-width: 40rem) {
  .hero .feature-list { grid-template-columns: minmax(0, 1fr); }
  .plans { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.plans > * { overflow-wrap: break-word; }
.plans h3 { margin-top: 0; }
.plans .feature-list { grid-template-columns: minmax(0, 1fr); }
.plan-price { font-family: var(--font-display); font-weight: 700; margin-bottom: 0; }
.feature-list li {
  padding-left: var(--s6);
  position: relative;
}
.feature-list li::before {
  content: "";
  position: absolute;
  left: 0;
  top: .5em;
  width: .5em;
  height: .5em;
  border-radius: 50%;
  background: var(--leaf);
}

/* ---- get the app ---------------------------------------------------- */
/* Google's badge file carries its own clear space; show it unaltered, at
   least 28px tall (Google's badge rules). */
.get-app {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0 var(--s4);
  margin: var(--s6) 0 var(--s2) calc(var(--s3) * -1);  /* -12px: line the badge's
     artwork, not its built-in clear space, up with the text edge */
}
.play-badge { display: inline-block; line-height: 0; border-radius: var(--radius); }
.play-badge img { height: 96px; width: auto; }
.hero .get-app-alt { font-size: .95rem; color: var(--ink-muted); margin: 0; padding-left: var(--s3); }

/* ---- screenshots --------------------------------------------------- */
.shots {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 18rem));
  gap: var(--s6);
}
/* Narrow screens: a swipeable row, with the next phone peeking in. */
@media (max-width: 39.99rem) {
  .shots {
    grid-template-columns: none;
    grid-auto-flow: column;
    grid-auto-columns: 72%;
    gap: var(--s4);
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    padding-bottom: var(--s2);
  }
  .shots figure { scroll-snap-align: start; }
}
.shots figure { margin: 0; }
.shots img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--line);
  border-radius: calc(var(--radius) * 2);   /* kept: 24px echoes the phone's own rounded screen in the screenshot */
  box-shadow: var(--shadow);
}
.shots figcaption { font-size: .9rem; color: var(--ink-muted); margin-top: var(--s2); }

/* ---- footer -------------------------------------------------------- */
footer.attribution {
  padding: var(--s6) clamp(var(--s3), 3vw, var(--s8)) var(--s8);
  max-width: var(--page);
  margin: 0 auto;
  color: var(--ink-muted);
  font-size: .85rem;
  border-top: 1px solid var(--line);
}
footer.attribution p { margin: var(--s2) 0; max-width: none; }
footer.attribution p:first-child { font-size: .95rem; }

/* ---- fine print (licence text on the home page) --------------------- */
.fine-print { font-size: .9rem; color: var(--ink-muted); border-top: 1px solid var(--line); padding-top: var(--s2); }
.fine-print h2 { font-size: 1.1rem; font-weight: 500; }

/* ---- 404 ------------------------------------------------------------ */
.not-found { padding: var(--s8) 0; }
.not-found .stamp { margin: 0 0 var(--s6); font-size: 2rem; }
footer.attribution a { overflow-wrap: anywhere; }

@media (max-width: 25rem) {
  main { padding-left: var(--s3); padding-right: var(--s3); }
  .plans > .card { padding: var(--s3); }
  .feature-list li { padding-left: var(--s4); }
}

/* ---- forms (beta/report pages) -------------------------------------- */
form { max-width: 32em; }
label {
  display: block;
  font-weight: 500;
  margin-bottom: var(--s1);
}
label + br { display: none; }   /* report.php keeps <br> for unstyled reading */
textarea,
input[type="text"],
input[type="email"] {
  display: block;
  width: 100%;
  max-width: 100%;
  box-sizing: border-box;
  font: inherit;
  font-size: 1rem;   /* 16px minimum: no iOS zoom-on-focus */
  color: var(--ink);
  background: var(--card);
  border: 1px solid var(--field-line);
  border-radius: var(--radius);
  padding: var(--s2) var(--s3);
}
textarea { resize: vertical; }
input[readonly] { background: transparent; }
input:disabled { color: var(--ink-muted); text-decoration: line-through; }
input[type="checkbox"] {
  width: 1.25rem;
  height: 1.25rem;
  margin: 0 var(--s2) 0 0;
  vertical-align: -0.2em;
  accent-color: var(--ink-green);
  border-radius: 4px;   /* kept: the native box's own corner, so its focus ring stays square */
}
#device label:has(input[type="checkbox"]) {
  min-height: var(--tap);
  display: flex;
  align-items: center;
}
fieldset {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--s3);
  margin: 0 0 var(--s4);
}
legend { font-weight: 600; padding: 0 var(--s1); }
/* Text is --paper, not --chrome-ink: --ink-green turns light in dark mode
   (SHE-2468). Display font and 8px radius match the web UI's .btn. */
button {
  font: inherit;
  font-family: var(--font-display);
  font-size: 1rem;
  font-weight: 500;
  color: var(--paper);
  background: var(--ink-green);
  border: none;
  border-radius: 8px;
  min-height: var(--tap);
  padding: var(--s2) var(--s6);
  cursor: pointer;
}
button:hover { background: var(--btn-hover); }
textarea:focus-visible,
input:focus-visible,
button:focus-visible {
  outline: 3px solid var(--ink-green);
  outline-offset: 2px;
}
