/* ============================================================
   Gallery — public site + admin
   Palette and typography chosen to match the reference design:
   warm off-white background, italic serif headings, matted tiles.
   ============================================================ */

:root {
  --bg    : #f7f4ee;
  --ink   : #23211c;
  --muted : #6f6a5f;
  --card  : #ffffff;
  --line  : #ddd6c8;
  --accent: #9c3d2e;
  --serif : "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, "Times New Roman", serif;
  --sans  : -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

* {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
}

body {
  margin     : 0;
  background : var(--bg);
  color      : var(--ink);
  line-height: 1.5;
  font-family: var(--serif);
}

img {
  max-width: 100%;
}

a {
  color: inherit;
}

.wrap {
  margin   : 0 auto;
  padding  : 0 1.5rem 4rem;
  max-width: 1180px;
}

/* ---------- header ---------- */

.site-header {
  padding: 2.4rem 0 1.2rem;
}

.site-title {
  margin        : 0;
  font-style    : italic;
  font-weight   : 600;
  font-size     : clamp(1.9rem, 4vw, 2.6rem);
  font-family   : var(--serif);
  letter-spacing: 0.01em;
}

/* ---------- layout ---------- */

.layout {
  display              : grid;
  grid-template-columns: 220px minmax(0, 1fr);
  align-items          : start;
  gap                  : 3rem;
}

/* ---------- navigation ---------- */

/* The sidebar is the grid item, so it has to be the sticky box. A sticky
   element only travels inside its containing block, and the nav's parent
   (.sidebar) shrank to exactly the nav's height, which left it nowhere to
   move — so the nav never stuck. Sticking the grid item instead lets it ride
   down beside the taller works column; align-self keeps it at its content
   height (a stretched item would fill the row and have no travel either). */
.sidebar {
  position  : sticky;
  top       : 1.25rem;
  align-self: start;
  /* A section list taller than the window scrolls on its own, so the last
     links stay reachable instead of being pinned off-screen. */
  max-height: calc(100vh - 2.5rem);
  overflow-y: auto;
}

.nav {
  display       : flex;
  flex-direction: column;
  gap           : 0.55rem;
}

.nav a {
  padding        : 0.08rem 0;
  color          : var(--ink);
  font-style     : italic;
  font-size      : 1.02rem;
  font-family    : var(--serif);
  text-decoration: none;
}

.nav a:hover {
  text-decoration      : underline;
  text-underline-offset: 4px;
}

.nav a[aria-current="page"] {
  font-weight: 700;
}

/* A section that links to another site: the arrow hints that it leaves. The
   gap is a margin, not a space, so a long name can wrap without leaving the
   arrow stranded on a line of its own. */
.nav-external {
  margin-left: 0.25em;
  font-size  : 0.85em;
  white-space: nowrap;
}

/* A link section with no address set yet — shown, but not clickable. */
.nav-empty {
  padding    : 0.08rem 0;
  color      : var(--muted);
  font-style : italic;
  font-size  : 1.02rem;
  font-family: var(--serif);
}

.admin-link {
  display        : inline-block;
  margin-top     : 2.2rem;
  color          : var(--muted);
  font-size      : 0.78rem;
  font-family    : var(--sans);
  letter-spacing : 0.04em;
  text-decoration: none;
}

.admin-link:hover {
  color          : var(--ink);
  text-decoration: underline;
}

/* ---------- mobile menu (hamburger + drawer) ---------- */

/* Hidden until the Responsive section switches them on. Keeping the drawer
   in the document flow by default means a browser without scripting still
   gets the plain stacked menu. */
.nav-toggle,
.nav-close,
.nav-backdrop {
  display: none;
}

.nav-toggle,
.nav-close {
  justify-content: center;
  align-items    : center;
  cursor         : pointer;
  border         : 0;
  border-radius  : 50%;
  background     : transparent;
  padding        : 0;
  width          : 2.5rem;
  height         : 2.5rem;
  color          : var(--ink);
}

.nav-toggle:hover,
.nav-close:hover {
  background: #fff;
}

.nav-toggle svg,
.nav-close svg {
  display: block;
  width  : 1.35rem;
  height : 1.35rem;
}

body.nav-open {
  overflow: hidden;
}

/* ---------- gallery grid ---------- */

.section-title {
  margin     : 0 0 1.5rem;
  font-style : italic;
  font-weight: 600;
  font-size  : 1.6rem;
  font-family: var(--serif);
}

.grid {
  display              : grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap                  : 1.28rem;
}

.tile {
  margin: 0;
}

.frame {
  display   : block;
  box-shadow: none;
  border    : 0;
  background: none;
  padding   : 0;
  overflow  : hidden;
}

.frame img {
  display     : block;
  cursor      : zoom-in;
  border      : 0;
  aspect-ratio: 1 / 1;
  width       : 100%;
  height      : auto;
  object-fit  : cover;
}

/* Under each tile: title, then description, then an optional price. */
.tile figcaption {
  display       : flex;
  flex-direction: column;
  gap           : 0.2rem;
  padding       : 0.6rem 0.25rem 0.1rem;
  color         : var(--muted);
  font-size     : 0.92rem;
}

.tile-title {
  color      : var(--ink);
  font-style : italic;
  line-height: 1.35;
}

.tile-description {
  margin     : 0.1rem 0;
  font-size  : 0.86rem;
  line-height: 1.45;
  /* Newlines in a description are meaningful, so keep them. */
  white-space: pre-line;
}

.tile-price {
  color         : var(--ink);
  font-style    : normal;
  font-size     : 0.82rem;
  font-family   : var(--sans);
  letter-spacing: 0.02em;
}

/* "Sold" / "Available" marker — a quiet pill under each tile. */
.tile-status {
  align-self    : flex-start;
  margin-top    : 0.15rem;
  border        : 1px solid var(--line);
  border-radius : 999px;
  padding       : 0.1rem 0.5rem;
  font-style    : normal;
  font-size     : 0.68rem;
  font-family   : var(--sans);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.tile-status.is-available {
  color: var(--muted);
}

.tile-status.is-sold {
  border-color: var(--accent);
  color       : var(--accent);
  font-weight : 600;
}

.empty {
  border    : 1px dashed var(--line);
  background: rgba(255, 255, 255, 0.5);
  padding   : 2.5rem 1rem;
  color     : var(--muted);
  font-style: italic;
}

.empty a {
  color: var(--ink);
}

/* ---------- text pages ---------- */

.prose {
  max-width  : 44rem;
  font-size  : 1.06rem;
  line-height: 1.75;
}

.prose p {
  margin: 0 0 1.15em;
}

.prose a {
  text-decoration      : underline;
  text-underline-offset: 3px;
}

/* An image inserted into a text page with ![alt](uploads/…). It may be wider
   than the 44rem text column, so it is capped at the column and keeps its own
   proportions. */
.prose img {
  display   : block;
  max-width : 100%;
  height    : auto;
  margin    : 1.6em 0;
}

/* ---------- lightbox ---------- */

.lightbox {
  display        : none;
  position       : fixed;
  justify-content: center;
  align-items    : center;
  z-index        : 60;
  inset          : 0;
  background     : rgba(24, 19, 12, 0.88);
  /* Top room for the close button; side gutters are widened only when the
     arrows are showing so the artwork never slides under them. */
  padding        : 3.75rem 1.5rem 1.5rem;
  /* A gallery note can make the figure taller than a short viewport; scroll
     rather than clipping the top of the artwork. */
  overflow-y     : auto;
}

.lightbox.open {
  display: flex;
}

.lightbox.has-nav {
  padding-right: 4.5rem;
  padding-left : 4.5rem;
}

.lightbox figure {
  /* auto (not 0) so that when the figure overflows the overlay, its top stays
     reachable instead of being cut off above the scrollable area. */
  margin   : auto;
  max-width: min(1100px, 100%);
}

.lightbox img {
  display   : block;
  margin    : 0 auto;
  background: #fff;
  max-width : 100%;
  max-height: 82vh;
}

/* With details below it, leave the artwork a little more room so the note
   stays visible without scrolling. */
.lightbox.has-details img {
  max-height: 68vh;
}

.lightbox figcaption {
  padding-top: 0.8rem;
  color      : #efe9dd;
  font-style : italic;
  font-size  : 1.05rem;
  text-align : center;
}

.lightbox-caption {
  display       : flex;
  flex-direction: column;
  gap           : 0.25rem;
}

/* Empty title/description/price spans are hidden, so the flex gap does not
   leave a phantom line between the rest. */
.lightbox-caption>[hidden] {
  display: none;
}

.lightbox-count {
  color         : rgba(239, 233, 221, 0.65);
  font-style    : normal;
  font-size     : 0.85rem;
  letter-spacing: 0.04em;
}

/* The painting's own note, under its title. */
.lightbox-description {
  margin     : 0 auto;
  max-width  : 40rem;
  color      : rgba(239, 233, 221, 0.8);
  font-style : normal;
  font-size  : 0.9rem;
  line-height: 1.55;
  white-space: pre-line;
}

.lightbox-price {
  color         : #efe9dd;
  font-style    : normal;
  font-size     : 0.92rem;
  font-family   : var(--sans);
  letter-spacing: 0.02em;
}

/* Same sold/available pill as the tile, on the dark overlay. */
.lightbox-status {
  align-self    : center;
  border        : 1px solid rgba(239, 233, 221, 0.35);
  border-radius : 999px;
  padding       : 0.1rem 0.55rem;
  color         : rgba(239, 233, 221, 0.85);
  font-style    : normal;
  font-size     : 0.72rem;
  font-family   : var(--sans);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.lightbox-status.is-sold {
  border-color: #e0a294;
  color       : #e0a294;
  font-weight : 600;
}

/* SVG icon, flex-centred — same treatment as the arrows so the glyph cannot
   drift with font metrics. */
.lightbox-close {
  display        : flex;
  position       : absolute;
  top            : 0.9rem;
  right          : 1.1rem;
  justify-content: center;
  align-items    : center;
  cursor         : pointer;
  border         : none;
  border-radius  : 50%;
  background     : rgba(255, 255, 255, 0.14);
  padding        : 0;
  width          : 2.4rem;
  height         : 2.4rem;
  color          : #fff;
}

.lightbox-close svg {
  display: block;
  width  : 1.2rem;
  height : 1.2rem;
}

.lightbox-close:hover {
  background: rgba(255, 255, 255, 0.28);
}

/* Previous / next arrows. Only useful with more than one image, so they stay
   hidden until the script adds .has-nav to the overlay. The chevrons are SVG
   (not text glyphs) so they sit dead-centre regardless of font metrics. */
.lightbox-nav {
  display      : none;
  position     : absolute;
  top          : 50%;
  transform    : translateY(-50%);
  cursor       : pointer;
  border       : none;
  border-radius: 50%;
  background   : rgba(255, 255, 255, 0.14);
  padding      : 0;
  width        : 3rem;
  height       : 3rem;
  color        : #fff;
  user-select  : none;
}

.lightbox.has-nav .lightbox-nav {
  display        : flex;
  justify-content: center;
  align-items    : center;
}

.lightbox-nav svg {
  display: block;
  width  : 1.5rem;
  height : 1.5rem;
}

.lightbox-prev {
  left: 1.1rem;
}

.lightbox-next {
  right: 1.1rem;
}

.lightbox-nav:hover {
  background: rgba(255, 255, 255, 0.28);
}

.lightbox-nav:focus-visible,
.lightbox-close:focus-visible {
  outline       : 2px solid #fff;
  outline-offset: 3px;
}

.lightbox:focus {
  outline: none;
}

@media (max-width: 640px) {

  /* Arrows drop to the bottom corners on small screens so the artwork keeps
     the full width. */
  .lightbox,
  .lightbox.has-nav {
    padding: 3.25rem 1rem 4.5rem;
  }

  .lightbox img {
    max-height: 72vh;
  }

  .lightbox.has-details img {
    max-height: 60vh;
  }

  .lightbox-nav {
    top      : auto;
    bottom   : 0.9rem;
    transform: none;
    width    : 2.6rem;
    height   : 2.6rem;
  }

  .lightbox-nav svg {
    width : 1.3rem;
    height: 1.3rem;
  }

  .lightbox-prev {
    left: 1rem;
  }

  .lightbox-next {
    right: 1rem;
  }
}

body.no-scroll {
  overflow: hidden;
}

/* ============================================================
   Admin
   ============================================================ */

.admin-header {
  display        : flex;
  flex-wrap      : wrap;
  justify-content: space-between;
  align-items    : baseline;
  gap            : 1rem;
  padding        : 1.6rem 0 1rem;
}

.admin-header .site-title {
  font-size: 1.7rem;
}

.admin-header nav {
  display    : flex;
  gap        : 1.1rem;
  font-size  : 0.9rem;
  font-family: var(--sans);
}

.admin-header nav a {
  border-bottom  : 1px solid var(--line);
  padding-bottom : 1px;
  text-decoration: none;
}

.admin-header nav a:hover {
  border-color: var(--ink);
}

.signed-in {
  color      : var(--muted);
  font-size  : 0.82rem;
  font-family: var(--sans);
}

.card {
  margin-bottom: 1.4rem;
  border       : 1px solid var(--line);
  border-radius: 8px;
  background   : var(--card);
  padding      : 1.3rem 1.4rem;
}

.card h2 {
  margin     : 0 0 0.35rem;
  font-style : italic;
  font-weight: 600;
  font-size  : 1.3rem;
}

.card .hint {
  margin     : 0 0 1rem;
  color      : var(--muted);
  font-size  : 0.85rem;
  font-family: var(--sans);
}

label {
  display    : block;
  margin     : 0.8rem 0 0.25rem;
  color      : var(--muted);
  font-size  : 0.85rem;
  font-family: var(--sans);
}

input[type="text"],
input[type="password"],
input[type="number"],
select,
textarea {
  border       : 1px solid var(--line);
  border-radius: 6px;
  background   : #fff;
  padding      : 0.5rem 0.65rem;
  width        : 100%;
  color        : var(--ink);
  font-size    : 0.95rem;
  font-family  : var(--sans);
}

textarea {
  min-height : 15rem;
  resize     : vertical;
  line-height: 1.6;
}

input:focus,
select:focus,
textarea:focus {
  outline       : 2px solid rgba(156, 61, 46, 0.35);
  outline-offset: 1px;
  border-color  : var(--accent);
}

.btn {
  display        : inline-block;
  cursor         : pointer;
  border         : 1px solid var(--ink);
  border-radius  : 6px;
  background     : var(--ink);
  padding        : 0.5rem 1rem;
  color          : #fff;
  font-size      : 0.9rem;
  font-family    : var(--sans);
  text-decoration: none;
}

.btn:hover {
  opacity: 0.88;
}

.btn.secondary {
  background: #fff;
  color     : var(--ink);
}

.btn.danger {
  border-color: var(--accent);
  background  : #fff;
  color       : var(--accent);
}

.btn.small {
  padding  : 0.25rem 0.6rem;
  font-size: 0.78rem;
}

.btn-row {
  display    : flex;
  flex-wrap  : wrap;
  align-items: center;
  gap        : 0.6rem;
  margin-top : 1rem;
}

.row {
  display    : flex;
  flex-wrap  : wrap;
  align-items: center;
  gap        : 0.6rem;
  border-top : 1px solid var(--line);
  padding    : 0.75rem 0;
}

.row:first-of-type {
  border-top: none;
}

.row input[type="text"] {
  flex : 1 1 170px;
  width: auto;
}

.row select {
  flex : 0 0 auto;
  width: auto;
}

.row .grow {
  flex: 1 1 170px;
}

/* Title / description / price editor, one per image row. */
.image-details {
  display       : flex;
  flex-direction: column;
  align-items   : flex-start;
  gap           : 0.4rem;
  margin        : 0;
  width         : 100%;
  min-width     : 210px;
  max-width     : 340px;
}

/* Outranks the generic `table.works input[type="text"]` sizing above/below. */
table.works .image-details input[type="text"],
.image-details textarea {
  padding  : 0.35rem 0.5rem;
  width    : 100%;
  font-size: 0.88rem;
}

.image-details textarea {
  /* The global textarea rule is sized for a page body. */
  min-height : 3.4rem;
  line-height: 1.45;
}

/* Inline checkbox + label, e.g. the Sold box on each image row. */
.check {
  display            : inline-flex;
  align-items        : center;
  gap                : 0.4rem;
  cursor             : pointer;
  color              : var(--ink);
  font-size          : 0.85rem;
  font-family        : var(--sans);
  user-select        : none;
  -webkit-user-select: none;
}

.check input[type="checkbox"] {
  margin      : 0;
  width       : auto;
  accent-color: var(--accent);
}

.sold-check input:checked+span {
  color      : var(--accent);
  font-weight: 600;
}

.dropzone {
  display      : block;
  cursor       : pointer;
  margin-bottom: 1rem;
  border       : 2px dashed var(--line);
  border-radius: 8px;
  background   : rgba(255, 255, 255, 0.6);
  padding      : 1.1rem;
  color        : var(--muted);
  font-size    : 0.9rem;
  font-family  : var(--sans);
  text-align   : center;
}

.dropzone:hover,
.dropzone.drag {
  border-color: var(--accent);
  background  : #faf3ee;
  color       : var(--ink);
}

.dropzone input[type="file"] {
  display: none;
}

.dropzone strong {
  color: var(--ink);
}

.table-wrap {
  overflow-x: auto;
}

table.works {
  border-collapse: collapse;
  width          : 100%;
  font-size      : 0.88rem;
  font-family    : var(--sans);
}

table.works th {
  padding       : 0.4rem 0.5rem;
  color         : var(--muted);
  font-weight   : 600;
  font-size     : 0.72rem;
  letter-spacing: 0.05em;
  text-align    : left;
  text-transform: uppercase;
}

table.works td {
  vertical-align: middle;
  border-top    : 1px solid var(--line);
  padding       : 0.55rem 0.5rem;
}

table.works .thumb {
  display      : block;
  border-radius: 3px;
  background   : #f1ede4;
  width        : 68px;
  height       : 68px;
  object-fit   : cover;
}

table.works .file {
  color    : var(--muted);
  font-size: 0.74rem;
}

table.works input[type="text"] {
  padding  : 0.35rem 0.5rem;
  width    : auto;
  min-width: 150px;
  font-size: 0.88rem;
}

/* --- Hand-picked image order (admin gallery cards) --- */

.order-hint {
  margin-bottom: 0.5rem;
}

.order-status {
  margin-left: 0.35rem;
  color      : var(--accent);
  font-size  : 0.8rem;
}

.order-status.saving {
  color: var(--muted);
}

table.works .order-col {
  width      : 1%;
  white-space: nowrap;
}

table.works .order-cell {
  white-space: nowrap;
}

.drag-handle {
  display            : inline-flex;
  align-items        : center;
  vertical-align     : middle;
  cursor             : grab;
  margin-right       : 0.3rem;
  color              : var(--muted);
  user-select        : none;
  -webkit-user-select: none;
}

.drag-handle:active {
  cursor: grabbing;
}

.move-btns {
  display       : inline-flex;
  align-items   : center;
  vertical-align: middle;
  gap           : 0.25rem;
}

.move-btns .btn {
  padding    : 0.2rem 0.5rem;
  line-height: 1;
}

.move-btns .btn[disabled] {
  opacity: 0.35;
  cursor : default;
}

table.works tr.dragging {
  opacity   : 0.55;
  background: #faf3ee;
}

table.works tr.dragging td {
  border-top-color: transparent;
}

/* A sold painting is dimmed in the admin list so it is obvious at a glance. */
table.works tr.sold-row .thumb {
  opacity: 0.5;
}

.flash {
  margin       : 0 0 1.2rem;
  border-radius: 6px;
  padding      : 0.7rem 1rem;
  font-size    : 0.92rem;
  font-family  : var(--sans);
}

.flash.ok {
  border    : 1px solid #cfe0cc;
  background: #eef4ec;
  color     : #31502f;
}

.flash.err {
  border    : 1px solid #e6c4ba;
  background: #f9eae6;
  color     : #7c2d1f;
}

.badge {
  border        : 1px solid var(--line);
  border-radius : 99px;
  padding       : 0.1rem 0.55rem;
  color         : var(--muted);
  font-size     : 0.72rem;
  font-family   : var(--sans);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space   : nowrap;
}

.muted {
  color: var(--muted);
}

/* ---------- login page ---------- */

.login-wrap {
  margin   : 12vh auto 0;
  padding  : 0 1rem;
  max-width: 400px;
}

.login-wrap .card {
  padding: 1.8rem;
}

.login-wrap h1 {
  font-size: 1.5rem;
}

/* ============================================================
   Responsive
   ============================================================ */

@media (max-width: 900px) {
  .layout {
    grid-template-columns: 1fr;
    gap                  : 1.5rem;
  }

  /* One column: there is no tall works column beside the menu any more, so
     nothing is left to stick against — and the drawer breakpoint below
     positions the sidebar itself. */
  .sidebar {
    position  : static;
    align-self: auto;
    max-height: none;
    overflow  : visible;
  }

  .nav {
    flex-direction: row;
    flex-wrap     : wrap;
    gap           : 0.4rem 1.1rem;
  }

  .admin-link {
    margin-top: 0.9rem;
  }

  .grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap                  : 1.1rem;
  }

  .site-header {
    padding: 1.6rem 0 0.8rem;
  }
}

@media (max-width: 640px) {
  .site-header {
    display    : flex;
    align-items: center;
    gap        : 0.7rem;
    padding    : 1.5rem 0 1rem;
  }

  /* Only offer the button when a script can drive the drawer. */
  .js .nav-toggle {
    display: flex;
  }

  /* The sidebar leaves the flow and becomes an off-canvas drawer. */
  .js .sidebar {
    display            : flex;
    position           : fixed;
    top                : 0;
    bottom             : 0;
    left               : 0;
    flex-direction     : column;
    transform          : translateX(-100%);
    /* Hides the drawer from the tab order and assistive tech once it is shut,
       but only after the slide-out has finished — visibility has no duration,
       it is simply delayed on close and applied at once on open. */
    visibility         : hidden;
    z-index            : 70;
    transition         : transform 0.25s ease, visibility 0s linear 0.25s;
    box-shadow         : 0 0 2.5rem rgba(24, 19, 12, 0.28);
    border-right       : 1px solid var(--line);
    background         : var(--bg);
    padding            : 1rem 1.25rem 1.5rem;
    width              : min(78%, 17rem);
    overflow-y         : auto;
    overscroll-behavior: contain;
  }

  body.nav-open .sidebar {
    transform : none;
    visibility: visible;
    transition: transform 0.25s ease, visibility 0s linear 0s;
  }

  .js .nav-close {
    display      : flex;
    align-self   : flex-end;
    margin-bottom: 0.75rem;
  }

  .js .sidebar .nav {
    position      : static;
    flex-direction: column;
    gap           : 0.1rem;
  }

  .js .sidebar .nav a {
    padding  : 0.5rem 0.25rem;
    font-size: 1.08rem;
  }

  .js .sidebar .admin-link {
    margin-top : auto;
    padding-top: 1.25rem;
  }

  .js body.nav-open .nav-backdrop {
    display   : block;
    position  : fixed;
    z-index   : 65;
    inset     : 0;
    background: rgba(24, 19, 12, 0.45);
  }
}

@media (prefers-reduced-motion: reduce) {
  .js .sidebar {
    transition: none;
  }
}

@media (max-width: 600px) {
  .wrap {
    padding: 0 1rem 3rem;
  }

  .grid {
    grid-template-columns: 1fr;
  }

  .section-title {
    font-size: 1.4rem;
  }

  .card {
    padding: 1rem 1rem;
  }

  .admin-header {
    padding-top: 1.1rem;
  }
}