/* ==========================================================================
   Zine Rack — application skin

   Loads AFTER zinerack.css and dresses the markup the templates already
   emit. Every selector here targets a class name that was already in the
   codebase, so no template had to be rewritten to be restyled — which
   matters because zines/tests.py asserts on exact class attributes in the
   rack theme editor (`class="colour-pick"`, `class="swatch"`,
   `class="linky colour-clear"`, counted three times each).

   Nothing in this file changes behaviour. No selector adds, removes or
   reorders a control; none is depended on by the inline scripts, which
   query `.colour-pick`, `.colour-clear`, `.swatch[data-for]` and a handful
   of ids — all left untouched.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Legacy custom properties.
   Templates use var(--accent), var(--ink), var(--line), var(--muted) and
   var(--bg) in inline style attributes, so these names have to keep
   resolving. They are remapped onto the night palette.

   --accent stays a warm red-pink because it does double duty: it is the
   "liked" button fill (.admin-btn) and the description-mismatch warning in
   zine_detail.html, which sets color:var(--accent) inline. Rose reads as
   both. Link colour is set separately below so links can be violet without
   turning that warning violet too.
   -------------------------------------------------------------------------- */

:root {
  --ink:    var(--zr-paper);
  --muted:  var(--zr-text-muted);
  --line:   var(--zr-line);
  --bg:     var(--zr-night-900);
  --accent: var(--zr-rose);
}

/* --------------------------------------------------------------------------
   Page frame
   -------------------------------------------------------------------------- */

