/* OneSunny CMS.
 *
 * ⚠️ THE SHOP'S PALETTE, A TOOL'S LAYOUT. The greens are lifted from
 * onesunny-website/assets/css/site.css so the two do not feel like two
 * companies. Everything else is denser and plainer on purpose: an admin is
 * judged on how fast a row can be found and changed, not on whitespace.
 *
 * ⛔ NO WEBFONTS, same rule as the shop - system stack only.
 */

:root {
  color-scheme: light;
  --paper:  #F2F6EC;
  --card:   #FFFFFF;
  --ink:    #16241B;
  --body:   #47533F;
  --muted:  #68745E;
  --rule:   #DFE7D3;
  --leaf:   #106838;
  --leaf-dk:#0B4F2A;
  --pale:   #DCEBCF;
  --warn:   #8A5A00;
  --bad:    #8A2B2B;
  --sans:   system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
}

*, *::before, *::after { box-sizing: border-box; }
body {
  margin: 0; background: var(--paper); color: var(--body);
  font-family: var(--sans); font-size: 15px; line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}
a { color: var(--leaf); }
h1, h2, h3 { color: var(--ink); line-height: 1.25; margin: 0 0 0.5rem; }
h1 { font-size: 1.5rem; }
h2 { font-size: 1.15rem; margin-top: 2rem; }
img { max-width: 100%; display: block; }

/* ------------------------------------------------------------- chrome ---- */

.top {
  display: flex; align-items: center; justify-content: space-between;
  gap: 0.6rem 1rem; padding: 0.65rem 1.25rem; flex-wrap: wrap;
  background: var(--leaf); color: #fff;
}
.top__brand { color: #fff; text-decoration: none; font-weight: 600; letter-spacing: 0.01em; }
.top__brand span { opacity: 0.7; font-weight: 400; }
.top__right { display: flex; align-items: center; gap: 1rem; }
/* ⚠️ nowrap: on a phone these four short items break mid-phrase ("View / shop",
   "Sign / out") and the bar grows to three ragged lines. */
.top__brand, .top__shop, .top__who, .top .btn { white-space: nowrap; }
.top__shop, .top__who { color: #fff; font-size: 0.875rem; opacity: 0.85; }
.top__right form { margin: 0; }

.shell { display: flex; align-items: flex-start; min-height: calc(100vh - 46px); }
.shell--bare { justify-content: center; padding-top: 4rem; }
.side {
  flex: 0 0 200px; padding: 1.25rem 0.75rem; display: flex; flex-direction: column; gap: 0.15rem;
  border-right: 1px solid var(--rule); min-height: calc(100vh - 46px);
}
.side a {
  display: block; padding: 0.5rem 0.75rem; border-radius: 7px;
  text-decoration: none; color: var(--body);
}
.side a:hover { background: var(--pale); }
.side a.on { background: var(--leaf); color: #fff; }
.main { flex: 1 1 auto; padding: 1.5rem 1.75rem 4rem; max-width: 1100px; }
.shell--bare .main { flex: 0 1 26rem; }

.pagehead { display: flex; align-items: center; justify-content: space-between; gap: 1rem; margin-bottom: 1.25rem; }
.pagehead h1 { margin: 0; }

/* -------------------------------------------------------------- pieces --- */

.card {
  background: var(--card); border: 1px solid var(--rule); border-radius: 10px;
  padding: 1.25rem; margin: 0 0 1.25rem;
}
.flash {
  background: var(--pale); border: 1px solid var(--leaf); color: var(--ink);
  padding: 0.6rem 0.9rem; border-radius: 8px; margin: 0 0 1.25rem;
}
.err  { color: var(--bad); font-size: 0.875rem; display: block; margin-top: 0.25rem; }
.hint { color: var(--muted); font-size: 0.8125rem; }
.warn { color: var(--warn); }

.tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr)); gap: 1rem; margin-bottom: 1.5rem; }
.tile { background: var(--card); border: 1px solid var(--rule); border-radius: 10px; padding: 1rem 1.1rem; }
.tile strong { display: block; font-size: 1.6rem; color: var(--ink); line-height: 1.1; }
.tile span { color: var(--muted); font-size: 0.8125rem; }
.tile a { font-size: 0.8125rem; }

