/*
Theme Name: Soffguiden
Theme URI: https://soffguiden.se/
Description: Astra child theme for Soffguiden. Adds the server-rendered affiliate product card system — product cards, award toplists and comparison tables built from feed data at render time, never in the browser. Adds no global styling: every rule below is scoped to .sg so existing pages are untouched.
Author: Soffguiden
Template: astra
Version: 1.0.0
Text Domain: soffguiden-child
*/

/* ══════════════════════════════════════════════════════════════════
   Soffguiden design system v1 — component scope only.

   EVERY selector below is scoped under .sg. Nothing here can reach
   Astra's markup. Tokens are declared ON .sg (not :root) so they
   cannot leak into or collide with theme or plugin custom properties.

   Signature: måttbandet — a hairline carrying graduation marks, like
   the edge of a tape measure. The only decorative element in the
   system. It recurs as section divider and as the dimension rule
   beneath every sofa card.

   Colour discipline:
     loden  — endorsement AND action. Award label and the single
              filled button. Nowhere else.
     ochre  — verified money claims only. Its scarcity is what makes
              it read as evidence.
     No red exists in the system. No shadows — cards are hairline-ruled
     entries, which leaves the CTA as the only raised object.
   ══════════════════════════════════════════════════════════════════ */

.sg {
  --sg-linen:      #EFF2ED;
  --sg-surface:    #FAFBF8;
  --sg-sunken:     #E5EAE3;
  --sg-graphite:   #171C18;
  --sg-soft:       #5C6961;
  --sg-faint:      #8A968D;
  --sg-rule:       #CFD7CF;
  --sg-rule-firm:  #A6B2A8;
  --sg-loden:      #2F4739;
  --sg-loden-ink:  #FAFBF8;
  --sg-loden-wash: #E3EBE4;
  --sg-ochre:      #8A6A22;
  --sg-ochre-wash: #F5EEDD;
  --sg-tick:       #A6B2A8;
}

/* Dark tokens.
   Deliberately NOT wired to prefers-color-scheme by default: soffguiden.se
   is a light-only site today, so auto-switching would leave dark cards
   floating on a light page. The palette is complete and one flag away — PHP
   adds .sg-dark-auto to the component wrapper when the `sg_enable_dark_mode`
   filter returns true, at which point the OS preference takes effect. An
   explicit data-theme on <html> always wins, in both directions. */
:root[data-theme="dark"] .sg {
  --sg-linen:      #121611;
  --sg-surface:    #191E1A;
  --sg-sunken:     #0D110C;
  --sg-graphite:   #E7ECE6;
  --sg-soft:       #9EAAA1;
  --sg-faint:      #78857C;
  --sg-rule:       #2C352E;
  --sg-rule-firm:  #465046;
  --sg-loden:      #93BFA3;
  --sg-loden-ink:  #0D110C;
  --sg-loden-wash: #1E2A22;
  --sg-ochre:      #DCB86C;
  --sg-ochre-wash: #2A2415;
  --sg-tick:       #465046;
}

@media (prefers-color-scheme: dark) {
  .sg.sg-dark-auto {
    --sg-linen:      #121611;
    --sg-surface:    #191E1A;
    --sg-sunken:     #0D110C;
    --sg-graphite:   #E7ECE6;
    --sg-soft:       #9EAAA1;
    --sg-faint:      #78857C;
    --sg-rule:       #2C352E;
    --sg-rule-firm:  #465046;
    --sg-loden:      #93BFA3;
    --sg-loden-ink:  #0D110C;
    --sg-loden-wash: #1E2A22;
    --sg-ochre:      #DCB86C;
    --sg-ochre-wash: #2A2415;
    --sg-tick:       #465046;
  }
}

:root[data-theme="light"] .sg {
  --sg-linen:      #EFF2ED;
  --sg-surface:    #FAFBF8;
  --sg-sunken:     #E5EAE3;
  --sg-graphite:   #171C18;
  --sg-soft:       #5C6961;
  --sg-faint:      #8A968D;
  --sg-rule:       #CFD7CF;
  --sg-rule-firm:  #A6B2A8;
  --sg-loden:      #2F4739;
  --sg-loden-ink:  #FAFBF8;
  --sg-loden-wash: #E3EBE4;
  --sg-ochre:      #8A6A22;
  --sg-ochre-wash: #F5EEDD;
  --sg-tick:       #A6B2A8;
}