body {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

main {
  width: 100%;
  max-width: 1060px;
  margin: var(--zr-8) auto var(--zr-16);
  padding: 0 var(--zr-6);
  flex: 1;
}

a { color: var(--zr-violet); }
a:hover { color: #A38FFF; }

h1 { font-size: var(--zr-fs-2xl); margin: 0 0 var(--zr-5); text-wrap: balance; }
h2 { font-size: var(--zr-fs-xl); margin: var(--zr-8) 0 var(--zr-4); text-wrap: balance; }
h3 { font-size: var(--zr-fs-lg); margin: 0 0 var(--zr-3); }

/* A section heading that introduces a grid gets the dotted trailing rule
   from the style guide. */
main > h3 {
  display: flex;
  align-items: center;
  gap: var(--zr-3);
  margin-top: var(--zr-10);
  font-size: var(--zr-fs-md);
  text-transform: uppercase;
  letter-spacing: .12em;
  color: var(--zr-text-muted);
  font-family: var(--zr-font-body);
}
main > h3::after {
  content: "";
  flex: 1;
  height: 1px;
  background-image: repeating-linear-gradient(
    to right, var(--zr-line-strong) 0 3px, transparent 3px 7px);
}

code {
  font-family: var(--zr-font-body);
  font-size: var(--zr-fs-sm);
  background: rgba(0,0,0,.4);
  border: 1px solid var(--zr-line);
  border-radius: var(--zr-r-sm);
  padding: 1px 6px;
  color: var(--zr-amber);
  overflow-wrap: anywhere;
}

.muted { color: var(--zr-text-muted); font-size: var(--zr-fs-sm); }

.spacer { flex: 1; }

/* --------------------------------------------------------------------------
   Header — the masthead
   -------------------------------------------------------------------------- */

header {
  position: sticky;
  top: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  gap: var(--zr-4);
  flex-wrap: wrap;
  padding: var(--zr-3) var(--zr-6);
  background: rgba(11,14,20,.88);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--zr-line);
}

/* Ransom-note wordmark: one paper tile per letter, alternating light and
   dark scraps at slightly different angles. */
header .brand {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  font-family: var(--zr-font-display);
  font-size: 1.05rem;
  line-height: 1;
  text-decoration: none;
  padding: 3px 0;
  flex: none;
}
header .brand b {
  display: inline-block;
  padding: 3px 6px 4px;
  font-weight: 400;
  background: var(--zr-paper);
  color: var(--zr-ink);
  border-radius: 1.5px;
  box-shadow: 0 1px 2px rgba(0,0,0,.6);
}
header .brand b:nth-child(2n) { background: var(--zr-night-700); color: var(--zr-paper); transform: rotate(2.5deg); }
header .brand b:nth-child(3n) { background: var(--zr-paper-mid); color: var(--zr-ink);   transform: rotate(-2deg); }
header .brand b:nth-child(4n) { background: var(--zr-ink);        color: var(--zr-paper); transform: rotate(1.5deg); }
header .brand b:nth-child(5n) { background: var(--zr-paper-dim);  color: var(--zr-ink);   transform: rotate(-3deg); }
header .brand b:nth-child(7n) { transform: rotate(3deg); }
header .brand i {          /* the word gap — an empty, unpainted tile */
  display: inline-block;
  width: var(--zr-2);
  background: none;
  box-shadow: none;
}

/* Header nav links. Scoped above the breakpoint so this rule can never
   out-specify the mobile `display:none` below — which is exactly what it did
   when it lived at (0,2,2) against the media query's (0,1,2). */
@media (min-width: 860.02px) {
header > a:not(.brand):not(.btn) {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px var(--zr-3);
  border-radius: var(--zr-r);
  color: var(--zr-text-muted);
  font-size: var(--zr-fs-sm);
  text-decoration: none;
  transition: color var(--zr-fast) var(--zr-ease),
              background-color var(--zr-fast) var(--zr-ease);
}
header > a:not(.brand):not(.btn):hover {
  color: var(--zr-paper);
  background: rgba(243,239,230,.06);
}
header > a[aria-current="page"] {
  color: var(--zr-violet);
  background: rgba(136,108,255,.13);
}
}
header form { display: inline; margin: 0; }
header button { min-height: 34px; padding: 6px var(--zr-4); font-size: var(--zr-fs-xs); }

/* --------------------------------------------------------------------------
   Mobile tab bar

   The links are the same URLs the header already renders, in the layout the
   mobile style guide specifies. It is shown only below the breakpoint,
   where the header's own link row is hidden.
   -------------------------------------------------------------------------- */

.tabbar { display: none; }

@media (max-width: 860px) {
  /* Only the destinations the bottom tab bar already offers are hidden here.
     Collections, Feed, Links, Admin and Log out have no tab, so they stay in
     the header — hiding them would have removed reach, not decoration. */
  header > a.nav-primary,
  header > .spacer { display: none; }

  header {
    justify-content: center;
    gap: var(--zr-2);
    padding: var(--zr-3) var(--zr-4);
  }
  header .brand { flex-basis: 100%; justify-content: center; margin-bottom: var(--zr-1); }
  header > a { font-size: var(--zr-fs-xs); padding: 6px var(--zr-3); }

  body { padding-bottom: 78px; }

  .tabbar {
    display: flex;
    position: fixed;
    bottom: 0; left: 0; right: 0;
    z-index: 50;
    align-items: center;
    justify-content: space-around;
    padding: 7px max(var(--zr-2), env(safe-area-inset-left))
             calc(7px + env(safe-area-inset-bottom))
             max(var(--zr-2), env(safe-area-inset-right));
    background: rgba(11,14,20,.94);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    border-top: 1px solid var(--zr-line);
  }
  .tabbar a, .tabbar button {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 3px;
    flex: 1;
    min-width: 0;
    padding: 5px 4px;
    border: 0;
    border-radius: var(--zr-r);
    background: none;
    box-shadow: none;
    color: var(--zr-text-faint);
    font-family: var(--zr-font-body);
    font-size: 10px;
    text-decoration: none;
    min-height: 0;
  }
  .tabbar a[aria-current="page"] {
    color: var(--zr-violet);
    background: rgba(136,108,255,.13);
  }
  .tabbar form { flex: 1; display: flex; margin: 0; }
  .tabbar svg { width: 21px; height: 21px; }
}

/* --------------------------------------------------------------------------
   Cards and grids
   -------------------------------------------------------------------------- */

.card {
  position: relative;
  background-color: var(--zr-surface);
  background-image: var(--zr-paper-dark);
  background-size: 300px auto;
  background-blend-mode: overlay;
  border: 1px solid var(--zr-line);
  border-radius: var(--zr-r);
  box-shadow: var(--zr-shadow-sm);
  padding: var(--zr-5);
  margin-bottom: var(--zr-5);
}

.card h3 {
  font-size: var(--zr-fs-md);
  color: var(--zr-paper);
  margin-bottom: var(--zr-3);
}

.card > strong,
.card a > strong {
  font-family: var(--zr-font-display);
  font-size: var(--zr-fs-md);
  letter-spacing: var(--zr-track-display);
  font-weight: 400;
  color: var(--zr-paper);
  display: block;
  margin-top: var(--zr-1);
}

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  gap: var(--zr-5);
  align-items: start;
  margin-bottom: var(--zr-5);
}
.grid .card { margin-bottom: 0; height: 100%; }