table { border-collapse: collapse; width: 100%; background: var(--card); }
th, td { border-bottom: 1px solid var(--rule); padding: 0.55rem 0.7rem; text-align: left; vertical-align: middle; }
th { font-size: 0.75rem; letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted); font-weight: 600; }
tbody tr:hover { background: #FAFCF7; }
td.num, th.num { text-align: right; white-space: nowrap; }
.thumb { width: 40px; height: 40px; object-fit: cover; border-radius: 6px; border: 1px solid var(--rule); }

.pill {
  display: inline-block; padding: 0.1rem 0.5rem; border-radius: 999px;
  font-size: 0.75rem; border: 1px solid var(--rule); background: #fff; color: var(--muted);
}
.pill--on   { background: var(--pale); border-color: var(--leaf); color: var(--leaf-dk); }
.pill--off  { background: #F3F3F1; }
.pill--warn { background: #FBF3E2; border-color: #E3C88B; color: var(--warn); }
.pill--bad  { background: #FBECEC; border-color: #E0B4B4; color: var(--bad); }

/* --------------------------------------------------------------- forms --- */

.field { margin: 0 0 1rem; }
.field > label { display: block; font-size: 0.8125rem; color: var(--muted); margin-bottom: 0.25rem; }
/* ⛔ EXCLUDE THE TYPES THAT MUST NOT BE BOXED - NEVER LIST THE ONES THAT MUST.
   This rule used to name the types it styled: input[type=text], [type=email],
   [type=number], and so on. That silently missed every `<input>` written
   WITHOUT a type attribute - which behaves as type=text but does NOT match
   `input[type=text]`, because the attribute is genuinely absent. 33 fields
   across banner, login, order, product, promotion, settings and users were
   rendering as raw browser default next to styled neighbours; Charles reported
   it on 2026-09-08 as "the text fields are not formatted properly". It also
   missed type=file, and would have missed tel, password and any type added
   later. Written as a deny-list, a new or untyped field is styled by default
   and only a deliberately-excluded one is not - the safe direction. */
input:not([type=checkbox]):not([type=radio]):not([type=hidden]):not([type=submit]):not([type=button]):not([type=reset]):not([type=image]):not([type=range]):not([type=color]),
select, textarea {
  width: 100%; padding: 0.5rem 0.65rem; font: inherit; color: var(--ink);
  background: #fff; border: 1px solid var(--rule); border-radius: 7px;
}
input:focus, select:focus, textarea:focus { outline: 2px solid var(--leaf); outline-offset: 1px; border-color: var(--leaf); }
textarea { min-height: 7rem; resize: vertical; }
.row { display: grid; grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr)); gap: 0 1rem; }
.check { display: flex; align-items: center; gap: 0.5rem; }
.check input { width: auto; }

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 0.4rem;
  padding: 0.5rem 1rem; min-height: 2.35rem;
  border: 1px solid var(--leaf); border-radius: 999px;
  background: var(--leaf); color: #fff; font: inherit; font-size: 0.9375rem;
  text-decoration: none; cursor: pointer;
}
.btn:hover { background: var(--leaf-dk); border-color: var(--leaf-dk); color: #fff; }
.btn--ghost { background: transparent; color: var(--leaf); }
.top .btn--ghost { color: #fff; border-color: rgba(255,255,255,0.6); }
.top .btn--ghost:hover { background: rgba(255,255,255,0.15); }
.btn--sm { padding: 0.3rem 0.75rem; min-height: 2rem; font-size: 0.8125rem; }
.btn--bad { border-color: var(--bad); color: var(--bad); background: transparent; }
.btn--bad:hover { background: var(--bad); color: #fff; }
.btnrow { display: flex; gap: 0.6rem; align-items: center; flex-wrap: wrap; margin-top: 1.25rem; }

.filters { display: flex; gap: 0.6rem; flex-wrap: wrap; align-items: flex-end; margin-bottom: 1rem; }
.filters .field { margin: 0; min-width: 9rem; }
.filters .field--wide { flex: 1 1 16rem; }

.pager { display: flex; gap: 1rem; align-items: center; justify-content: center; margin-top: 1.25rem; color: var(--muted); font-size: 0.875rem; }

/* ---------------------------------------------------------- sign-in ------ */

/* ⭐ THIS CARD IS BUILT TO THE VANSON CMS SIGN-IN FORMAT - Jacelyn, 2026-09-23,
   "in this format", pointing at vansonwebcms.digitalperpetual.com/admin/?r=login.
   That screen is: centred mark, the bare word "CMS" under it in small muted
   type, a LEFT-aligned field label, and a full-width button. The numbers below
   are that screen's, converted from its px to this sheet's rem.

   ⚠️ ONLY THE BRAND BLOCK AND THE HEADINGS ARE CENTRED, not the whole card -
   the label deliberately stays left. An earlier pass centred everything via
   `text-align: center` on .login, which also centred the User ID as it was
   typed, because text-align inherits into the input.

   ⛔ EVERY RULE HERE IS SCOPED UNDER .login. .field, .btnrow and .btn are
   shared with banner, order, product, promotion, settings and users - all of
   them working admin screens where a left-aligned column scans faster. */
.login { background: var(--card); border: 1px solid var(--rule); border-radius: 12px; padding: 1.75rem; }

.login__brand { text-align: center; margin-bottom: 2rem; }
/* ⚠️ THE width/height ATTRIBUTES STAY ON THE <img> at its true 495x370 so the
   browser reserves the right box before the PNG arrives and the card does not
   jolt. The CSS is what actually sizes it: width is set, height is auto.
   ⚠️ SIZED BY WIDTH, WHERE VANSON SIZES BY HEIGHT (60px). Its mark is a
   compact 157x101; this one is a 4:3 stack with the wordmark UNDER the mark,
   so matching the height would shrink "One Sunny" to a smudge. 7rem lands it
   at roughly Vanson's visual weight. */
.login__logo { display: block; width: 7rem; height: auto; margin: 0 auto; }
/* Vanson: margin 8px 0 0; 16px; 600; muted.

   ⚠️ THE GAP IS THE ONE NUMBER NOT COPIED FROM IT - Jacelyn, 2026-09-23: "the
   word cms is too near to the logo". Vanson's 8px works because its PNG carries
   its own breathing room; this one does not - the artwork runs to all four
   edges of the 495x370 canvas (alpha bbox measured full), so the wordmark ends
   flush with the bottom of the image and 8px put "CMS" almost against it.
   1.25rem is the same optical gap Vanson's 8px gives, once the missing padding
   is accounted for.

   ⛔ MUST BE `.login .login__sub`, NOT `.login__sub`. `.login p` below sets
   `margin-top: 0` and scores (0,1,1) against a bare class's (0,1,0), so it
   wins and the gap silently stays at zero - which is exactly what happened
   here twice, at 0.5rem and again at 1.25rem, both measured as 0px before this
   selector was raised to (0,2,0). Do not "simplify" this back to one class. */
.login .login__sub { margin: 1.25rem 0 0; font-size: 1rem; font-weight: 600; color: var(--muted); }

/* Vanson: body.ad-auth h1 - 20px, centred. Only the code and welcome screens
   still carry an h1; the entry screen's is now the brand block above. */
.login h1 { font-size: 1.25rem; text-align: center; margin: 0 0 0.5rem; }
.login p { text-align: center; }

/* Vanson: body.ad-auth .btn - width 100%, centred text. .btnrow is flex, so it
   is switched to a column to stack the code screen's second button full-width
   underneath the first rather than squeezing the two side by side. */
.login .btnrow { flex-direction: column; align-items: stretch; }
.login .btnrow .btn { width: 100%; }
.login p { color: var(--muted); margin-top: 0; }
/* ⚠️ A 2-DIGIT CODE, SO THE BOX IS SIZED FOR TWO. A full-width input invites a
   password, which there is not one of.

   ⛔ BUT width AND font-size HERE HAVE NEVER ACTUALLY APPLIED, and that is not
   new - measured 2026-09-23 with getComputedStyle: this box renders 722px wide
   at 15px, not 5.5rem at 1.75rem. The deny-list rule further up
   (`input:not([type=checkbox]):not([type=radio])...`) carries about nine
   attribute selectors, so it scores (0,9,1) against this rule's (0,2,1) and
   wins on specificity no matter what order they sit in; its `width: 100%` and
   `font: inherit` are what you see. text-align and letter-spacing DO apply,
   because that rule sets neither - which is why the digits are centred inside
   a full-width box rather than in a small one.

   ⭐ LEFT ALONE DELIBERATELY. Full-width is what the Vanson format this card
   was rebuilt to uses for its inputs, so the accident happens to be the
   wanted result. To actually honour the comment above, raise this to
   `.login .field > input[name=code]` - but that is a visible change to the
   code screen and a design decision, not a tidy-up. */
.login input[name=code], .login input[name=pin] {
  width: 5.5rem; font-size: 1.75rem; text-align: center; letter-spacing: 0.15em;
}
.pin {
  font-size: 2.5rem; letter-spacing: 0.15em; color: var(--leaf);
  margin: 0.4rem 0; font-weight: 600;
}

@media (max-width: 760px) {
  .shell { display: block; }
  .side { flex: none; width: auto; min-height: 0; border-right: 0; border-bottom: 1px solid var(--rule);
          flex-direction: row; flex-wrap: wrap; }
  .main { padding: 1.25rem 1rem 3rem; }
  /* ⛔ THE TABLE SCROLLS, NOT THE PAGE - added 2026-09-15. The Products table has
     eight columns and cannot fit a phone, and a table is the widest thing on the
     page: without this the WHOLE page grew to 755px on a 390px screen, so the
     header, the filters and the bulk bar all sat half off-screen and every tap
     needed a sideways scroll first. Measured on a 390px viewport before the fix.
     Making just the table a scrolling block leaves everything else at phone
     width. */
  table { display: block; width: 100%; overflow-x: auto; -webkit-overflow-scrolling: touch; }
}

/* ------------------------------------------------- categories & bulk ----- */
/* Added 2026-09-15 for the Categories screen and the tick-and-act bar on
   Products. Nicole works on forty products at a time and has never edited one
   on its own, so the row has to be big enough to tick on a phone. */

.tabs { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.tab {
  display: inline-flex; align-items: center; gap: 0.4rem;
  padding: 0.4rem 0.75rem; border: 1px solid var(--rule); border-radius: 999px;
  background: var(--card); color: var(--body); text-decoration: none; font-size: 0.9rem;
}
.tab span { font-size: 0.78rem; color: var(--muted); background: var(--paper);
            padding: 0.05rem 0.4rem; border-radius: 999px; }
.tab:hover { border-color: var(--leaf); color: var(--leaf-dk); }
.tab.on { background: var(--leaf); border-color: var(--leaf); color: #fff; font-weight: 600; }
.tab.on span { background: rgba(255,255,255,0.22); color: #fff; }
.tab--warn { border-color: #E3C88B; background: #FBF3E2; }

/* ⚠️ STICKY, BECAUSE THE LIST IS 167 ROWS LONG. Ticking forty products and then
   scrolling back to the top to find the Move button is the whole reason a bulk
   screen gets abandoned after one try. */
.bulkbar {
  position: sticky; top: 0; z-index: 5;
  display: flex; flex-wrap: wrap; gap: 0.6rem; align-items: center;
  padding: 0.6rem 0.75rem; margin-bottom: 0.75rem;
  background: var(--pale); border: 1px solid var(--rule); border-radius: 10px;
}
.bulkbar select { width: auto; min-width: 11rem; }
.bulkbar label { margin: 0; font-weight: 600; color: var(--ink); font-size: 0.9rem; }
.bulkbar__sep { flex: 1 1 0; }

.picks td:first-child, .picks th:first-child { width: 2.2rem; }
.picks input[type=checkbox] { width: 1.15rem; height: 1.15rem; }
.picks tr:hover td { background: var(--paper); }

@media (max-width: 760px) {
  .bulkbar__sep { flex: 0 0 100%; }
}