.sg {
  color: var(--sg-graphite);
  font-size: 16px;
  line-height: 1.55;
  margin: 32px 0;
  -webkit-font-smoothing: antialiased;
}
.sg *,
.sg *::before,
.sg *::after { box-sizing: border-box; }
.sg p { margin: 0; }
.sg a { color: inherit; }
.sg :focus-visible { outline: 2px solid var(--sg-loden); outline-offset: 3px; }

/* ── Signature: the measurement rule ─────────────────────────────── */
.sg-matt {
  height: 13px;
  border-top: 1px solid var(--sg-rule-firm);
  background-image: repeating-linear-gradient(to right, var(--sg-tick) 0 1px, transparent 1px 20px);
  background-size: 100% 5px;
  background-repeat: no-repeat;
  background-position: 0 0;
}
.sg-matt--major {
  background-image:
    repeating-linear-gradient(to right, var(--sg-tick) 0 1px, transparent 1px 20px),
    repeating-linear-gradient(to right, var(--sg-rule-firm) 0 1px, transparent 1px 100px);
  background-size: 100% 5px, 100% 11px;
}

/* ── Type ────────────────────────────────────────────────────────── */
.sg h2, .sg h3, .sg h4 {
  margin: 0;
  font-weight: 660;
  letter-spacing: -0.032em;
  text-wrap: balance;
  color: var(--sg-graphite);
}
.sg h2 { font-size: clamp(1.5rem, 3.4vw, 2rem); line-height: 1.08; }
.sg h3 { font-size: 1.16rem; letter-spacing: -0.02em; line-height: 1.2; }

.sg-lbl {
  font-size: .68rem;
  letter-spacing: .155em;
  text-transform: uppercase;
  color: var(--sg-soft);
  font-weight: 640;
}

/* Numerals are display type: on a measurement brand the number is the
   content, so the unit drops to a lighter weight and the value reads first. */
.sg-figure {
  font-variant-numeric: tabular-nums;
  font-weight: 680;
  letter-spacing: -0.035em;
  white-space: nowrap;
}
/* The gap before the unit is a non-breaking space in the markup, not a margin,
   so the price extracts as "13 995 kr". Only the optical remainder is CSS. */
.sg-figure .sg-unit {
  font-weight: 420;
  letter-spacing: 0;
  font-size: .52em;
  margin-left: .04em;
  color: var(--sg-soft);
}

/* ── Card ────────────────────────────────────────────────────────── */
.sg-cards { display: flex; flex-direction: column; gap: 22px; }

.sg-card {
  background: var(--sg-surface);
  border: 1px solid var(--sg-rule);
  padding: 20px;
  display: grid;
  grid-template-columns: 150px 1fr;
  gap: 20px;
  align-items: start;
}
.sg-card + .sg-card { margin-top: 0; }

.sg-shot {
  aspect-ratio: 1;
  background: var(--sg-sunken);
  border: 1px solid var(--sg-rule);
  overflow: hidden;
}
.sg-shot img {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: contain;
  background: #fff;
}
.sg-shot--empty {
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--sg-faint);
  font-size: .68rem;
  letter-spacing: .1em;
  text-transform: uppercase;
}

.sg-cbody { display: flex; flex-direction: column; gap: 9px; min-width: 0; }

.sg-award {
  align-self: start;
  background: var(--sg-loden);
  color: var(--sg-loden-ink);
  padding: 4px 10px;
  font-size: .66rem;
  letter-spacing: .13em;
  text-transform: uppercase;
  font-weight: 680;
}
.sg-brand { font-size: .82rem; color: var(--sg-soft); }
.sg-why   { color: var(--sg-soft); font-size: .93rem; }

/* Dimension bar — the måttband applied to a product */
.sg-dims { margin-top: 4px; padding-top: 11px; border-top: 1px solid var(--sg-rule); }
.sg-dimbar {
  height: 11px;
  background-image: repeating-linear-gradient(to right, var(--sg-tick) 0 1px, transparent 1px 14px);
  background-size: 100% 4px;
  background-repeat: no-repeat;
  border-top: 1px solid var(--sg-rule-firm);
}
.sg-dimvals { display: flex; justify-content: space-between; gap: 12px; margin-top: 7px; flex-wrap: wrap; }
.sg-dimvals span { font-size: .78rem; color: var(--sg-soft); font-variant-numeric: tabular-nums; }
.sg-dimvals b { color: var(--sg-graphite); font-weight: 620; }