/* Tilt is owned by the collage layer, which sets it per card from --tilt.
   The two hardcoded angles that used to live here were (0,3,0) and beat the
   collage's (0,1,0) `.card` rule, so half of every grid ignored the
   randomiser and kept the same two angles on every visit. */
.grid > .card { transition: transform var(--zr-med) var(--zr-ease),
                            box-shadow var(--zr-med) var(--zr-ease); }
.grid > .card:hover { transform: translateY(-3px) rotate(0deg); box-shadow: var(--zr-shadow-lg); }

.card a { text-decoration-thickness: 1px; text-underline-offset: 3px; }
.card a:has(.thumb), .card a:has(img) { text-decoration: none; }
.card a:hover strong { color: var(--zr-violet); }


/* --------------------------------------------------------------------------
   Section band (Discover's "Racks near you")
   -------------------------------------------------------------------------- */

.band {
  margin: 0 0 var(--zr-10);
  padding-bottom: var(--zr-6);
  border-bottom: 1px solid var(--zr-line-strong);
}
.band h2 { margin: var(--zr-1) 0 var(--zr-2); }

/* --------------------------------------------------------------------------
   Buttons
   -------------------------------------------------------------------------- */

button, .btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--zr-2);
  min-height: 38px;
  padding: 9px var(--zr-5);
  border: 1px solid transparent;
  border-radius: var(--zr-r);
  background: var(--zr-violet);
  color: var(--zr-white);
  font-family: var(--zr-font-body);
  font-size: var(--zr-fs-sm);
  font-weight: 600;
  letter-spacing: .01em;
  text-decoration: none;
  cursor: pointer;
  box-shadow: var(--zr-glow-violet);
  transition: transform var(--zr-fast) var(--zr-ease),
              background-color var(--zr-fast) var(--zr-ease),
              border-color var(--zr-fast) var(--zr-ease),
              box-shadow var(--zr-fast) var(--zr-ease);
}
button:hover, .btn:hover { background: #9A81FF; transform: translateY(-1px); }
button:active, .btn:active { background: var(--zr-violet-deep); transform: translateY(0); }
button:disabled { opacity: .45; cursor: not-allowed; transform: none; }

button.secondary, .btn.secondary, .secondary {
  background: transparent;
  color: var(--zr-paper);
  border-color: var(--zr-line-strong);
  box-shadow: none;
  font-weight: 500;
}
button.secondary:hover, .btn.secondary:hover, .secondary:hover {
  background: rgba(243,239,230,.06);
  border-color: var(--zr-paper-dim);
  color: var(--zr-paper);
}

/* .admin-btn is the staff Admin link in the header and the "liked" state of
   every heart button. Both want to stand apart from the violet primary. */
.admin-btn {
  background: var(--zr-rose);
  color: var(--zr-night-900);
  box-shadow: 0 0 0 1px rgba(255,107,139,.4), 0 6px 18px rgba(255,107,139,.24);
}
.admin-btn:hover { background: #FF8AA3; }
.admin-btn:active { background: #E85878; }

/* --------------------------------------------------------------------------
   Tags and badges
   -------------------------------------------------------------------------- */

.tag {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  background: rgba(243,239,230,.05);
  border: 1px solid var(--zr-line-strong);
  border-radius: var(--zr-r-pill);
  padding: 3px 11px;
  font-size: var(--zr-fs-xs);
  color: var(--zr-text-muted);
  margin: 2px;
  text-decoration: none;
  transition: color var(--zr-fast) var(--zr-ease),
              border-color var(--zr-fast) var(--zr-ease),
              background-color var(--zr-fast) var(--zr-ease);
}
a.tag:hover {
  color: var(--zr-paper);
  border-color: var(--zr-paper-dim);
  background: rgba(243,239,230,.09);
}
.tag a { color: inherit; text-decoration: none; }

/* .tag.ai marks both an AI-suggested tag and the selected sort/filter chip. */
.tag.ai {
  background: var(--zr-violet);
  border-color: transparent;
  color: var(--zr-white);
  font-weight: 500;
}
a.tag.ai:hover { background: #9A81FF; color: var(--zr-white); }

/* The inline × inside a tag is a form button; shrink it back to a glyph. */
.tag button, .tag .secondary {
  min-height: 0;
  padding: 0 4px;
  border: 0;
  background: none;
  box-shadow: none;
  color: var(--zr-text-faint);
  font-size: var(--zr-fs-sm);
  line-height: 1;
}
.tag button:hover { background: none; color: var(--zr-rose); transform: none; }

.badge {
  display: inline-flex;
  align-items: center;
  border-radius: var(--zr-r-sm);
  border: 1px solid currentColor;
  background: rgba(0,0,0,.3);
  padding: 2px 9px;
  font-size: var(--zr-fs-xs);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--zr-paper-dim);
}
.badge.approved   { color: var(--zr-sage); }
.badge.pending,
.badge.processing { color: var(--zr-amber); }
.badge.rejected   { color: var(--zr-rose); }
.badge.failed     { color: var(--zr-violet); }

/* --------------------------------------------------------------------------
   Covers and thumbnails
   -------------------------------------------------------------------------- */

.thumb {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 3/4;
  object-fit: cover;
  border: 1px solid var(--zr-line);
  border-radius: var(--zr-r-sm);
  margin-bottom: var(--zr-3);
  background: var(--zr-night-700);
  box-shadow: var(--zr-shadow-sm);
}
.thumb.ph {
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--zr-text-faint);
  font-size: 1.6rem;
  background-color: var(--zr-night-700);
  background-image: var(--zr-paper-griddk);
  background-size: 130px auto;
}

.cover {
  display: block;
  width: 100%;
  max-width: 420px;
  height: auto;
  border: 1px solid var(--zr-line-strong);
  border-radius: var(--zr-r);
  background: var(--zr-night-700);
  box-shadow: var(--zr-shadow-lg);
}
.cover-missing { color: var(--zr-text-muted); font-size: var(--zr-fs-sm); }
@media (max-width: 600px) { .cover { max-width: 100%; } }

/* --------------------------------------------------------------------------
   Forms
   -------------------------------------------------------------------------- */

input, textarea, select, button { font: inherit; }

input[type=text], input[type=password], input[type=email], input[type=url],
input[type=search], input[type=number], input[type=date], textarea, select {
  width: 100%;
  padding: 9px var(--zr-4);
  min-height: 40px;
  background: var(--zr-surface-sunk);
  border: 1px solid var(--zr-line-strong);
  border-radius: var(--zr-r);
  color: var(--zr-paper);
  font-family: var(--zr-font-body);
  font-size: var(--zr-fs-base);
  transition: border-color var(--zr-fast) var(--zr-ease),
              box-shadow var(--zr-fast) var(--zr-ease);
}
textarea { min-height: 96px; line-height: var(--zr-lh-body); resize: vertical; }

input:focus, textarea:focus, select:focus {
  outline: none;
  border-color: var(--zr-violet);
  box-shadow: 0 0 0 3px rgba(136,108,255,.22);
}
::placeholder { color: var(--zr-text-faint); opacity: 1; }

/* Native select needs an explicit option colour or some browsers draw the
   list with the page's light default text on a light popup. */
select option { background: var(--zr-night-800); color: var(--zr-paper); }

input[type=file] {
  width: 100%;
  padding: var(--zr-3);
  background: rgba(0,0,0,.22);
  border: 1.5px dashed var(--zr-line-strong);
  border-radius: var(--zr-r);
  color: var(--zr-text-muted);
  font-size: var(--zr-fs-sm);
  cursor: pointer;
}
input[type=file]:hover { border-color: var(--zr-violet); background: rgba(136,108,255,.07); }
input[type=file]::file-selector-button {
  margin-right: var(--zr-3);
  padding: 6px var(--zr-4);
  border: 1px solid var(--zr-line-strong);
  border-radius: var(--zr-r-sm);
  background: var(--zr-night-700);
  color: var(--zr-paper);
  font-family: var(--zr-font-body);
  font-size: var(--zr-fs-xs);
  cursor: pointer;
}

input[type=checkbox], input[type=radio] {
  appearance: none;
  width: 18px; height: 18px;
  margin: 0 6px 0 0;
  vertical-align: -3px;
  border: 1.6px solid var(--zr-line-strong);
  background: var(--zr-surface-sunk);
  cursor: pointer;
  transition: background-color var(--zr-fast) var(--zr-ease),
              border-color var(--zr-fast) var(--zr-ease);
}
input[type=checkbox] { border-radius: var(--zr-r-sm); }
input[type=radio]    { border-radius: var(--zr-r-pill); }
input[type=checkbox]:checked, input[type=radio]:checked {
  background-color: var(--zr-violet);
  border-color: var(--zr-violet);
}
input[type=checkbox]:checked {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m4.6 12.6 4.8 5.1L19.6 6.4'/%3E%3C/svg%3E");
  background-size: 12px; background-position: center; background-repeat: no-repeat;
}
input[type=radio]:checked { box-shadow: inset 0 0 0 3.5px var(--zr-surface-sunk); }

label { color: var(--zr-text); font-size: var(--zr-fs-sm); }
label .muted { display: block; margin-top: 4px; }

/* Django's <ul class="messages"> — also reused for form errors on upload. */
.messages { list-style: none; padding: 0; margin: 0 0 var(--zr-5); display: grid; gap: var(--zr-2); }
.messages li {
  list-style: none;
  padding: var(--zr-3) var(--zr-4);
  border-radius: var(--zr-r);
  border-left: 3px solid var(--zr-amber);
  background: rgba(255,181,112,.10);
  color: var(--zr-paper);
  font-size: var(--zr-fs-sm);
}

details summary { padding: var(--zr-2) 0; }
details[open] summary { color: var(--zr-paper); }

hr { border: 0; height: 1px; background: var(--zr-line-strong); }

/* --------------------------------------------------------------------------
   Profile
   -------------------------------------------------------------------------- */

.profile-banner {
  display: block;
  width: 100%;
  aspect-ratio: 3/1;
  object-fit: cover;
  border: 1px solid var(--zr-line);
  border-radius: var(--zr-r-lg);
  margin-bottom: -2.5rem;
  box-shadow: var(--zr-shadow);
}
.profile-head { display: flex; align-items: flex-end; gap: var(--zr-4); margin-bottom: var(--zr-5); }
.profile-head h1 { margin: 0 0 .1rem; }
.avatar {
  width: 96px; height: 96px;
  flex: none;
  border-radius: 50%;
  object-fit: cover;
  border: 3px solid var(--zr-night-800);
  background: var(--zr-night-700);
  box-shadow: var(--zr-shadow);
}
.avatar.ph {
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--zr-text-faint);
  font-size: 2rem;
  border-color: var(--zr-line-strong);
}
.profile-facts { display: grid; grid-template-columns: auto 1fr; gap: .35rem var(--zr-4); margin: 0; }
.profile-facts dt { font-size: var(--zr-fs-sm); }
.profile-facts dd { margin: 0; }

.image-slot { padding: var(--zr-3) 0; border-top: 1px solid var(--zr-line); }
.image-slot:first-of-type { border-top: none; }

/* --------------------------------------------------------------------------
   Rack theme editor

   Styled only. The markup, its class attributes and their order are exactly
   as the templates emit them, because tests count `class="colour-pick"`,
   `class="swatch"` and `class="linky colour-clear"` and the inline script
   selects on those same names.
   -------------------------------------------------------------------------- */

.colour-fields { display: flex; gap: var(--zr-4); flex-wrap: wrap; }
.colour-field  { flex: 1 1 200px; min-width: 200px; }
.colour-row    { display: flex; align-items: center; gap: .4rem; margin-top: .25rem; }
.colour-row input[type=text] { flex: 1; min-width: 0; font-family: var(--zr-font-body); }

/* The native picker is an <input>, so it has to opt out of the field styling
   above rather than inherit a 40px tall text box. */
.colour-pick {
  width: 2.2rem; height: 2.2rem;
  min-height: 0;
  padding: 0;
  border: 1px solid var(--zr-line-strong);
  border-radius: var(--zr-r);
  background: none;
  cursor: pointer;
  flex: none;
}

/* No background here: the editor script assigns .swatch background inline on
   every render, including the derived value for a blank field. A background
   in this rule (or worse, an !important) would fight it. */
.swatch {
  width: 1.6rem; height: 1.6rem;
  flex: none;
  border-radius: var(--zr-r);
  border: 1px solid var(--zr-line-strong);
}
.swatch.is-default { border-style: dashed; opacity: .6; }

.linky {
  background: none;
  border: none;
  box-shadow: none;
  color: var(--zr-violet);
  padding: 0;
  min-height: 0;
  font-size: var(--zr-fs-xs);
  font-weight: 400;
  cursor: pointer;
  text-decoration: underline;
}
.linky:hover { background: none; color: #A38FFF; transform: none; }

/* --------------------------------------------------------------------------
   Rack theming — the creator's colours are sovereign

   A rack is somebody's zine table. The server validates that each colour is
   a well-formed #rrggbb (that is the CSS-injection guard) and nothing else:
   no minimum contrast, no automatic text flip, no fallback that overrides a
   value once it is present. Black on black renders as black on black.

   The site chrome is dark, so every component that appears inside a themed
   rack has to stop asserting its own colour and inherit the creator's ink
   instead — otherwise a creator who picks a white background gets dark
   chrome pasted onto it. The fallbacks below are theming.DEFAULT_BG and
   theming.DEFAULT_INK verbatim, so an absent variable resolves exactly as
   it did before this restyle.
   -------------------------------------------------------------------------- */

.rack-themed {
  background: var(--rack-bg, #ffffff);
  color: var(--rack-ink, #1a1a1a);
  font-family: var(--rack-font, inherit);
  border: 1px solid var(--zr-line-strong);
  border-radius: var(--zr-r-lg);
  padding: var(--zr-6) var(--zr-8);
  box-shadow: var(--zr-shadow-lg);
}

/* Rack.\_declarations() emits --rack-accent ONLY when the creator set at least
   one colour; --rack-font is always emitted. So an unthemed rack — the default
   state of every rack — reaches these rules with no --rack-accent at all, and
   the fallback is what actually renders. It is theming.DEFAULT_ACCENT
   (#c0392b) verbatim, NOT the site's --accent: those differ, and using the
   site value here dropped an untouched rack's links and primary buttons from
   5.0:1 to 2.7:1 against the default white ground. */
.rack-themed a { color: var(--rack-accent, #c0392b); }

/* The creator's typeface has to reach the elements the site skin gives a face
   to, or picking "Book serif" would restyle body copy only and leave every
   heading and zine title in the site's display face. Each selector below is
   specific enough to beat the rule it is undoing:
     h1..h4            (0,0,1)  <  .rack-themed h1            (0,1,1)
     .card a > strong  (0,1,2)  <  .rack-themed .card a > strong (0,2,2)
     button, .btn      (0,0,1)  <  .rack-themed button        (0,1,1)      */
.rack-themed h1, .rack-themed h2, .rack-themed h3, .rack-themed h4,
.rack-themed strong,
.rack-themed .card h3,
.rack-themed .card > strong,
.rack-themed .card a > strong,
.rack-themed .card a:hover strong,
.rack-themed button, .rack-themed .btn,
.rack-themed input, .rack-themed select, .rack-themed textarea,
.rack-themed .tag, .rack-themed .badge, .rack-themed code {
  font-family: var(--rack-font, inherit);
}
.rack-themed h1, .rack-themed h2, .rack-themed h3, .rack-themed h4,
.rack-themed strong,
.rack-themed .card h3,
.rack-themed .card > strong,
.rack-themed .card a > strong,
.rack-themed .card a:hover strong {
  color: inherit;
}
.rack-themed .muted { color: var(--rack-ink, #1a1a1a); opacity: .7; }

/* Cards, tags and thumbs inside a themed rack draw themselves in the
   creator's ink rather than the site's night palette. */
.rack-themed .card {
  background: transparent;
  background-image: none;
  border-color: currentColor;
  box-shadow: none;
  opacity: .98;
}
/* (0,4,0) — .grid > .card:hover is (0,3,0) and would otherwise drop a shadow
   tuned for the dark chrome onto a creator's light paper. */
.rack-themed .grid > .card:hover { box-shadow: 0 4px 16px rgba(0,0,0,.16); }
/* (0,4,1) so a reordering of this file cannot let the violet washi sticker
   back onto a creator's rack; the base rule is (0,3,1). */

.rack-themed .tag {
  background: transparent;
  border-color: currentColor;
  color: inherit;
  opacity: .85;
}
/* a.tag:hover is (0,2,1) and beat the plain .rack-themed .tag at (0,2,0),
   painting near-white labels onto a white rack at 1.06:1. */
.rack-themed a.tag:hover {
  background: transparent;
  border-color: currentColor;
  color: inherit;
  opacity: 1;
}
.rack-themed .tag.ai,
.rack-themed a.tag.ai:hover {           /* (0,4,1) beats a.tag.ai:hover (0,3,1) */
  background: var(--rack-accent, #c0392b);
  border-color: transparent;
  color: var(--rack-bg, #ffffff);
  opacity: 1;
}
.rack-themed .badge { background: transparent; }
.rack-themed .thumb, .rack-themed .cover {
  border-color: currentColor;
  background: transparent;
}
.rack-themed .thumb.ph { background-image: none; color: inherit; opacity: .55; }
.rack-themed code {
  background: transparent;
  border-color: currentColor;
  color: inherit;
}
.rack-themed button,
.rack-themed .btn,
.rack-themed .admin-btn {               /* explicit: the liked state takes the
                                           creator's accent, like every other
                                           primary control on their page */
  background: var(--rack-accent, #c0392b);
  color: var(--rack-bg, #ffffff);
  border-color: transparent;
  box-shadow: none;
}
.rack-themed button.secondary,
.rack-themed .btn.secondary,
.rack-themed .secondary {
  background: transparent;
  color: inherit;
  border-color: currentColor;
}
.rack-themed input, .rack-themed textarea, .rack-themed select {
  background: transparent;
  color: inherit;
  border-color: currentColor;
}
/* The closed <select> takes its colour from the selected option on several
   browsers, so a cream-on-dark option rule made a required picker's label
   invisible on a light rack. */
.rack-themed select option {
  background: var(--rack-bg, #ffffff);
  color: var(--rack-ink, #1a1a1a);
}
.rack-themed ::placeholder { color: inherit; opacity: .5; }
.rack-themed summary { color: inherit; }

/* A rack card in a grid of many racks borrows its rack's accent and
   typeface only — never its background, so one creator's choices can't make
   a shared listing unreadable. Unchanged from the original rule. */
.rack-card {
  border-left: 4px solid var(--rack-accent, var(--zr-line-strong));
  font-family: var(--rack-font, inherit);
}
.rack-card a { color: var(--rack-accent, #c0392b); }

.rack-strip { display: flex; gap: .25rem; margin-bottom: .6rem; text-decoration: none; }
.rack-strip-img {
  flex: 1 1 0;
  min-width: 0;
  aspect-ratio: 3/4;
  object-fit: cover;
  border: 1px solid var(--zr-line);
  border-radius: var(--zr-r-sm);
  background: var(--zr-night-700);
}

/* --------------------------------------------------------------------------
   Footer
   -------------------------------------------------------------------------- */

.site-footer {
  border-top: 1px solid var(--zr-line);
  padding: var(--zr-8) var(--zr-6) var(--zr-10);
  color: var(--zr-text-faint);
  font-size: var(--zr-fs-sm);
}
.site-footer .inner {
  max-width: 1060px;
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--zr-4);
  flex-wrap: wrap;
}
.site-footer .sign {
  font-family: var(--zr-font-hand);
  font-size: 1.9rem;
  line-height: 1;
  color: var(--zr-paper-dim);
}

@media (max-width: 860px) {
  main { margin: var(--zr-5) auto var(--zr-10); padding: 0 var(--zr-4); }
  h1 { font-size: var(--zr-fs-xl); }
  .grid { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: var(--zr-4); }
  /* Mobile stays clean and easy to read: keep the collage, drop the tilt. */
  .grid > .card { transform: none !important; }
  .rack-themed { padding: var(--zr-5); }
  .site-footer { padding-bottom: var(--zr-16); }
}