/* Price head + ladder */
.sg-pricehead { display: flex; align-items: baseline; gap: 12px; margin-top: 6px; flex-wrap: wrap; }
.sg-pricehead .sg-figure { font-size: 1.9rem; }
.sg-was {
  color: var(--sg-soft);
  text-decoration: line-through;
  font-size: .85rem;
  font-variant-numeric: tabular-nums;
}
/* Ochre: verified money claims only. */
.sg-save {
  color: var(--sg-ochre);
  font-weight: 660;
  font-size: .85rem;
  background: var(--sg-ochre-wash);
  padding: 2px 7px;
  font-variant-numeric: tabular-nums;
}

.sg-ladder { margin-top: 8px; border-top: 1px solid var(--sg-rule); }
.sg-rung {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
  padding: 9px 0;
  border-bottom: 1px solid var(--sg-rule);
}
.sg-rung:last-child { border-bottom: 0; }
.sg-rung .sg-m { font-size: .88rem; }
.sg-rung .sg-m em { font-style: normal; color: var(--sg-faint); font-size: .76rem; display: block; }
.sg-rung .sg-p { font-size: 1.05rem; }
.sg-rung--best .sg-m { font-weight: 620; }

/* Exactly one filled button per card.
   The selectors are doubled up (.sg .sg-cta) so they outrank the
   `.sg a { color: inherit }` reset above — that rule is one element more
   specific than a bare class, and it would otherwise paint the button text
   graphite on graphite, which is exactly what it did on first deploy. */
.sg .sg-cta {
  margin-top: 12px;
  align-self: start;
  display: inline-block;
  background: var(--sg-loden);
  color: var(--sg-loden-ink);
  text-decoration: none;
  padding: 13px 20px;
  font-weight: 640;
  font-size: .95rem;
  min-height: 46px;
  line-height: 20px;
  border: 0;
  transition: filter .15s;
}
.sg .sg-cta:hover, .sg .sg-cta:focus { filter: brightness(1.15); color: var(--sg-loden-ink); text-decoration: none; }
.sg .sg-cta2 {
  margin-top: 12px;
  align-self: start;
  display: inline-block;
  border: 1px solid var(--sg-rule-firm);
  padding: 12px 19px;
  font-weight: 600;
  font-size: .95rem;
  text-decoration: none;
  min-height: 46px;
  line-height: 20px;
}

/* ── Jump bar ────────────────────────────────────────────────────── */
/* The disclosure, then a control that moves the reader down the page.
   OUTLINED, never filled: rule 1 gives the one filled loden button on a
   card to the affiliate CTA, and a second filled button competing with it
   costs clicks on both. Same square corners, weight and size as .sg-cta so
   they read as one family — only the fill separates them, which is exactly
   the distinction being drawn. Hover is a faint loden wash, not a fill; the
   system has no shadows and this button has no transition of its own. */
.sg-jumpbar { display: flex; flex-direction: column; align-items: flex-start; }
.sg-jumpbar .sg-discl { margin-bottom: 16px; }

.sg .sg-jump {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .4em;
  /* 44px is the smallest reliable tap target; padding alone would not
     guarantee it once the label wraps to one short word. */
  min-height: 44px;
  padding: 11px 19px;
  background: transparent;
  border: 1px solid var(--sg-loden);
  border-radius: 0;
  color: var(--sg-loden);
  text-decoration: none;
  font-weight: 640;
  font-size: .95rem;
  letter-spacing: normal;
  line-height: 20px;
}
.sg .sg-jump:hover,
.sg .sg-jump:focus {
  background: var(--sg-loden-wash);
  color: var(--sg-loden);
  text-decoration: none;
}
.sg .sg-jump:focus-visible {
  outline: 2px solid var(--sg-loden);
  outline-offset: 3px;
}

/* Rule 5: every price carries its last-checked date.

   Set in --sg-soft, not --sg-faint. Faint measured 2.96:1 against the card
   surface — below AA — on the one line whose entire job is to be believed. A
   freshness claim nobody can read is not a freshness claim, and at .72rem it is
   small text, so 4.5:1 is the bar, not 3:1. Soft is already in the palette and
   clears it in both schemes: 5.54:1 on --sg-surface and 5.09:1 on --sg-linen in
   light, 7.02:1 in dark. No new colour was introduced — this is the token the
   disclosure strip already uses for exactly the same reason. */
.sg-fresh { font-size: .72rem; color: var(--sg-soft); font-variant-numeric: tabular-nums; }

.sg-discl {
  border: 1px solid var(--sg-rule);
  background: var(--sg-surface);
  padding: 11px 14px;
  font-size: .8rem;
  color: var(--sg-soft);
  margin-bottom: 24px;
}

/* ── Toplist ─────────────────────────────────────────────────────── */
/* Astra's header is sticky, so a fragment jump that lands flush at the top
   of the wrapper hides the heading underneath it. */
.sg-toplist,
.sg-tablewrap { scroll-margin-top: 96px; }

.sg-verdict { border-top: 2px solid var(--sg-rule-firm); margin-bottom: 24px; }
.sg-verdict-row {
  display: flex;
  align-items: baseline;
  gap: 16px;
  padding: 13px 0;
  border-bottom: 1px solid var(--sg-rule);
}
.sg-verdict-label {
  flex: 0 0 9rem;
  font-size: .68rem;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--sg-loden);
  font-weight: 680;
}
.sg-verdict-name  { flex: 1 1 auto; font-weight: 600; }
.sg-verdict-price { font-variant-numeric: tabular-nums; color: var(--sg-soft); white-space: nowrap; }

/* ── Comparison table ────────────────────────────────────────────── */
.sg-tw { overflow-x: auto; border: 1px solid var(--sg-rule); }
.sg-tw table {
  border-collapse: collapse;
  width: 100%;
  min-width: 600px;
  background: var(--sg-surface);
  font-size: .88rem;
  margin: 0;
}
.sg-tw caption {
  text-align: left;
  padding: 12px 14px;
  color: var(--sg-soft);
  font-size: .8rem;
  border-bottom: 1px solid var(--sg-rule);
  caption-side: top;
}
.sg-tw th, .sg-tw td {
  text-align: left;
  padding: 11px 14px;
  border-bottom: 1px solid var(--sg-rule);
  vertical-align: top;
}
.sg-tw thead th {
  font-size: .66rem;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--sg-soft);
  font-weight: 660;
}
.sg-tw tbody th { font-weight: 600; }
.sg-tw td.sg-n { font-variant-numeric: tabular-nums; white-space: nowrap; }
.sg-tw tbody tr:last-child > * { border-bottom: 0; }
.sg-row-award { display: block; font-size: .68rem; color: var(--sg-loden); font-weight: 660; margin-top: 2px; letter-spacing: .06em; text-transform: uppercase; }
.sg-was-inline { display: block; font-size: .76rem; color: var(--sg-soft); text-decoration: line-through; }
.sg .sg-tablelink { color: var(--sg-loden); font-weight: 640; white-space: nowrap; }

/* ── Editor-only notice. Never rendered for visitors. ────────────── */
.sg-admin-note {
  border: 1px dashed var(--sg-rule-firm);
  background: var(--sg-ochre-wash);
  color: var(--sg-ochre);
  padding: 10px 13px;
  font-size: .8rem;
  margin-bottom: 16px;
}

@media (max-width: 640px) {
  .sg-card { grid-template-columns: 1fr; }
  .sg-shot { max-width: 200px; }
  .sg .sg-cta, .sg .sg-cta2 { width: 100%; text-align: center; }
  .sg-verdict-row { flex-wrap: wrap; gap: 4px 14px; }
  .sg-verdict-label { flex-basis: 100%; }
}
@media (prefers-reduced-motion: reduce) {
  .sg * { transition: none !important; animation: none !important; }
}

/* The one selector in this file that is not scoped under .sg, and it has to
   be: scroll-behavior is only honoured on the scrolling element, which is
   <html>. Declared inside no-preference rather than switched off inside
   reduce, so a visitor whose OS states no preference at all — and every
   browser that has never heard of the query — gets the instant jump. The
   [sg_jump] button is a plain href; no JavaScript is involved either way. */
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}
