/* Old Baraka — main front-end styles.
   Design system: _project/DESIGN-SYSTEM.md. Tokens mirror theme.json presets.
   Single committed warm light identity; hero + bands are intentionally dark walnut.

   Palette is sampled from the carved wooden logo (walnut rim, birch inlay,
   off-white ground). The logo is monochrome warm-brown and carries no accent
   colour of its own, so --ob-copper is the one derived value: the wood's own
   hue (18deg) pushed to a burnt sienna with enough chroma to carry buttons,
   prices and active states. Every pairing below is WCAG-AA checked -- copper
   sits at 4.80:1 on --ob-bg, 5.32:1 on --ob-surface, 5.70:1 under white text.
   Keep those ratios if you retune it. */

:root {
	--ob-walnut: #3E2415;
	--ob-walnut-2: #54331E;
	--ob-walnut-deep: #2A170C;
	--ob-copper: #B04415;
	--ob-copper-br: #C65A22;
	--ob-tan: #9B7051;
	--ob-tan-2: #C08F63;
	/* Same hue (25deg) and saturation as --ob-tan, dropped to 40% lightness: the
	   tan for SMALL TEXT on the light grounds. --ob-tan itself is only 4.05:1 on
	   --ob-surface and 3.66:1 on --ob-bg, so it fails AA as body-size type and is
	   safe only as a hairline or on the dark bands. This clears 5.11:1 / 4.62:1. */
	--ob-tan-ink: #876146;
	/* Channels of --ob-tan-2, for the many rgba() hairlines and glows below.
	   Keep in sync with --ob-tan-2 if that changes. */
	--ob-tan-rgb: 192, 143, 99;

	--ob-bg: #F4EAE0;
	--ob-surface: #FCF6F0;
	--ob-surface-2: #F6EDE3;
	--ob-ink: #2A170C;
	--ob-ink-soft: #6B5443;
	--ob-cream: #EBD5BE;
	--ob-cream-soft: #D3B999;

	--ob-line: rgba(42, 23, 12, .16);
	--ob-line-2: rgba(42, 23, 12, .08);

	/* The one non-palette hue the design allows, because "this field is wrong" cannot
	   be said in copper — copper is what buttons and prices already use. Deep enough
	   to read as warning rather than as decoration, and warm enough not to fight the
	   walnut. Was hard-coded in three places before it earned a name. */
	--ob-err: #9E1B1B;

	--ob-max: 1120px;
	--ob-gap: clamp(1.1rem, 4vw, 2.5rem);
	--ob-serif: 'Noto Serif Georgian', Georgia, 'Sylfaen', serif;
	--ob-sans: 'Noto Sans Georgian', 'Segoe UI', system-ui, -apple-system, sans-serif;

	/* ---- Eyebrows ----
	   TWO sizes, and only two. Audited across the whole site on 2026-08-18, this one
	   component was rendering at FIVE — .72rem here, .68rem in the footer, .66rem on the
	   article nav, .64rem on a shop card and .6rem on a shop card below 560px, i.e. 11.5px
	   down to 9.6px. Each step had been tuned locally with no principle behind it, and the
	   bottom two sit below the point where uppercase type with .14em of letter-spacing is
	   comfortably readable on a phone.

	   `--ob-eyebrow` is the size. `--ob-eyebrow-tight` (11.2px) is the ONE allowed
	   reduction, for genuinely cramped boxes. 11.2px is the floor; do not add a third
	   value. The single deliberate ENLARGEMENT is not an eyebrow doing eyebrow work —
	   `.ob-menu__cat-head .ob-eyebrow` at .9rem is a section heading — and is left alone. */
	--ob-eyebrow: .72rem;
	--ob-eyebrow-tight: .7rem;

	/* ---- Touch ----
	   The smallest a control may be on a touch-sized viewport. 40px is below Apple's 44
	   and above the WCAG AA 24, and it is what the nav toggle already was — so it is the
	   number the rest of the site is being brought into line WITH rather than a new
	   opinion. See the "Touch targets" section for how it is applied without moving any
	   visual box. */
	--ob-touch: 40px;

	/* ---- Motion ----
	   Three durations and three curves, used everywhere, so the whole site moves
	   with one hand. Before this there were six ad-hoc durations and no shared
	   easing, which is why the interface felt inert rather than slow.

	   --ob-ease leaves fast and lands soft (the standard hover/press feel).
	   --ob-pop overshoots ~10% and is reserved for things that should feel alive
	   when they APPEAR — a quantity changing, the cart badge counting up. Used on
	   hovers it would read as jelly, so don't.

	   Only transform / opacity / colour / box-shadow are animated anywhere; nothing
	   animates a property that would reflow the page. */
	--ob-dur-1: 130ms;  /* press, instant acknowledgement */
	--ob-dur-2: 240ms;  /* hovers, state changes */
	--ob-dur-3: 460ms;  /* photo zooms, larger reveals */
	--ob-ease: cubic-bezier(.22, .61, .36, 1);
	--ob-ease-in-out: cubic-bezier(.5, .05, .3, 1);
	--ob-pop: cubic-bezier(.34, 1.4, .64, 1);

	--ob-shadow-1: 0 2px 8px rgba(42, 23, 12, .08);
	--ob-shadow-2: 0 8px 20px rgba(42, 23, 12, .14);
	--ob-shadow-3: 0 14px 30px rgba(42, 23, 12, .18);
}

/* ---------- Motion primitives ---------- */
@keyframes ob-pop-in {
	from { opacity: 0; transform: scale(.82); }
	to   { opacity: 1; transform: scale(1); }
}
@keyframes ob-bump {
	0%   { transform: scale(1); }
	38%  { transform: scale(1.28); }
	100% { transform: scale(1); }
}
@keyframes ob-fade-up {
	from { opacity: 0; transform: translateY(10px); }
	to   { opacity: 1; transform: none; }
}

* { box-sizing: border-box; }

/* ⚠️ INHERITED, and it is load-bearing on a Georgian site. Georgian compounds routinely
   run past 18 characters with no internal break opportunity and there is no hyphenation
   dictionary for the language, so a single word can be wider than the column it sits in —
   and CSS will happily let it overflow rather than break it.

   Found on 2026-08-18 by the responsive audit: the privacy policy's own title,
   `კონფიდენციალურობის პოლიტიკა`, laid out 403px of text in a 285px column at 320px wide
   and pushed the document to 422px. The RUSSIAN title has the same shape
   («конфиденциальности», 18 characters). It presents oddly, too: the fixed cookie banner
   measured 422px as well, because a fixed element with `inset-inline: 0` resolves against
   an initial containing block that grows with the document's overflow — so the banner
   looks like the culprit and is a symptom.

   Set on `body` rather than on a list of selectors so it covers copy the client writes
   later. It cannot disturb anything that currently fits: `overflow-wrap` only acts on a
   word that would otherwise overflow its line box, and `white-space: nowrap` still wins
   where it is set (the menu's dotted price leader, buttons, prices). */
body {
	overflow-wrap: break-word;
	margin: 0;
	background: var(--ob-bg);
	color: var(--ob-ink);
	font-family: var(--ob-sans);
	font-size: clamp(.9rem, .85rem + .3vw, 1rem);
	line-height: 1.6;
	-webkit-font-smoothing: antialiased;
}

h1, h2, h3 {
	font-family: var(--ob-serif);
	font-weight: 600;
	line-height: 1.15;
	text-wrap: balance;
	margin: 0;
}

img { max-width: 100%; height: auto; }

.ob-wrap {
	max-width: var(--ob-max);
	margin-inline: auto;
	padding-inline: var(--ob-gap);
}

.ob-eyebrow {
	font-family: var(--ob-sans);
	text-transform: uppercase;
	letter-spacing: .22em;
	font-size: var(--ob-eyebrow);
	font-weight: 700;
	color: var(--ob-tan);
	margin: 0;
}

.ob-orn { display: block; width: 120px; height: 18px; margin: 1.1rem auto; color: var(--ob-tan); }

/* ---------- Buttons ---------- */
.ob-btn {
	display: inline-block;
	text-decoration: none;
	font-family: var(--ob-sans);
	font-weight: 600;
	font-size: .92rem;
	padding: .7rem 1.35rem;
	border-radius: 2px;
	border: 1px solid transparent;
	cursor: pointer;
	transition: transform var(--ob-dur-1) var(--ob-ease),
	            box-shadow var(--ob-dur-2) var(--ob-ease),
	            background var(--ob-dur-2) var(--ob-ease),
	            color var(--ob-dur-2) var(--ob-ease),
	            border-color var(--ob-dur-2) var(--ob-ease);
}
/* Lift on hover, sink on press. The press is deliberately quicker than the hover
   (--ob-dur-1) so a click feels acknowledged the instant the finger lands. */
.ob-btn:hover { transform: translateY(-1px); }
.ob-btn:active { transform: translateY(1px) scale(.985); }
.ob-btn--pom { background: var(--ob-copper); color: #fff; box-shadow: var(--ob-shadow-1); }
.ob-btn--pom:hover { background: var(--ob-copper-br); color: #fff; box-shadow: var(--ob-shadow-2); }
.ob-btn--ghost { background: transparent; color: var(--ob-cream); border-color: rgba(var(--ob-tan-rgb), .6); }
.ob-btn--ghost:hover { border-color: var(--ob-tan-2); background: rgba(var(--ob-tan-rgb), .12); }

/* ---------- Header ---------- */
.site-header {
	position: sticky;
	top: 0;
	z-index: 50;
	background: var(--ob-walnut);
	color: var(--ob-cream);
	border-bottom: 1px solid rgba(var(--ob-tan-rgb), .35);
	transition: box-shadow var(--ob-dur-2) var(--ob-ease);
}
/* Earns a shadow only once it is actually overlapping content (class from main.js),
   so the header lifts off the page as you scroll instead of floating from the start. */
.site-header.is-stuck { box-shadow: 0 6px 22px rgba(20, 10, 4, .34); }
/* Two groups, not four spread items: [brand + navigation] ... [language, cart,
   order]. With justify-content:space-between the four flex children were spaced
   evenly, which parked the nav in the middle of the bar with a 295px hole
   between it and the wordmark and no relationship to either side. Identity and
   navigation now read as one cluster and the actions own the right edge, which
   is the split every ordering site the client uses already has.

   Height: 80px at rest was the whole budget a sticky header should ever take.
   .62rem of padding on a 44px roundel lands it at ~64px, and the 16px it gives
   back is 16px of dish photography on every scroll of every page. */
.site-header__inner {
	max-width: var(--ob-max);
	margin-inline: auto;
	padding: .62rem var(--ob-gap);
	display: flex;
	align-items: center;
	gap: 1rem;
}
/* flex, not the default block: .brand is inline-flex, so it sat on its parent's
   text baseline and the line box reserved 8px of descender space under a 44px
   logo. That phantom 8px was the tallest thing in the row and set the header's
   height (52px branding box for a 44px mark). */
.site-branding { display: flex; align-items: center; }
/* ONE ROW OR THE PANEL — and 960px is where the row genuinely fits.
   This was 781px, and at 781–840 the header had been overflowing the document by
   up to 89px with the four original links: measured 2026-08-14, scrollWidth 945
   against a 781px viewport. Nothing had shrunk — the cluster had GROWN twice since
   the number was chosen, by the account icon (+30px) and by the language switcher
   becoming KA·EN·RU (+60px), and neither pass measured this band. Adding the blog
   link took it to 164px and made the range reach 1010.
   The row's real cost is brand + nav + controls + padding + two grid gaps. With
   five links that is ~975px, so it technically fits at 960 — but with the brand
   track already at its minimum and only the two 16px grid gaps left, i.e. no
   cushion at all: a two-digit cart badge (+7px) would put it over. 1024 is the
   first width that keeps ~40px in hand, and it also keeps iPad landscape on the
   desktop row. Below it the phone panel is not a compromise, it is the layout that
   fits. */
@media (min-width: 1024px) {
	/* Three tracks, so the nav is centred on the PAGE rather than in whatever space
	   the brand and the actions leave over. 1fr on both flanks makes those side
	   columns equal, which is what "centred" has to mean when the wordmark and the
	   icon cluster are different widths.
	   The nav-toggle is display:none up here, so it takes no track. */
	.site-header__inner {
		display: grid;
		grid-template-columns: 1fr auto 1fr;
	}
	.site-branding      { justify-self: start; margin-inline-end: 0; }
	.site-nav           { justify-self: center; }
	.site-header__right { justify-self: end; }
	/* A nav link that wraps makes the whole header two rows tall. Never. */
	.site-nav ul a { white-space: nowrap; }
}
/* Logo roundel + wordmark. The wordmark sits deliberately below the logo's optical
   size so the carved mark leads and the text reads as its caption — at equal
   weight the two competed. */
.brand { display: inline-flex; align-items: center; gap: .6rem; text-decoration: none; color: var(--ob-cream); }
.brand:hover { color: var(--ob-tan-2); }
.brand:focus-visible { outline: 2px solid var(--ob-tan-2); outline-offset: 4px; border-radius: 2px; }
.brand__logo { width: 44px; height: 44px; display: block; flex: none; }
/* The carved roundel is illegible at header size by nature, so the wordmark is
   what actually identifies the site. It was set lighter and smaller than the
   nav's optical weight and lost that job; 600 at 1.28rem lets the brand hold
   the left end of the bar on its own. */
.brand__mark { font-family: var(--ob-serif); font-weight: 600; font-size: clamp(1.05rem, 2vw, 1.28rem); letter-spacing: .01em; white-space: nowrap; }
.brand__since { font-size: .62rem; letter-spacing: .28em; text-transform: uppercase; color: var(--ob-tan-2); }

.site-nav ul { display: flex; gap: 1.4rem; list-style: none; margin: 0; padding: 0; }
/* Scoped to `ul a`, NOT `.site-nav a`: the nav also holds the mobile order CTA, and
   a bare `.site-nav a` (0-1-1) outranks `.ob-btn--pom` (0-1-0) — it would repaint the
   button's white label cream and flatten its padding. Menu-link rules stay inside
   the list where they belong.
   The underline is a scaled pseudo-element rather than a border-colour swap, so it
   grows out from the left instead of just switching on. */
.site-nav ul a {
	position: relative;
	text-decoration: none;
	font-size: .9rem;
	/* Was --ob-cream-soft, which on walnut made every link look pre-dimmed —
	   a nav where nothing is active reads as a nav that is disabled. Cream at
	   82% keeps a real gap to the full-cream hover without starting faded. */
	color: rgba(235, 213, 190, .82);
	padding-block: .2rem;
	transition: color var(--ob-dur-2) var(--ob-ease);
}
.site-nav ul a::after {
	content: "";
	position: absolute; left: 0; right: 0; bottom: 0; height: 2px;
	background: var(--ob-tan);
	transform: scaleX(0); transform-origin: left;
	transition: transform var(--ob-dur-2) var(--ob-ease);
}
.site-nav ul a:hover { color: var(--ob-cream); }
.site-nav ul a:hover::after,
.site-nav .current-menu-item > a::after { transform: scaleX(1); }
/* The page you are ON and the link you are POINTING AT were drawn identically —
   same tan bar, so hovering any link made two links look current at once. Copper
   is what the rest of the site already uses for an active state (prices, the
   quantity stepper, the cart badge), so the current page takes copper and full
   cream, and hover stays tan. Two states, two colours. */
.site-nav .current-menu-item > a { color: var(--ob-cream); }
.site-nav .current-menu-item > a::after { background: var(--ob-copper-br); }

/* Just above the panel breakpoint the row fits, but only just: five Georgian
   labels, three controls and the order button in under 1080px. At full size that
   comes to ~1048px, so without this it would overflow 1024 by 24px. So the nav tightens
   through that band rather than the header growing or a link wrapping.
   ⚠️ THE POSITION OF THIS BLOCK IS LOAD-BEARING. It has to come AFTER the
   `.site-nav ul` and `.site-nav ul a` rules above, because a media query adds no
   specificity — the same selector later in the file wins whatever the query says.
   It used to sit before them, and had therefore been doing NOTHING since those
   rules were written: measured at 900px, the nav still computed to font-size 14.4px
   and gap 22.4px, i.e. the full desktop sizes. Both numbers below are now real. */
@media (min-width: 1024px) and (max-width: 1080px) {
	.site-nav ul { gap: 1rem; }
	.site-nav ul a { font-size: .84rem; }
}

/* One rule governs this cluster: ONLY the primary action is filled. It used to
   hold three unrelated treatments side by side — a solid tan box (language), a
   bare outline glyph (cart) and a solid copper button (order) — so the eye had
   no way to rank them, and the tan box read as a second accent on a palette
   that allows exactly one. Language and cart are now quiet cream controls and
   copper is the only fill in the bar. */
.site-header__right { display: flex; align-items: center; gap: .9rem; }
/* A hairline groups the two quiet controls and separates them from the button,
   so "settings" and "act" are visibly different kinds of thing. */
.site-header__right .ob-btn { margin-inline-start: .2rem; }

/* The language switcher is a miniature of the nav: same idle colour, same
   underline marking the current choice. That is what makes a lone "KA" read as
   one option of several rather than as a label — and when EN and a third
   language land, `KA EN RU` with one underlined needs no further design. */
/* Optical inset to match the icons beside it. Both icons carry ~7px of transparent
   margin inside their own box before any ink; "KA" is text and has none, so with an
   even box gap it sat visibly tighter to the cart than the account icon did. The
   padding goes on the wrapper, NOT the anchor: `.lang-switcher a::after` is the
   current-language underline and stretches left:0/right:0, so padding on the anchor
   would widen the underline instead of hugging the letters. */
.site-header__right .lang-switcher { padding-inline: 8px; }
.lang-switcher ul { display: flex; gap: .5rem; align-items: center; list-style: none; margin: 0; padding: 0; }
.lang-switcher a {
	position: relative;
	display: block;
	text-decoration: none;
	padding-block: .2rem;
	font-size: .8rem;
	font-weight: 600;
	letter-spacing: .06em;
	color: var(--ob-cream-soft);
	transition: color var(--ob-dur-2) var(--ob-ease);
}
.lang-switcher a::after {
	content: "";
	position: absolute; left: 0; right: 0; bottom: 0; height: 2px;
	background: var(--ob-tan);
	transform: scaleX(0); transform-origin: left;
	transition: transform var(--ob-dur-2) var(--ob-ease);
}
.lang-switcher a:hover { color: var(--ob-cream); }
.lang-switcher a:hover::after { transform: scaleX(1); }
.lang-switcher__item.is-current a { color: var(--ob-cream); }
.lang-switcher__item.is-current a::after { transform: scaleX(1); background: var(--ob-copper-br); }

/* Cart button */
.ob-cart { position: relative; display: inline-flex; align-items: center; color: var(--ob-cream); text-decoration: none; padding: .2rem; transition: color var(--ob-dur-2) var(--ob-ease), transform var(--ob-dur-1) var(--ob-ease); }
.ob-cart:hover { color: var(--ob-tan-2); }
.ob-cart:active { transform: scale(.94); }
/* Nudged 1px right as an OPTICAL correction, not a layout one. The cart glyph is
   drawn from x=3 to x≈19.8 in a 24 box, so its ink sat 6.2px from the box's left
   edge and 8.2px from the right — 2px off centre. With even box gaps that made the
   account icon look further from the cart than the language switch is. transform,
   so the box itself does not move and the row's arithmetic is untouched. */
.ob-cart__ic { width: 24px; height: 24px; display: block; transform: translateX(1px); }
.ob-cart__count {
	position: absolute; top: -7px; right: -9px;
	min-width: 18px; height: 18px; padding: 0 4px; box-sizing: border-box;
	border-radius: 999px; background: var(--ob-copper); color: #fff;
	font-size: .66rem; font-weight: 700; line-height: 18px; text-align: center;
	font-variant-numeric: tabular-nums;
}
.ob-cart__count.is-empty { display: none; }
/* Counts up with a small overshoot — the badge is the only confirmation the
   quick-add controls give, so it has to catch the eye. Class set in main.js after
   the cart fragment is swapped in. */
.ob-cart__count.is-bump { animation: ob-bump 420ms var(--ob-pop); }

.nav-toggle { display: none; }
/* The mobile-only half of the duplicated order CTA (see header.php). */
.site-nav__cta { display: none; }

/* Account link. Same outline weight and hover as .ob-cart beside it — the single
   filled element in this header is the order CTA. */
.ob-acct-link {
	display: inline-flex;
	align-items: center;
	color: var(--ob-cream);
	text-decoration: none;
	padding: .2rem;
	transition: color var(--ob-dur-2) var(--ob-ease), transform var(--ob-dur-1) var(--ob-ease);
}
.ob-acct-link:hover { color: var(--ob-tan-2); }
.ob-acct-link:active { transform: scale(.94); }
.ob-acct-link__ic { width: 24px; height: 24px; display: block; }
/* Logged in reads copper, the same signal the nav uses for the current page, so
   "I am signed in" is legible without adding a word to the header. */
.ob-acct-link.is-in { color: var(--ob-copper-br); }
.ob-acct-link.is-in:hover { color: var(--ob-tan-2); }

/* Mobile shows this in the nav panel instead — see header.php. */
.site-nav__acct { display: none; }

/* The nav-panel half of the duplicated language switcher (see the note in
   template-parts/language-switcher.php). Shown only below 360px, where the header row
   has no space for it; the header cluster's copy is the live one everywhere else. */
.lang-switcher--nav { display: none; }

/* Hamburger → X. Three absolutely-positioned bars so the outer two can rotate into
   the cross while the middle one fades; a border-based icon can't do that. Driven
   off the button's own aria-expanded, so the visual state cannot drift from the
   state assistive tech is told about — there is no second class to keep in sync. */
.nav-toggle__box { position: relative; display: block; width: 20px; height: 14px; }
.nav-toggle__box span {
	position: absolute; left: 0; right: 0; height: 2px;
	border-radius: 2px; background: currentColor;
	transition: transform var(--ob-dur-2) var(--ob-ease), opacity var(--ob-dur-1) var(--ob-ease);
}
.nav-toggle__box span:nth-child(1) { top: 0; }
.nav-toggle__box span:nth-child(2) { top: 6px; }
.nav-toggle__box span:nth-child(3) { top: 12px; }
.nav-toggle[aria-expanded="true"] .nav-toggle__box span:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] .nav-toggle__box span:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] .nav-toggle__box span:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

/* ---------- Hero ---------- */
.ob-hero {
	position: relative;
	isolation: isolate;
	color: var(--ob-cream);
	text-align: center;
	overflow: hidden;
	/* Shown when no photo resolves at all; also the tone the photo sits on. */
	background:
		radial-gradient(120% 90% at 50% -10%, rgba(var(--ob-tan-rgb), .18), transparent 55%),
		linear-gradient(160deg, #4A2C1A, var(--ob-walnut) 55%, #2A170C);
}

/* Photo + scrim live on their own element, so the dot texture keeps its own
   pseudo-element instead of competing for one. */
.ob-hero__media { position: absolute; inset: 0; z-index: -2; }
.ob-hero--photo .ob-hero__media::before {
	content: "";
	position: absolute; inset: 0;
	background-image: var(--ob-hero-img);
	background-size: cover;
	background-position: center 55%;
	/* Slight overscale hides softness when a modest photo is stretched wide;
	   it is also the resting end of the drift below. */
	transform: scale(1.04);
	filter: saturate(.82) contrast(1.04);
	animation: ob-hero-drift 38s var(--ob-ease-in-out) infinite alternate;
}

/* Ken Burns, deliberately slower than the genre norm. Over 38s the frame edge
   travels well under 1px/s, so it never reads as "a moving background" — you
   only notice that the photograph is not a still. Runs from the existing 1.04
   overscale so nothing shifts at the moment the animation attaches, and stays
   transform-only: no reflow, no repaint of the photo itself. */
@keyframes ob-hero-drift {
	from { transform: scale(1.04) translate3d(0, 0, 0); }
	to   { transform: scale(1.11) translate3d(-1.4%, -1.1%, 0); }
}
/* One even wash of walnut — no spotlight, no coloured glow. It reads as a
   darkened photograph rather than as a gradient laid over one. Depth stays
   flat enough that the cream type clears AA everywhere (verified on render). */
.ob-hero--photo .ob-hero__media::after {
	content: "";
	position: absolute; inset: 0;
	background: rgba(42, 23, 12, .74);
}

/* Woven dot texture, kept from the original hero. */
.ob-hero::after {
	content: "";
	position: absolute; inset: 0; z-index: -1;
	opacity: .06; pointer-events: none;
	background-image: radial-gradient(circle at 1px 1px, var(--ob-tan-2) 1px, transparent 0);
	background-size: 22px 22px;
}

.ob-hero__inner {
	position: relative;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	min-height: clamp(440px, 66vh, 720px);
	padding-block: clamp(3.5rem, 9vw, 6rem);
}
/* Cream, not tan: over a photo the tan eyebrow measures 2.8:1 at the bright
   spots. Tan stays correct on the solid dark bands, where it clears 5:1. */
.ob-hero .ob-eyebrow { color: var(--ob-cream); text-shadow: 0 1px 10px rgba(42, 23, 12, .7); }
.ob-hero .ob-orn { color: var(--ob-tan-2); }
.ob-hero__logo {
	width: clamp(76px, 10vw, 116px);
	height: auto;
	margin-bottom: clamp(1rem, 2.5vw, 1.6rem);
	filter: drop-shadow(0 8px 22px rgba(0, 0, 0, .48));
}
.ob-hero h1 {
	font-size: clamp(2.8rem, 8vw, 5.2rem);
	letter-spacing: .01em;
	text-shadow: 0 2px 28px rgba(42, 23, 12, .55);
}
.ob-hero__sub {
	max-width: 44ch;
	margin: 1rem auto 0;
	color: var(--ob-cream);
	font-size: clamp(1rem, 2.4vw, 1.18rem);
	text-shadow: 0 1px 14px rgba(42, 23, 12, .6);
}
.ob-hero__cta { display: flex; gap: .8rem; justify-content: center; flex-wrap: wrap; margin-top: clamp(1.6rem, 4vw, 2.4rem); }
.ob-hero__cta .ob-btn { padding: .85rem 1.9rem; font-size: .98rem; box-shadow: 0 10px 26px rgba(42, 23, 12, .38); }

/* ---------- Hero motion ----------
   The hero opened as a still photograph with static type on it. Everything
   below moves on transform/opacity only, in the same register as the rest of
   the site: short, soft, no bounce except where something appears. */

/* 1 — Arrival. The hero is always above the fold, so this is a CSS load
   animation rather than the IntersectionObserver .ob-rise path. `both` keeps
   the from-state before the delay elapses, which is what makes the stagger
   readable instead of six things easing in at once. */
@keyframes ob-hero-in {
	from { opacity: 0; transform: translateY(16px); }
	to   { opacity: 1; transform: none; }
}
.ob-hero__inner > * { animation: ob-hero-in var(--ob-dur-3) var(--ob-ease) both; }
.ob-hero__logo       { animation-delay:  60ms; }
.ob-hero .ob-eyebrow { animation-delay: 150ms; }
.ob-hero h1          { animation-delay: 240ms; }
.ob-hero .ob-orn     { animation-delay: 330ms; }
.ob-hero__sub        { animation-delay: 420ms; }
.ob-hero__cta        { animation-delay: 510ms; }

/* 2 — The ornament draws itself. Each rule is 42 units long (6→48, 72→114), so
   one dasharray covers both; the diamond and the two stops then land after the
   lines have arrived. This is the one place --ob-pop belongs — they appear. */
@keyframes ob-orn-draw { from { stroke-dashoffset: 42; } to { stroke-dashoffset: 0; } }
@keyframes ob-orn-pop  { from { opacity: 0; transform: scale(.35); } to { opacity: 1; transform: none; } }
.ob-hero .ob-orn line {
	stroke-dasharray: 42;
	animation: ob-orn-draw 620ms var(--ob-ease) 380ms both;
}
.ob-hero .ob-orn path,
.ob-hero .ob-orn circle {
	/* fill-box, or transform-origin would resolve against the whole SVG canvas
	   and the diamond would scale in from the left edge. */
	transform-box: fill-box;
	transform-origin: center;
	animation: ob-orn-pop 360ms var(--ob-pop) 900ms both;
}

/* The scroll cue (a diamond descending a hairline at the bottom of the hero) is
   gone, along with the 78px of hero padding that had to be reserved on desktop
   to stop it landing on the CTA. A label telling you to scroll is the weakest
   possible thing to put at the fold; the visit strip below now takes that space
   and puts the opening hours there instead. */

/* ---------- Visit strip ----------
   Hours · address · phone, hard against the bottom of the hero. Walnut-deep, so
   the dark fold reads as one block that ends on a crisp tan hairline instead of
   dissolving into the light page — the same hard-edge treatment as .ob-page-hero,
   and the reason there is no fade anywhere near it.
   Tan-2 is legal for the icons and small type here because this is a dark ground
   (5:1+); on the light sections it would not be. See --ob-tan-ink. */
.ob-visit {
	background: var(--ob-walnut-deep);
	color: var(--ob-cream);
	border-bottom: 1px solid rgba(var(--ob-tan-rgb), .55);
}
.ob-visit__inner {
	display: grid;
	gap: .55rem 2rem;
	padding-block: .95rem;
}
.ob-visit__item {
	display: flex;
	align-items: center;
	gap: .55rem;
	margin: 0;
	font-size: .86rem;
	min-width: 0;
}
.ob-visit__ic { width: 17px; height: 17px; flex: none; color: var(--ob-tan-2); }
.ob-visit__val { color: var(--ob-cream); text-decoration: none; }
/* Hours and phone numbers sit in the same row and both change per language;
   tabular figures keep the digits from shuffling the row's width. */
.ob-visit__val--num { font-variant-numeric: tabular-nums; }
a.ob-visit__val { transition: color var(--ob-dur-2) var(--ob-ease); }
a.ob-visit__val:hover { color: var(--ob-tan-2); }
/* Three items spread edge to edge only once they genuinely fit on one line.
   Below that they stack, rather than compressing the address to two words. */
@media (min-width: 900px) {
	.ob-visit__inner { grid-auto-flow: column; justify-content: space-between; }
}

/* ---------- Section scaffold ---------- */
.ob-section { padding-block: clamp(3rem, 7vw, 5rem); }
.ob-section--alt { background: var(--ob-surface-2); border-block: 1px solid var(--ob-line); }
.ob-sec-head { text-align: center; margin-bottom: 2.4rem; }
.ob-sec-head h2 { font-size: clamp(1.9rem, 4.5vw, 2.8rem); margin-top: .5rem; }
.ob-sec-head p { color: var(--ob-ink-soft); max-width: 46ch; margin: .6rem auto 0; }

/* Heading on the left, the section's overflow link on its baseline at the right.
   Every section head on this page was centred, which made four different jobs
   look like one repeated one. Only used where the right-hand side carries a real
   action — a heading with a paragraph floating beside it is just a broken column. */
.ob-sec-head--split {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	justify-content: space-between;
	gap: .4rem 1.5rem;
	text-align: left;
}
.ob-sec-head--split h2 { margin-top: 0; }

.ob-more {
	display: inline-flex;
	align-items: center;
	gap: .4rem;
	text-decoration: none;
	font-weight: 600;
	font-size: .9rem;
	color: var(--ob-copper);
	border-bottom: 1px solid transparent;
	transition: color var(--ob-dur-2) var(--ob-ease), border-color var(--ob-dur-2) var(--ob-ease);
}
.ob-more:hover { color: var(--ob-copper-br); border-bottom-color: currentColor; }
/* The arrow steps forward on hover; the label does not move, so the link does
   not reflow the row it sits in. */
.ob-more__ic { width: 15px; height: 15px; transition: transform var(--ob-dur-2) var(--ob-ease); }
.ob-more:hover .ob-more__ic { transform: translateX(3px); }

/* The homepage's own product card (.ob-cards / .ob-card) is gone. It was a
   second, shallower design for the same objects — photo, name, price, no
   add-to-cart — so the four featured dishes looked like different products from
   the ones on the shop page. The popular-dishes section now runs the real
   WooCommerce loop and gets .ob-pcard, further down this file. */

/* ---------- Promo strip ---------- */
.ob-promo { background: var(--ob-tan); color: var(--ob-walnut-deep); text-align: center; }
.ob-promo__inner { padding-block: 1rem; font-weight: 600; }
.ob-promo a { color: var(--ob-walnut-deep); }

/* ---------- About teaser ---------- */
.ob-about { display: grid; grid-template-columns: 1fr; gap: 2.5rem; align-items: center; }
.ob-about__media {
	aspect-ratio: 5/4; border-radius: 4px; border: 1px solid var(--ob-line); overflow: hidden;
	background: radial-gradient(80% 80% at 30% 20%, rgba(var(--ob-tan-rgb), .35), transparent 60%), linear-gradient(150deg, #4A2C1A, #54331E);
	display: grid; place-items: center; color: rgba(235, 213, 190, .6); font-size: .75rem;
}
.ob-about__media img { width: 100%; height: 100%; object-fit: cover; }
.ob-about h2 { font-size: clamp(1.8rem, 4vw, 2.5rem); margin-bottom: .8rem; }
.ob-about p { color: var(--ob-ink-soft); margin: 0; }
.ob-about p + p { margin-top: .9rem; }
@media (min-width: 820px) { .ob-about { grid-template-columns: 1.1fr 1fr; } }

/* ---------- Ordering & delivery band ----------
   Asymmetric on purpose: the route the business wants gets the heading, the
   width and the only button; the two alternatives get a narrow column and a
   single hairline between them. The three equal .ob-ocard boxes this replaced
   gave all three equal weight and boxed the primary action inside a card with
   nothing to click. */
.ob-order { background: var(--ob-walnut); color: var(--ob-cream); }
.ob-order__split { display: grid; grid-template-columns: 1fr; gap: 2.4rem; align-items: start; }
.ob-order__lead h2 { color: var(--ob-cream); font-size: clamp(1.9rem, 4.5vw, 2.8rem); }
.ob-order__lead p { color: var(--ob-cream-soft); max-width: 34ch; margin: .8rem 0 0; }
.ob-order__cta { margin-top: 1.5rem; padding: .85rem 1.9rem; font-size: .98rem; }

/* Not cards. A border-box around two short paragraphs on a dark ground adds a
   rectangle and no information; one hairline says "these are two things" for
   1px. */
.ob-route + .ob-route { margin-top: 1.4rem; padding-top: 1.4rem; border-top: 1px solid rgba(var(--ob-tan-rgb), .3); }
.ob-route h3 { color: var(--ob-tan-2); font-size: 1.08rem; margin-bottom: .35rem; }
.ob-route p { color: var(--ob-cream-soft); font-size: .9rem; margin: 0; max-width: 40ch; }

.ob-chips { margin-top: .8rem; display: flex; gap: .5rem; flex-wrap: wrap; }
.ob-chip { font-size: .72rem; letter-spacing: .05em; padding: .25rem .6rem; border: 1px solid rgba(var(--ob-tan-rgb), .5); border-radius: 999px; color: var(--ob-tan-2); }

/* 1.15/.85 rather than 1/1: the right column holds two short blocks and would
   otherwise claim the same visual weight as the block with the CTA in it. */
@media (min-width: 860px) {
	.ob-order__split { grid-template-columns: 1.15fr .85fr; gap: clamp(2.5rem, 6vw, 5rem); }
}

/* ---------- Page hero + generic page content ---------- */
/* One flat band, one hard edge — no decorative gradient. Deepest walnut rather
   than --ob-walnut so it reads as its own band instead of merging into the
   sticky header, which is --ob-walnut. */
.ob-page-hero {
	background: var(--ob-walnut-deep);
	color: var(--ob-cream);
	text-align: center;
	padding-block: clamp(2.5rem, 6vw, 4rem);
	border-bottom: 1px solid rgba(var(--ob-tan-rgb), .3);
}
.ob-page-hero__title { font-size: clamp(2rem, 5.5vw, 3.2rem); }
.ob-page-hero .ob-orn { margin-top: .8rem; margin-bottom: 0; }
.ob-page-hero .ob-eyebrow { color: var(--ob-tan-2); margin-bottom: .7rem; }
.ob-page-hero__sub {
	max-width: 54ch;
	margin: .9rem auto 0;
	color: var(--ob-cream-soft);
	font-size: clamp(.9rem, 1.8vw, 1rem);
}
/* The ornament separates title from subtitle here, so it needs less air above. */
.ob-page-hero--shop .ob-orn { margin-top: .9rem; }

.ob-page { padding-block: clamp(2.5rem, 6vw, 4rem); }
.ob-page__title { font-size: clamp(2rem, 5vw, 3rem); margin-bottom: 1.2rem; }
.entry-content { max-width: 720px; }
.entry-content > * + * { margin-top: 1.1rem; }
.entry-content h2 { font-size: 1.6rem; margin-top: 2rem; }
.entry-content a { color: var(--ob-copper); }

/* ---------- Contact ---------- */
.ob-contact { display: grid; grid-template-columns: 1fr; gap: 1.6rem; align-items: stretch; }
@media (min-width: 860px) { .ob-contact { grid-template-columns: 0.9fr 1.1fr; } }

/* Info panel — wine card */
.ob-contact__panel {
	background:
		radial-gradient(90% 70% at 15% 0%, rgba(var(--ob-tan-rgb), .16), transparent 55%),
		linear-gradient(160deg, var(--ob-walnut-2), var(--ob-walnut) 55%, var(--ob-walnut-deep));
	color: var(--ob-cream);
	border: 1px solid rgba(var(--ob-tan-rgb), .3);
	border-radius: 6px;
	padding: clamp(1.6rem, 4vw, 2.4rem);
}
.ob-contact__panel h2 { color: var(--ob-cream); font-size: 1.6rem; margin: .3rem 0 1.6rem; }
.ob-contact__list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 1.25rem; }
.ob-contact__list li { display: flex; gap: .9rem; align-items: flex-start; }
.ob-contact__ic {
	flex: none; width: 40px; height: 40px; border-radius: 50%;
	display: grid; place-items: center;
	border: 1px solid rgba(var(--ob-tan-rgb), .45);
	color: var(--ob-tan-2);
	background: rgba(255, 255, 255, .04);
}
.ob-contact__ic svg { width: 20px; height: 20px; }
.ob-contact__lbl { display: block; font-size: var(--ob-eyebrow); letter-spacing: .16em; text-transform: uppercase; color: var(--ob-tan-2); margin-bottom: .15rem; }
.ob-contact__list a { color: var(--ob-cream); text-decoration: none; border-bottom: 1px solid rgba(var(--ob-tan-rgb), .4); }
.ob-contact__list a:hover { color: var(--ob-tan-2); }
.ob-contact__social { margin-top: 1.8rem; padding-top: 1.4rem; border-top: 1px solid rgba(var(--ob-tan-rgb), .22); display: flex; gap: .6rem; flex-wrap: wrap; }
.ob-contact__social a { font-size: .82rem; text-decoration: none; border: 1px solid rgba(var(--ob-tan-rgb), .5); padding: .45rem .9rem; border-radius: 999px; color: var(--ob-tan-2); }
.ob-contact__social a:hover { background: rgba(var(--ob-tan-rgb), .14); color: var(--ob-cream); }

/* Form card */
.ob-contact__form {
	background: var(--ob-surface);
	border: 1px solid var(--ob-line-2);
	border-radius: 6px;
	padding: clamp(1.6rem, 4vw, 2.4rem);
}
.ob-contact__form h2 { font-size: 1.6rem; margin: .3rem 0 1.4rem; }

/* Map */
.ob-contact__map { margin-top: 1.6rem; border: 1px solid var(--ob-line); border-radius: 6px; overflow: hidden; }
.ob-contact__map iframe { display: block; width: 100%; height: 420px; border: 0; }
.ob-contact__map--empty {
	display: flex; flex-direction: column; align-items: center; justify-content: center; gap: .6rem;
	height: 260px; background: var(--ob-surface-2); color: var(--ob-ink-soft);
}
.ob-contact__map--empty .ob-media-ph { width: 84px; height: 84px; min-height: 0; border-radius: 50%; }
.ob-contact__map--empty p { margin: 0; font-size: .82rem; letter-spacing: .12em; text-transform: uppercase; }

/* ---------- Menu (digital menu page) ---------- */
.ob-menu { padding-block: clamp(2.5rem, 6vw, 4rem); }
.ob-menu__empty { text-align: center; color: var(--ob-ink-soft); }

.ob-menu__filter {
	display: flex; flex-wrap: wrap; gap: .5rem;
	justify-content: center;
	margin-bottom: clamp(2rem, 5vw, 3rem);
}
/* Used as a <button> on the menu page and as an <a> on the shop archive. */
.ob-mchip {
	font: inherit;
	font-size: .82rem;
	letter-spacing: .04em;
	display: inline-flex;
	align-items: center;
	gap: .45rem;
	padding: .45rem 1rem;
	border: 1px solid var(--ob-line);
	border-radius: 999px;
	background: var(--ob-surface);
	color: var(--ob-ink-soft);
	text-decoration: none;
	cursor: pointer;
	transition: background var(--ob-dur-2) var(--ob-ease), color var(--ob-dur-2) var(--ob-ease),
	            border-color var(--ob-dur-2) var(--ob-ease), transform var(--ob-dur-1) var(--ob-ease);
}
.ob-mchip:hover { border-color: var(--ob-tan); color: var(--ob-ink); }
.ob-mchip:active { transform: scale(.96); }
.ob-mchip.is-active { background: var(--ob-walnut); color: var(--ob-cream); border-color: var(--ob-walnut); }
.ob-mchip:focus-visible { outline: 2px solid var(--ob-copper); outline-offset: 2px; }
/* Product count on the shop chips. */
.ob-mchip__n { font-size: .7rem; font-variant-numeric: tabular-nums; opacity: .55; }

.ob-menu__cat { margin-bottom: clamp(2.5rem, 6vw, 3.5rem); scroll-margin-top: 90px; }
.ob-menu__cat.is-hidden { display: none; }
/* Sections toggle with `display`, so the ones being revealed animate in. Class is
   added by the chip handler only, never on first paint. */
.ob-menu__cat.is-refiltered { animation: ob-fade-up 320ms var(--ob-ease) both; }
.ob-menu__cat-head { text-align: center; margin-bottom: 1.6rem; }
.ob-menu__cat-head .ob-eyebrow { font-size: .9rem; color: var(--ob-tan); }
.ob-menu__cat-desc { color: var(--ob-ink-soft); margin: .4rem auto 0; max-width: 48ch; font-size: .9rem; }

/* Wider than the original 760px now that each row carries a quick-add control,
   so the dotted leader keeps a readable run between name and price. */
.ob-menu__list { list-style: none; margin: 0 auto; padding: 0; max-width: 880px; }
/* The inline padding is permanent, and the negative margin cancels it, so the
   hover tint has breathing room without the row shifting when it appears. */
.ob-menu__row {
	padding: .9rem .7rem; margin-inline: -.7rem;
	border-bottom: 1px solid var(--ob-line-2);
	border-radius: 8px;
	display: flex; flex-wrap: wrap; gap: 1rem; align-items: center;
	transition: background var(--ob-dur-2) var(--ob-ease);
}
.ob-menu__row:hover { background: rgba(var(--ob-tan-rgb), .09); }
.ob-menu__thumb img { transition: transform var(--ob-dur-3) var(--ob-ease); }
.ob-menu__row:hover .ob-menu__thumb img { transform: scale(1.07); }
.ob-menu__row:last-child { border-bottom: 0; }
.ob-menu__thumb { flex: none; width: 68px; height: 68px; border-radius: 6px; overflow: hidden; }
.ob-menu__thumb img, .ob-menu__thumb .ob-media-ph { width: 100%; height: 100%; object-fit: cover; min-height: 0; }
.ob-menu__thumb .ob-media-ph svg { width: 40%; }
.ob-menu__row-main { flex: 1; min-width: 0; }
.ob-menu__lead { display: flex; align-items: baseline; gap: .5rem; }
.ob-menu__name {
	font-family: var(--ob-serif);
	font-size: 1.15rem;
	color: var(--ob-ink);
	text-decoration: none;
	white-space: nowrap;
}
.ob-menu__name:hover { color: var(--ob-copper); }
.ob-menu__dots {
	flex: 1;
	align-self: flex-end;
	border-bottom: 1px dotted var(--ob-cream-soft);
	transform: translateY(-.28em);
	min-width: 1.5rem;
}
.ob-menu__price {
	font-weight: 700;
	color: var(--ob-copper);
	white-space: nowrap;
	font-variant-numeric: tabular-nums;
}
.ob-menu__desc { margin: .3rem 0 0; color: var(--ob-ink-soft); font-size: .88rem; max-width: 54ch; }

/* ---------- Quick add ----------
   Markup: ob_quick_add() in ob-core/includes/class-shop.php. Two states in one
   box: a "+" until the dish is in the cart, then a −/n/+ stepper showing the CART
   quantity. Only one is ever in flow, and both are the same height, so switching
   between them costs no layout shift.

   Two styles: --inline (menu rows, a 34px circle) and --block (shop cards, full
   card width so every button in the grid keeps its shared baseline). */
.ob-qadd { --ob-qadd-h: 34px; flex: none; }
.ob-qadd__add,
.ob-qadd__step { height: var(--ob-qadd-h); }

/* The "+" (not-in-cart) state */
.ob-qadd__add {
	display: inline-flex; align-items: center; justify-content: center; gap: .45rem;
	border: 0; border-radius: 999px;
	background: var(--ob-copper); color: #fff;
	text-decoration: none; cursor: pointer;
	font-family: var(--ob-sans); font-weight: 600; font-size: .84rem; line-height: 1;
	transition: background var(--ob-dur-2) var(--ob-ease), transform var(--ob-dur-1) var(--ob-ease),
	            box-shadow var(--ob-dur-2) var(--ob-ease);
	box-shadow: var(--ob-shadow-1);
}
.ob-qadd__add:hover { background: var(--ob-copper-br); color: #fff; box-shadow: var(--ob-shadow-2); transform: translateY(-1px); }
.ob-qadd__add:active { transform: translateY(0) scale(.94); }
.ob-qadd--inline .ob-qadd__add { width: var(--ob-qadd-h); padding: 0; }

/* The stepper (in-cart) state */
.ob-qadd__step {
	display: none;
	align-items: center;
	background: var(--ob-surface);
	border: 1px solid var(--ob-tan);
	border-radius: 999px;
	overflow: hidden;
}
.ob-qadd.is-active .ob-qadd__add { display: none; }
.ob-qadd.is-active .ob-qadd__step { display: inline-flex; }

/* The two states swap via `display`, which cannot be transitioned — so whichever
   arrives animates itself in. Gated on .is-flip, which main.js adds only when the
   USER caused the change: without that gate all 30 controls would pop on load. */
.ob-qadd.is-flip.is-active .ob-qadd__step,
.ob-qadd.is-flip:not(.is-active) .ob-qadd__add {
	animation: ob-pop-in var(--ob-dur-2) var(--ob-pop) both;
}
/* And the number bumps when the quantity changes without a state flip. */
.ob-qadd__n { display: inline-block; }
.ob-qadd__n.is-bump { animation: ob-bump var(--ob-dur-2) var(--ob-pop); }

/* 30px wide, and that is a decision like the language codes': the menu row's stepper
   replaces a 42px "+" with an 88px control, and 40px buttons would make it 106px —
   twenty of the ~150px a Georgian dish name has at 320px. Height is the axis that was
   failing and it is 40; the width clears the 24px AA floor. The shop CARD's stepper is
   full-width and does get 40, in the --block override below. Do not "fix" this one. */
.ob-qadd__pm {
	display: grid; place-items: center;
	width: 30px; height: calc(var(--ob-qadd-h) - 2px); padding: 0;
	border: 0; background: none; cursor: pointer;
	color: var(--ob-copper); text-decoration: none;
	transition: background var(--ob-dur-1) var(--ob-ease), color var(--ob-dur-1) var(--ob-ease),
	            transform var(--ob-dur-1) var(--ob-ease);
}
.ob-qadd__pm:hover:not(:disabled) { background: rgba(var(--ob-tan-rgb), .16); }
.ob-qadd__pm:active:not(:disabled) { transform: scale(.86); }
.ob-qadd__pm:disabled { color: var(--ob-ink-soft); opacity: .4; cursor: default; }
.ob-qadd__n {
	min-width: 26px; text-align: center;
	font-size: .88rem; font-weight: 700; color: var(--ob-ink);
	font-variant-numeric: tabular-nums;
}
.ob-qadd__ic { width: 15px; height: 15px; display: block; }
.ob-qadd__add:focus-visible,
.ob-qadd__pm:focus-visible { outline: 2px solid var(--ob-walnut); outline-offset: 2px; }

/* In-flight: dim without moving anything, so a fast tapper sees feedback but the
   row never jumps. */
.ob-qadd.is-busy { opacity: .65; }

/* Shop-card variant — fills the card, keeps the grid's shared button baseline. */
.ob-qadd--block { --ob-qadd-h: 2.6rem; display: block; }
.ob-qadd--block .ob-qadd__add { width: 100%; border-radius: 3px; }
.ob-qadd--block .ob-qadd__step { width: 100%; border-radius: 3px; justify-content: space-between; }
.ob-qadd--block .ob-qadd__pm { width: 44px; height: calc(var(--ob-qadd-h) - 2px); }
.ob-qadd--block .ob-qadd__n { flex: 1; font-size: .95rem; }
/* nowrap is load-bearing: a two-line label makes THIS card's button taller than
   the stepper on its neighbour, and the grid's shared button baseline is gone. */
.ob-qadd__label { white-space: nowrap; }

/* Two-up cards on a phone leave ~147px inside the card, which the full Georgian
   label plus an icon can't share. The label is the more useful half — the icon
   goes, and the "+" affordance returns as the stepper the moment it's in the cart.

   Dropping the icon is not enough, and that is the "button text is cropped" report:
   კალათაში დამატება measures 140px at .78rem, and the button is 128px wide at
   360px and 108px at 320px — so 12px and then 31px of the label was sliced off by the
   card's own overflow:hidden. Nothing is wrong with the button; the label does not fit
   on one line on a small phone, and 375px is the knife edge. So it WRAPS here, and
   `--ob-qadd-h` grows once to hold two lines.

   That is technique 1 from the touch-target block below: one declaration drives both
   quick-add states, so the +/stepper swap still costs no layout shift and every button
   in the grid keeps the shared baseline the card design is built on. The shorter English
   and Russian labels stay on one line inside the same taller button.

   The selector is `.ob-qadd.ob-qadd--block`, not `.ob-qadd--block`: the touch-target
   block sets `--ob-qadd-h: var(--ob-touch)` on `.ob-qadd` at max-width 1023px, which is
   the same specificity and LATER in the file, so it would win. A media query adds no
   specificity — this file has been bitten by that before. */
@media (max-width: 560px) {
	.ob-qadd.ob-qadd--block { --ob-qadd-h: 3.25rem; }
	.ob-qadd--block .ob-qadd__add .ob-qadd__ic { display: none; }
	.ob-qadd--block .ob-qadd__add { font-size: .78rem; padding-inline: .4rem; }
	.ob-qadd--block .ob-qadd__label { white-space: normal; text-align: center; line-height: 1.18; }
	/* 40, not 38: two of these plus the 26px number is 106px inside the 108px button a
	   two-up card gives at 320px, so the touch floor fits with 2px to spare. */
	.ob-qadd--block .ob-qadd__pm { width: var(--ob-touch); }
}

/* Phones: the dotted leader is a desktop device — `white-space: nowrap` on the name is
   what makes it work, and on a 390px screen a long Georgian dish name then forces the
   whole PAGE wide (266px of horizontal overflow). Below this width the name wraps and
   the leader is dropped; name and price simply sit together.

   The row itself stays ONE row: thumb | name + price | control, which is the layout of
   every delivery app's menu list. It used to send the "+" to a line of its own —
   `flex-basis: calc(100% - 84px)` on the text block filled row one exactly and
   `margin-left: auto` right-aligned the orphan — so the control sat 65px BELOW the dish
   it belongs to and every row was 154px tall around a 68px photo. That is the "plus icon
   jumps one row lower" report. `nowrap` on the row forbids the break; the text block
   needs `min-width: 0` to be allowed to shrink rather than push the control out. */
@media (max-width: 620px) {
	.ob-menu__row { flex-wrap: nowrap; gap: .75rem; }
	.ob-menu__row-main { flex: 1 1 auto; min-width: 0; }
	.ob-menu__name { white-space: normal; }
	.ob-menu__dots { display: none; }
	.ob-menu__lead { flex-wrap: wrap; gap: .1rem .6rem; }
}
/* On a phone the photo is what the name is short of: 68px of thumb plus a 40px control
   leaves 152px at 320px for a Georgian dish name at 1.15rem, which is three lines. 480 is
   an existing breakpoint in this file rather than a new one measured for this row, and
   56px is the thumbnail size the cart already uses. */
@media (max-width: 480px) {
	.ob-menu__row { padding-inline: .45rem; margin-inline: -.45rem; gap: .6rem; }
	.ob-menu__thumb { width: 56px; height: 56px; }
	.ob-menu__name { font-size: 1.02rem; }
}

/* ---------- Forms ---------- */
.ob-form__row { display: flex; flex-direction: column; gap: .35rem; margin: 0 0 1rem; }
.ob-form label { font-size: .8rem; letter-spacing: .04em; color: var(--ob-ink-soft); }
.ob-form input, .ob-form textarea {
	font: inherit;
	padding: .6rem .75rem;
	border: 1px solid var(--ob-line);
	border-radius: 3px;
	background: var(--ob-surface);
	color: var(--ob-ink);
}
.ob-form input:focus, .ob-form textarea:focus { outline: 2px solid var(--ob-tan-2); outline-offset: 1px; border-color: var(--ob-tan); }
.ob-form__hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.ob-form__notice { padding: .8rem 1rem; border-radius: 3px; margin-bottom: 1.2rem; font-size: .9rem; }
/* Success/error stay semantic rather than brand-coloured: the accent is now a
   warm sienna, and an error styled in it would read as a primary action. */
.ob-form__notice--ok { background: rgba(74, 110, 42, .14); border: 1px solid rgba(74, 110, 42, .4); color: #3c5722; }
.ob-form__notice--err { background: rgba(158, 27, 27, .1); border: 1px solid rgba(158, 27, 27, .4); color: var(--ob-err); }

/* ---------- Shared media placeholder ---------- */
.ob-media-ph {
	width: 100%; height: 100%; min-height: 180px;
	display: grid; place-items: center;
	color: rgba(255, 255, 255, .8);
	background:
		radial-gradient(80% 80% at 30% 20%, rgba(var(--ob-tan-rgb), .4), transparent 60%),
		linear-gradient(150deg, #7C5433, #C08F63);
}
.ob-media-ph svg { width: 46%; max-width: 96px; height: auto; opacity: .9; }

/* ---------- About: story ---------- */
.ob-story { display: grid; grid-template-columns: 1fr; gap: 2.5rem; align-items: center; }
@media (min-width: 860px) { .ob-story { grid-template-columns: 1.15fr .85fr; } }
.ob-story__body .entry-content { max-width: none; }
.ob-story__body h2 { font-size: clamp(1.8rem, 4vw, 2.4rem); margin: 1.6rem 0 .8rem; }
/* The opening paragraph carries the whole "what is this place" job, so it is set
   as a lead rather than as the first of three equal paragraphs. Selected in CSS
   instead of being split out in PHP: the copy comes from the block editor and
   the client must stay free to rewrite it without the markup shape mattering. */
.ob-story__body .entry-content > p:first-child {
	font-size: clamp(1.05rem, 1.9vw, 1.24rem);
	line-height: 1.55;
	color: var(--ob-ink);
	margin-top: 0;
}
.ob-story__body .entry-content > p { color: var(--ob-ink-soft); }

/* ---------- About: fact strip ----------
   Three real numbers under the story. Hairline-divided rather than boxed, so it
   cannot be mistaken for the three value cards further down the same page — and
   because a number needs a rule beside it, not a container around it.
   Walnut numerals, not copper: three copper numbers at this size would outshout
   every button on the page, and copper is reserved for things you can act on. */
.ob-facts {
	display: grid;
	grid-template-columns: 1fr;
	gap: 1.2rem;
	margin: clamp(2.5rem, 6vw, 3.5rem) 0 0;
	padding-top: clamp(1.8rem, 4vw, 2.4rem);
	border-top: 1px solid var(--ob-line);
}
.ob-fact { min-width: 0; }
.ob-fact__num {
	font-family: var(--ob-serif);
	font-weight: 600;
	font-size: clamp(2.1rem, 5vw, 2.9rem);
	line-height: 1;
	color: var(--ob-walnut);
	font-variant-numeric: tabular-nums;
}
/* A time range is two numbers and a dash, so it runs far wider than "1994" at
   the same size and would force the third column to wrap. */
.ob-fact__num--time { font-size: clamp(1.6rem, 3.4vw, 2.1rem); }
.ob-fact__lbl {
	margin: .5rem 0 0;
	color: var(--ob-tan-ink);
	font-size: .84rem;
	line-height: 1.45;
	max-width: 22ch;
}
@media (min-width: 720px) {
	.ob-facts { grid-auto-flow: column; grid-auto-columns: 1fr; gap: 0; }
	.ob-fact + .ob-fact { padding-inline-start: clamp(1.5rem, 4vw, 3rem); border-inline-start: 1px solid var(--ob-line); }
	.ob-fact:not(:first-child) { margin-inline-start: clamp(1.5rem, 4vw, 3rem); }
}
.ob-story__media {
	margin: 0; border-radius: 6px; overflow: hidden;
	border: 1px solid var(--ob-line); aspect-ratio: 4/5;
	box-shadow: 0 18px 40px rgba(42, 23, 12, .16);
}
.ob-story__media img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* ---------- About: values ---------- */
.ob-values { display: grid; grid-template-columns: 1fr; gap: 1.2rem; }
@media (min-width: 760px) { .ob-values { grid-template-columns: repeat(3, 1fr); } }
.ob-value {
	background: var(--ob-surface); border: 1px solid var(--ob-line-2);
	border-radius: 6px; padding: 1.6rem; text-align: center;
}
.ob-value__mark {
	display: inline-block; width: 44px; height: 44px; margin-bottom: 1rem;
	border-radius: 50%; background: var(--ob-walnut);
	position: relative;
}
.ob-value__mark::after {
	content: ""; position: absolute; inset: 0; margin: auto;
	width: 12px; height: 12px; border-radius: 50%;
	background: var(--ob-tan-2);
	box-shadow: 0 0 0 4px rgba(var(--ob-tan-rgb), .25);
}
.ob-value h3 { font-size: 1.2rem; margin-bottom: .5rem; }
.ob-value p { color: var(--ob-ink-soft); margin: 0; font-size: .92rem; }

/* ---------- About: heritage band ---------- */
/* One flat wash over the photograph, matching the home hero. This was a two-stop
   linear-gradient, which is the exact treatment the client rejected on the hero
   ("wtf is this gradient") — a darkened photograph reads as deliberate, a
   photograph with a gradient on it reads as smeared. Same .74 alpha as the hero,
   so both dark photo bands on the site are mixed identically. */
.ob-heritage {
	background:
		linear-gradient(rgba(42, 23, 12, .8), rgba(42, 23, 12, .8)),
		url(../img/placeholders/tbilisi.jpg) center / cover no-repeat;
	color: var(--ob-cream);
}
.ob-heritage__inner { display: grid; grid-template-columns: 1fr; gap: 1.2rem; align-items: center; padding-block: clamp(2.5rem, 6vw, 4rem); }
@media (min-width: 720px) { .ob-heritage__inner { grid-template-columns: auto 1fr; gap: 2.5rem; } }
.ob-heritage__year {
	font-family: var(--ob-serif); font-weight: 600;
	font-size: clamp(3.5rem, 12vw, 6.5rem); line-height: 1;
	color: var(--ob-tan-2); letter-spacing: .01em;
	font-variant-numeric: tabular-nums;
}
.ob-heritage__text p:last-child { color: var(--ob-cream-soft); margin: .5rem 0 0; max-width: 52ch; }

/* ---------- About: gallery ---------- */
/* auto-fit, not a fixed count: about.php renders three photos until the client
   supplies real ones (see the note there), and a fixed 4-column grid would
   leave a hole in the row. auto-fit collapses the empty tracks, so three items
   become three equal columns and four become four, at any width. */
.ob-gallery { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1rem; }
/* Three photos in two columns would leave a hole at the end of the second row.
   The third takes the full width instead, at 2:1 so it reads as a deliberate
   wide frame rather than a stretched square. Stacking all three at one per row
   was the other option and made the phone page 1500px longer. */
.ob-gallery__item:nth-child(3):last-child { grid-column: 1 / -1; aspect-ratio: 2 / 1; }
@media (min-width: 560px) {
	.ob-gallery { grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); }
	.ob-gallery__item:nth-child(3):last-child { grid-column: auto; aspect-ratio: 1; }
}
.ob-gallery__item {
	margin: 0; border-radius: 6px; overflow: hidden; aspect-ratio: 1;
	border: 1px solid var(--ob-line-2);
}
.ob-gallery__item img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform var(--ob-dur-3) var(--ob-ease); }
.ob-gallery__item:hover img { transform: scale(1.05); }

/* ---------- WooCommerce single product ---------- */
.ob-shop { padding-block: clamp(2.5rem, 6vw, 4rem); }
/* .ob-shop is a whole PAGE wrapper on the shop and product screens, and its
   padding is that page's vertical rhythm. The homepage borrows the class purely
   as the scope the card CSS is written against, inside an .ob-section that
   already owns the rhythm — so it was paying twice: 64px between the heading
   and the cards, and 144px of dead ground between the cards and the section
   after them. The modifier gives the padding back. */
.ob-shop--bare { padding-block: 0; }
.ob-shop .woocommerce-breadcrumb {
	font-size: .78rem; letter-spacing: .08em; text-transform: uppercase;
	color: var(--ob-ink-soft); margin-bottom: 1.8rem;
}
.ob-shop .woocommerce-breadcrumb a { color: var(--ob-tan); text-decoration: none; }
.ob-shop .woocommerce-breadcrumb a:hover { color: var(--ob-copper); }

.ob-shop div.product { display: grid; grid-template-columns: 1fr; gap: clamp(1.8rem, 5vw, 3rem); }
@media (min-width: 820px) { .ob-shop div.product { grid-template-columns: 1fr 1fr; align-items: start; } }

/* product media */
.ob-shop div.product .woocommerce-product-gallery { margin: 0; float: none; width: 100% !important; }
.ob-shop div.product .woocommerce-product-gallery__wrapper { margin: 0; border-radius: 8px; overflow: hidden; border: 1px solid var(--ob-line); }
.ob-shop div.product .woocommerce-product-gallery .ob-media-ph { aspect-ratio: 4/3; }
.ob-shop div.product .woocommerce-product-gallery img { border-radius: 8px; }

/* summary */
.ob-shop div.product .summary { margin: 0 !important; width: 100% !important; float: none !important; }
.ob-product__eyebrow { margin-bottom: .4rem; }
.ob-shop div.product .product_title {
	font-family: var(--ob-serif); font-weight: 600;
	font-size: clamp(1.9rem, 5vw, 2.8rem); line-height: 1.1; margin: 0 0 .8rem;
}
.ob-shop div.product p.price,
.ob-shop div.product span.price {
	color: var(--ob-copper) !important; font-weight: 700;
	font-size: 1.7rem; font-variant-numeric: tabular-nums; margin-bottom: 1.2rem;
}
.ob-shop div.product .woocommerce-product-details__short-description { color: var(--ob-ink-soft); margin-bottom: 1.6rem; }
.ob-shop div.product .woocommerce-product-details__short-description p { margin: 0 0 .8rem; }

/* add to cart */
.ob-shop div.product form.cart { margin: 0 0 1.2rem; display: flex; gap: .8rem; align-items: center; flex-wrap: wrap; }
.ob-shop div.product form.cart .quantity input {
	font: inherit; width: 4.5rem; padding: .6rem .5rem; text-align: center;
	border: 1px solid var(--ob-line); border-radius: 3px; background: var(--ob-surface); color: var(--ob-ink);
}
.ob-shop div.product .single_add_to_cart_button,
.ob-shop div.product .button {
	background: var(--ob-copper); color: #fff; border: 1px solid transparent;
	font-family: var(--ob-sans); font-weight: 600; font-size: .95rem;
	padding: .75rem 1.6rem; border-radius: 2px; cursor: pointer;
	transition: background var(--ob-dur-2) var(--ob-ease), transform var(--ob-dur-1) var(--ob-ease), box-shadow var(--ob-dur-2) var(--ob-ease);
}
.ob-shop div.product .single_add_to_cart_button:hover,
.ob-shop div.product .button:hover { background: var(--ob-copper-br); color: #fff; }
.ob-shop div.product .button:active { transform: translateY(1px); }

.ob-product__note {
	font-size: .82rem; color: var(--ob-ink-soft);
	padding-top: 1rem; margin: 0; border-top: 1px solid var(--ob-line-2);
	display: flex; align-items: center; gap: .5rem;
}
.ob-shop div.product .product_meta { margin-top: 1.2rem; font-size: .82rem; color: var(--ob-ink-soft); }
.ob-shop div.product .product_meta a { color: var(--ob-tan); text-decoration: none; }
.ob-shop div.product .product_meta > span { display: block; margin-bottom: .2rem; }

/* tabs */
.ob-shop .woocommerce-tabs { grid-column: 1 / -1; margin-top: clamp(1.5rem, 4vw, 2.5rem); }
.ob-shop .woocommerce-tabs ul.tabs {
	list-style: none; margin: 0 0 1.4rem; padding: 0 0 .2rem;
	display: flex; gap: 1.6rem; border-bottom: 1px solid var(--ob-line);
}
.ob-shop .woocommerce-tabs ul.tabs li { margin: 0; }
.ob-shop .woocommerce-tabs ul.tabs li a {
	text-decoration: none; font-family: var(--ob-serif); font-size: 1.05rem;
	color: var(--ob-ink-soft); padding-bottom: .7rem; display: inline-block;
	border-bottom: 2px solid transparent; margin-bottom: -.3rem;
}
.ob-shop .woocommerce-tabs ul.tabs li.active a,
.ob-shop .woocommerce-tabs ul.tabs li a:hover { color: var(--ob-ink); border-color: var(--ob-tan); }
.ob-shop .woocommerce-tabs .panel { max-width: 720px; }
.ob-shop .woocommerce-tabs .panel h2 { font-size: 1.4rem; margin: 0 0 .8rem; }
.ob-shop .woocommerce-tabs .panel p { color: var(--ob-ink-soft); margin: 0 0 .8rem; }

/* product placeholder sizing (override shared min-height) */
.ob-media-ph--product { min-height: 0; aspect-ratio: 4/3; }

/* category photo placeholder (real image) — inherits each container's img rules */
.ob-ph-img { display: block; width: 100%; object-fit: cover; }
/* Real venue photographs (assets/img/venue/, ob_venue_photo()). Both places that
   currently use them — .ob-gallery__item and .ob-about__media — already size a
   bare `img`, so this is only a floor for any future container that does not. */
.ob-venue-img { display: block; width: 100%; object-fit: cover; }
.ob-menu__thumb .ob-ph-img,
.ob-pcard__media .ob-ph-img { height: 100%; }

/* ---------- WooCommerce shop / category archive (card grid) ----------
   Markup: theme woocommerce/content-product.php. The card is deliberately built
   from fixed-height rows — eyebrow (1 line), name (clamped to exactly 2), price
   (1 line) — so every card in the grid is the same height and the prices and
   add-to-cart buttons share a baseline no matter how long a dish name runs.
   Nothing here may depend on the length of the copy. */

.ob-shop--archive { padding-top: clamp(2rem, 5vw, 3rem); }

/* Category filter row (links; same chips as the digital menu page). */
.ob-shopnav {
	display: flex; flex-wrap: wrap; gap: .5rem; justify-content: center;
	margin-bottom: clamp(1.8rem, 4.5vw, 2.6rem);
}

.ob-shop ul.products {
	list-style: none; margin: 0; padding: 0;
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(228px, 1fr));
	gap: clamp(1rem, 2.2vw, 1.5rem);
	align-items: stretch;
}
/* WooCommerce's float clearfix would add phantom grid items. */
.ob-shop ul.products::before, .ob-shop ul.products::after { content: none; display: none; }

.ob-pcard {
	position: relative; /* anchors the sale flash + the "view cart" pill */
	margin: 0 !important; width: auto !important; float: none !important; padding: 0;
	display: flex; flex-direction: column;
	background: var(--ob-surface);
	/* A tan-tinted hairline, not --ob-line-2: the surface sits only a shade above
	   the page ground, so an 8%-ink border left the cards reading as loose photos
	   rather than as a grid of cards. */
	border: 1px solid rgba(var(--ob-tan-rgb), .38);
	border-radius: 8px;
	overflow: hidden;
	text-align: left;
	transition: transform var(--ob-dur-2) var(--ob-ease), border-color var(--ob-dur-2) var(--ob-ease), box-shadow var(--ob-dur-2) var(--ob-ease);
}
.ob-pcard:hover {
	transform: translateY(-3px);
	border-color: var(--ob-tan);
	box-shadow: var(--ob-shadow-3);
}

/* Media — one ratio for the whole grid. The parchment ground keeps product
   shots that were photographed on white (bottled drinks) from glaring. */
.ob-pcard__media {
	display: block; position: relative;
	aspect-ratio: 4 / 3;
	background: var(--ob-surface-2);
	border-bottom: 1px solid rgba(var(--ob-tan-rgb), .3);
	overflow: hidden;
}
/* The shared line-art placeholder is a warm gradient tile, which shouts in a
   grid of photographs. Inside a card it becomes a quiet parchment panel. */
.ob-pcard__media .ob-media-ph { background: var(--ob-surface-2); color: var(--ob-tan); }
.ob-pcard__media .ob-media-ph svg { width: 34%; opacity: .5; }
/* The long selector is deliberate: WooCommerce ships
   `.woocommerce ul.products li.product img { height: auto }` at (0,3,1), which
   outranks a plain `.ob-pcard__media img` and leaves the photo at its native
   ratio inside the 4/3 frame. This has to out-specify it. */
.ob-shop ul.products li.ob-pcard .ob-pcard__media img,
.ob-shop ul.products li.ob-pcard .ob-pcard__media .ob-media-ph {
	width: 100%; height: 100%; min-height: 0; margin: 0;
	transition: transform var(--ob-dur-3) var(--ob-ease);
}
.ob-shop ul.products li.ob-pcard .ob-pcard__media img { display: block; object-fit: cover; }
/* Keep the line-art placeholder a centring grid — `display:block` from the rule
   above would strand its icon in the top-left corner. */
.ob-shop ul.products li.ob-pcard .ob-pcard__media .ob-media-ph { display: grid; place-items: center; }
.ob-shop ul.products li.ob-pcard:hover .ob-pcard__media img { transform: scale(1.05); }
.ob-pcard .onsale {
	position: absolute; top: .6rem; left: .6rem; z-index: 2; margin: 0;
	background: var(--ob-copper); color: #fff; border-radius: 999px;
	font-size: .68rem; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
	padding: .28rem .6rem; min-height: 0; min-width: 0; line-height: 1.4;
}

.ob-pcard__body {
	flex: 1;
	display: flex; flex-direction: column;
	padding: .95rem 1rem 1.05rem;
}
/* Rendered even when a dish has no category, so the row still holds its line.
   --ob-tan-ink, not the eyebrow's default --ob-tan: at 10px this is body-size
   text and needs 4.5:1, which --ob-tan misses on the card surface. */
.ob-pcard__cat {
	font-size: var(--ob-eyebrow-tight); letter-spacing: .18em; color: var(--ob-tan-ink);
	min-height: 1.1em; margin: 0 0 .35rem;
	white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* Exactly two lines, always — the single biggest source of ragged cards. */
.ob-pcard__name {
	font-family: var(--ob-serif); font-size: 1.02rem; font-weight: 600; line-height: 1.34;
	margin: 0;
	min-height: calc(2 * 1.34em);
	display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
	overflow: hidden;
	text-wrap: initial; /* balancing would fight the clamp */
}
.ob-pcard__name a { color: var(--ob-ink); text-decoration: none; }
.ob-pcard__name a:hover { color: var(--ob-copper); }
.ob-pcard__name a:focus-visible { outline: 2px solid var(--ob-copper); outline-offset: 3px; border-radius: 2px; }

.ob-pcard__price {
	margin: .55rem 0 0; padding-top: .55rem;
	border-top: 1px solid var(--ob-line-2);
	color: var(--ob-copper); font-weight: 700; font-size: 1.02rem;
	font-variant-numeric: tabular-nums;
}
.ob-pcard__price del { color: var(--ob-ink-soft); font-weight: 400; opacity: .7; margin-right: .35rem; }
.ob-pcard__price ins { text-decoration: none; }

/* margin-top:auto is a safety net: the rows above are fixed-height so it should
   never engage, but if anything does wrap the buttons stay bottom-aligned. */
.ob-pcard__action { margin-top: auto; padding-top: .8rem; }
.ob-shop .ob-pcard .button {
	display: flex; align-items: center; justify-content: center;
	width: 100%; min-height: 2.6rem; margin: 0; padding: .5rem .9rem;
	background: var(--ob-copper); color: #fff; border: 0; border-radius: 3px;
	font-family: var(--ob-sans); font-weight: 600; font-size: .84rem; line-height: 1.3;
	text-align: center; text-decoration: none; white-space: nowrap;
	cursor: pointer; transition: background var(--ob-dur-2) var(--ob-ease), transform var(--ob-dur-1) var(--ob-ease);
}
.ob-shop .ob-pcard .button:hover { background: var(--ob-copper-br); color: #fff; }
.ob-shop .ob-pcard .button:active { transform: translateY(1px); }
.ob-shop .ob-pcard .button:focus-visible { outline: 2px solid var(--ob-walnut); outline-offset: 2px; }
.ob-shop .ob-pcard .button.loading { opacity: .7; }
/* Woo's own states use its icon font; keep them in our type instead. */
.ob-shop .ob-pcard .button.loading::after,
.ob-shop .ob-pcard .button.added::after { font-family: inherit; margin-left: .4rem; }
.ob-shop .ob-pcard .button.loading::after { content: "…"; }
.ob-shop .ob-pcard .button.added::after { content: "✓"; }

/* The "view cart" link Woo injects after an AJAX add. Floated over the photo so
   appearing costs no layout height — otherwise the card grows and the row of
   buttons goes ragged the moment someone orders something. */
.ob-pcard .added_to_cart {
	position: absolute; top: .6rem; right: .6rem; z-index: 3;
	margin: 0; padding: .34rem .7rem;
	background: var(--ob-walnut-deep); color: var(--ob-cream);
	border: 1px solid rgba(var(--ob-tan-rgb), .45); border-radius: 999px;
	font-size: .7rem; letter-spacing: .03em; text-decoration: none;
	box-shadow: 0 4px 14px rgba(42, 23, 12, .3);
}
.ob-pcard .added_to_cart:hover { background: var(--ob-copper); color: #fff; border-color: var(--ob-copper); }

/* Pagination (only appears if the catalog outgrows loop_shop_per_page). */
.ob-shop .woocommerce-pagination { margin-top: clamp(2rem, 5vw, 3rem); }
.ob-shop .woocommerce-pagination ul.page-numbers {
	display: flex; flex-wrap: wrap; justify-content: center; gap: .4rem;
	list-style: none; margin: 0; padding: 0; border: 0;
}
.ob-shop .woocommerce-pagination li { margin: 0; border: 0; overflow: visible; }
.ob-shop .woocommerce-pagination a.page-numbers,
.ob-shop .woocommerce-pagination span.page-numbers {
	display: grid; place-items: center;
	min-width: 40px; height: 40px; padding: 0 .6rem;
	background: var(--ob-surface); border: 1px solid var(--ob-line); border-radius: 4px;
	color: var(--ob-ink-soft); font-size: .88rem; text-decoration: none;
	transition: border-color var(--ob-dur-2) var(--ob-ease), color var(--ob-dur-2) var(--ob-ease);
}
.ob-shop .woocommerce-pagination a.page-numbers:hover { border-color: var(--ob-tan); color: var(--ob-ink); }
.ob-shop .woocommerce-pagination span.current {
	background: var(--ob-walnut); border-color: var(--ob-walnut); color: var(--ob-cream);
}

/* Two-up on phones: a one-column list of food cards scrolls forever. */
@media (max-width: 560px) {
	.ob-shop ul.products { grid-template-columns: repeat(2, 1fr); gap: .8rem; }
	.ob-pcard__body { padding: .75rem .8rem .85rem; }
	.ob-pcard__cat { font-size: var(--ob-eyebrow-tight); letter-spacing: .14em; }
	.ob-pcard__name { font-size: .92rem; }
	.ob-pcard__price { font-size: .94rem; }
	.ob-shop .ob-pcard .button { font-size: .74rem; padding: .5rem .4rem; min-height: 2.4rem; }
	.ob-pcard .added_to_cart { font-size: .64rem; padding: .26rem .55rem; }
}

/* woo notices (add-to-cart feedback) */
.ob-shop .woocommerce-message,
.ob-shop .woocommerce-info {
	background: var(--ob-surface-2); border-left: 3px solid var(--ob-tan);
	padding: .9rem 1.1rem; border-radius: 3px; margin-bottom: 1.4rem; list-style: none;
}
.ob-shop .woocommerce-message a, .ob-shop .woocommerce-info a { color: var(--ob-copper); }

/* ---------- "Note for the kitchen" field, on the dish page ----------
   Markup: ob-core/includes/class-item-notes.php. It sits inside form.cart, which
   is a wrapping flex row (quantity + button), so the field claims a full row of
   its own rather than trying to share one with a 70px number input. */

.ob-inote { flex: 1 0 100%; margin: 0 0 .2rem; }
.ob-inote__label {
	display: block; margin-bottom: .35rem;
	font-size: .78rem; font-weight: 600; letter-spacing: .02em; color: var(--ob-ink-soft);
}
.ob-inote__input,
.ob-cnote__input {
	display: block; width: 100%; box-sizing: border-box;
	padding: .55rem .7rem;
	background: var(--ob-surface); color: var(--ob-ink);
	border: 1px solid var(--ob-line); border-radius: 3px;
	font-family: var(--ob-sans); font-size: .88rem; line-height: 1.5;
	resize: vertical;
	transition: border-color var(--ob-dur-2) var(--ob-ease), box-shadow var(--ob-dur-2) var(--ob-ease);
}
.ob-inote__input::placeholder,
.ob-cnote__input::placeholder { color: var(--ob-ink-soft); opacity: .7; }
.ob-inote__input:focus,
.ob-cnote__input:focus {
	outline: none;
	border-color: var(--ob-copper);
	box-shadow: 0 0 0 3px rgba(var(--ob-tan-rgb), .3);
}
.ob-inote__hint { margin: .35rem 0 0; font-size: .74rem; line-height: 1.45; color: var(--ob-ink-soft); }

/* ---------- "Similar dishes" rail (dish page) ----------
   Markup: ob-core/includes/class-related.php. The cards are the shop grid's
   .ob-pcard, untouched — everything here changes the CONTAINER and nothing about
   the card, which is why a rail card and a grid card cannot drift apart. */

/* .ob-shop div.product is a two-column grid from 820px up (photo | summary), so
   like .woocommerce-tabs the rail has to claim both columns or it would be filed
   under the photo at half width. */
.ob-rel {
	grid-column: 1 / -1;
	/* Load-bearing, and it is not obvious. A grid item's automatic minimum size is
	   its CONTENT, not zero, so the rail refused to be narrower than ten cards laid
	   end to end: the item measured 1792px inside a 355px column, the scroller was
	   handed all 1792 of them and therefore had nothing left to scroll, and the
	   whole page went with it — measured 1816px of document against a 390px
	   viewport. min-width:0 is what lets the item be narrow so the scroller can do
	   its job. */
	min-width: 0;
	margin-top: clamp(2rem, 5vw, 3rem);
	padding-top: clamp(1.5rem, 3.5vw, 2.2rem);
	border-top: 1px solid var(--ob-line);
}
.ob-rel__head {
	display: flex; align-items: center; justify-content: space-between; gap: 1rem;
	margin-bottom: clamp(1rem, 2.4vw, 1.4rem);
}
.ob-rel__title {
	margin: 0;
	font-family: var(--ob-serif); font-weight: 600; font-size: clamp(1.2rem, 2.8vw, 1.55rem);
	color: var(--ob-ink);
}
.ob-rel__nav { display: flex; gap: .4rem; flex: 0 0 auto; }
/* A class selector (0,1,0) outranks the UA sheet's `[hidden] { display: none }`,
   so without this the nav would render on every page and the `hidden` attribute —
   the whole mechanism for keeping arrows off a rail that does not overflow —
   would do nothing at all. */
.ob-rel__nav[hidden] { display: none; }
.ob-rel__arrow {
	display: grid; place-items: center;
	width: 38px; height: 38px; padding: 0;
	background: var(--ob-surface); color: var(--ob-ink);
	border: 1px solid var(--ob-line); border-radius: 999px;
	cursor: pointer;
	transition: border-color var(--ob-dur-2) var(--ob-ease), color var(--ob-dur-2) var(--ob-ease), opacity var(--ob-dur-2) var(--ob-ease);
}
.ob-rel__arrow svg { width: 19px; height: 19px; }
.ob-rel__arrow:hover { border-color: var(--ob-tan); color: var(--ob-copper); }
.ob-rel__arrow:focus-visible { outline: 2px solid var(--ob-copper); outline-offset: 2px; }
/* Kept in the layout rather than hidden at an end: arrows that come and go make
   the heading row jump every time the rail reaches its last card. */
.ob-rel__arrow[disabled] { opacity: .35; cursor: default; border-color: var(--ob-line); color: var(--ob-ink); }

.ob-rel__scroller {
	overflow-x: auto;
	overscroll-behavior-x: contain;
	scroll-snap-type: x proximity;
	scrollbar-width: none;
	/* The cards lift 3px and cast a shadow on hover. Without this bleed the
	   scroller's own overflow clips both, and hovering a card looks like a
	   rendering fault along the top edge. */
	margin: -6px; padding: 6px;
}
.ob-rel__scroller::-webkit-scrollbar { display: none; }
/* The scroller is focusable so it can be panned by keyboard; say so visibly. */
.ob-rel__scroller:focus-visible { outline: 2px solid var(--ob-copper); outline-offset: 2px; border-radius: 8px; }

/* Beats `.ob-shop ul.products` (0,2,1), which is a grid. */
.ob-shop ul.products.ob-rel__track {
	display: flex;
	grid-template-columns: none;
	gap: clamp(.8rem, 2vw, 1.2rem);
	align-items: stretch;
}
/* flex-basis, not width: .ob-pcard carries `width: auto !important` (it has to,
   to undo WooCommerce's own float grid), and no width declaration can beat that.
   A flex-basis other than `auto` is what actually sizes a flex item, and it is
   not a width, so the !important never enters the argument. */
.ob-shop ul.products.ob-rel__track > li.ob-pcard {
	flex: 0 0 228px;
	scroll-snap-align: start;
}

@media (max-width: 560px) {
	/* Two cards and a sliver of the third — the sliver is the only thing telling
	   a thumb there is more to the right. */
	.ob-shop ul.products.ob-rel__track > li.ob-pcard { flex-basis: 43vw; }
	.ob-rel__nav { display: none; }
}

/* ---------- WooCommerce cart & checkout (classic) ---------- */
.woocommerce-cart .entry-content,
.woocommerce-checkout .entry-content { max-width: none; }

/* Notices (also used on cart/checkout, outside .ob-shop).
   The `border` shorthand is load-bearing: WooCommerce sets a 3px coloured
   border-TOP on these (purple/green/blue depending on type), which clashed with
   the palette and was never overridden by a border-left alone. */
.woocommerce-message, .woocommerce-info, .woocommerce-error, .woocommerce-noreviews {
	display: flex; align-items: center; gap: .8rem; flex-wrap: wrap;
	background: var(--ob-surface-2);
	border: 1px solid rgba(var(--ob-tan-rgb), .34);
	border-left: 3px solid var(--ob-tan);
	padding: .85rem 1.1rem; border-radius: 4px; margin: 0 0 1.2rem;
	list-style: none; font-size: .92rem;
}
/* WooCommerce draws an icon here from its own icon font. The font loads but the
   glyph for these codes is missing in 10.9, so it rendered as a tofu box sitting
   on top of the first word (its `position:absolute; left:1.5em` assumes Woo's own
   3.5em padding, which the padding above replaces). The second rule is Woo's
   float clearfix, unnecessary now the notice is a flex row. */
.woocommerce-message::before, .woocommerce-info::before, .woocommerce-error::before,
.woocommerce-message::after, .woocommerce-info::after, .woocommerce-error::after {
	content: none !important; display: none !important;
}
.woocommerce-error { border-left-color: var(--ob-err); }
.woocommerce-message { border-left-color: #4A6E2A; }
.woocommerce-message a, .woocommerce-info a { color: var(--ob-copper); }
/* Any button Woo puts in a notice ("View cart") goes to the far end of the row. */
.woocommerce-message .button, .woocommerce-info .button { margin-left: auto; }

/* ---------- Checkout validation ---------- */
/* A failed submit renders .woocommerce-error as a <ul> with one <li> per invalid
   field — a LIST, not the one-line message the flex row above was written for. As a
   flex container each message became a wrapped flex item, gap-spaced and
   vertically centred, so a seven-field failure arrived as a jumbled block with
   uneven spacing. Errors are the one notice type that is always a list, so the
   element selector is enough to separate the two cases. */
ul.woocommerce-error {
	display: block;
	padding: 1rem 1.1rem;
}
ul.woocommerce-error li { color: var(--ob-ink); }
ul.woocommerce-error li + li { margin-top: .55rem; }
/* Woo wraps the ENTIRE sentence in a jump-to-field anchor, and the theme's link
   underline then ran under the whole message — which is what made the block read as
   broken text rather than as prose. The field name alone carries the affordance. */
ul.woocommerce-error li a { color: inherit; text-decoration: none; }
ul.woocommerce-error li a strong {
	color: var(--ob-err);
	text-decoration: underline;
	text-decoration-thickness: 1px;
	text-underline-offset: 2px;
	transition: color var(--ob-dur-2) var(--ob-ease);
}
ul.woocommerce-error li a:hover strong { color: var(--ob-copper); }
ul.woocommerce-error li a:focus-visible { outline: 2px solid var(--ob-tan-2); outline-offset: 3px; border-radius: 2px; }

/* Woo also prints the message again under the field itself, as a bare <p> with no
   styling of its own — at body colour and size it read as a hint rather than as the
   reason the field is outlined red. */
.checkout-inline-error-message {
	margin: .35rem 0 0;
	font-size: .82rem;
	line-height: 1.35;
	color: var(--ob-err);
}

/* WooCommerce marks every SATISFIED field with a #007518 green border — the one hue
   nowhere in the walnut/copper palette, and it appeared on the country select and
   the optional fields the moment validation ran, so a failed submit lit up green and
   red at once. A filled-in field is the ordinary state and needs no decoration:
   these return to the normal border, leaving red as the only signal.
   The country dropdown is handled by the select2 rules further down, which need
   Woo's own selector shape to outrank it. */
.woocommerce form .form-row.woocommerce-validated input.input-text,
.woocommerce form .form-row.woocommerce-validated select,
.woocommerce form .form-row.woocommerce-validated textarea {
	border-color: var(--ob-line);
}

/* Tables (cart + order review) */
.woocommerce-cart table.shop_table,
.woocommerce-checkout table.shop_table {
	width: 100%; border-collapse: collapse; margin: 0 0 1.5rem;
	border: 1px solid var(--ob-line); border-radius: 6px; overflow: hidden; background: var(--ob-surface);
}
/* --ob-tan-ink, not --ob-tan: at .7rem these are body-size labels and need 4.5:1,
   which --ob-tan misses on both light grounds. */
.woocommerce-cart table.shop_table th,
.woocommerce-checkout table.shop_table th {
	text-align: left; font-size: .7rem; letter-spacing: .12em; text-transform: uppercase;
	color: var(--ob-tan-ink); padding: .85rem 1rem; font-weight: 700;
}
/* Only the HEADER row gets the rule. Totals rows use <th> for the row LABEL, so
   applying this to every th drew a hairline under the label cell that stopped
   before the amount column — it read as a rendering fault on both the cart totals
   and the checkout summary. */
.woocommerce-cart table.shop_table thead th,
.woocommerce-checkout table.shop_table thead th { border-bottom: 1px solid var(--ob-line); }
.woocommerce-cart table.shop_table td,
.woocommerce-checkout table.shop_table td {
	padding: .85rem 1rem; border-top: 1px solid var(--ob-line-2); vertical-align: middle;
}
.woocommerce-cart td.product-name a,
.woocommerce-checkout .cart_item td.product-name { color: var(--ob-ink); text-decoration: none; font-family: var(--ob-serif); }
.woocommerce-cart td.product-name a:hover { color: var(--ob-copper); }
.amount, .woocommerce-Price-amount { font-variant-numeric: tabular-nums; }
tr.order-total .amount, .product-subtotal .amount { color: var(--ob-copper); font-weight: 700; }

.woocommerce-cart td.product-thumbnail img,
.woocommerce-cart td.product-thumbnail .ob-media-ph { width: 56px; height: 56px; border-radius: 4px; object-fit: cover; min-height: 0; display: block; }
.woocommerce-cart td.product-remove a.remove { color: var(--ob-ink-soft); text-decoration: none; font-size: 1.1rem; }
.woocommerce-cart td.product-remove a.remove:hover { color: var(--ob-copper); }

/* Column widths — fixed layout so widths are honoured; keeps the ✕, thumbnail
   and name tight together on the left (auto layout ignored the widths). */
.woocommerce-cart table.cart { table-layout: fixed; }
.woocommerce-cart table.cart td.product-remove,
.woocommerce-cart table.cart th.product-remove { width: 44px; text-align: center; padding-left: .3rem; padding-right: .3rem; }
.woocommerce-cart table.cart td.product-thumbnail,
.woocommerce-cart table.cart th.product-thumbnail { width: 84px; padding-right: 0; }
.woocommerce-cart table.cart td.product-name,
.woocommerce-cart table.cart th.product-name { text-align: left; width: auto; word-wrap: break-word; }
.woocommerce-cart table.cart td.product-price,
.woocommerce-cart table.cart th.product-price { width: 92px; text-align: right; }
.woocommerce-cart table.cart td.product-quantity,
.woocommerce-cart table.cart th.product-quantity { width: 110px; text-align: right; }
.woocommerce-cart table.cart td.product-subtotal,
.woocommerce-cart table.cart th.product-subtotal { width: 100px; text-align: right; white-space: nowrap; }
.woocommerce-cart table.cart td.product-quantity .quantity { display: inline-flex; }

/* Quantity input */
.woocommerce .quantity input.qty {
	width: 3.8rem; padding: .5rem; text-align: center; font: inherit;
	border: 1px solid var(--ob-line); border-radius: 3px; background: var(--ob-surface); color: var(--ob-ink);
}

/* Buttons on cart/checkout — brand pomegranate; override Woo's purple .alt.
   !important + high specificity because WooCommerce's own stylesheet wins otherwise. */
.woocommerce-cart a.button, .woocommerce-cart button.button, .woocommerce-cart input.button,
.woocommerce-checkout a.button, .woocommerce-checkout button.button, .woocommerce-checkout input.button,
.woocommerce a.button.alt, .woocommerce button.button.alt, .woocommerce input.button.alt,
.wc-proceed-to-checkout a.checkout-button,
.woocommerce #place_order {
	background: var(--ob-copper) !important; color: #fff !important; border: 1px solid transparent !important;
	border-radius: 2px; font-family: var(--ob-sans); font-weight: 600; font-size: .9rem;
	/* .75, not .7: at .7rem these came to 39.3px tall, one pixel under --ob-touch, at every
	   width. Padding rather than min-height so the label stays optically centred. */
	padding: .75rem 1.4rem; cursor: pointer; transition: background var(--ob-dur-2) var(--ob-ease), transform var(--ob-dur-1) var(--ob-ease), box-shadow var(--ob-dur-2) var(--ob-ease); text-decoration: none; display: inline-block;
}
.woocommerce-cart a.button:hover, .woocommerce-cart button.button:hover, .woocommerce-cart input.button:hover,
.woocommerce-checkout a.button:hover, .woocommerce-checkout button.button:hover, .woocommerce-checkout input.button:hover,
.woocommerce a.button.alt:hover, .woocommerce button.button.alt:hover, .woocommerce input.button.alt:hover,
.wc-proceed-to-checkout a.checkout-button:hover,
.woocommerce #place_order:hover { background: var(--ob-copper-br) !important; color: #fff !important; }

/* Secondary buttons: update cart + apply coupon (gold outline). Placed after the
   primary rule so source order wins the !important tie. */
.woocommerce-cart button[name="update_cart"],
.woocommerce-cart button[name="apply_coupon"] {
	background: transparent !important; color: var(--ob-ink) !important; border: 1px solid var(--ob-line) !important;
}
.woocommerce-cart button[name="update_cart"]:hover,
.woocommerce-cart button[name="apply_coupon"]:hover { border-color: var(--ob-tan) !important; }
.woocommerce-cart button[name="update_cart"][disabled] { opacity: .5; cursor: default; }

/* ---------- Per-line kitchen note, in the cart's product-name cell ----------
   Markup: ob-core/includes/class-item-notes.php. Deliberately placed AFTER the
   button rules above: "Save note" is a real button[name="update_cart"] (that is
   how it rides WooCommerce's own update handler with and without JS), so it
   inherits their .7rem/1.4rem sizing, and .woocommerce-cart button.ob-cnote__save
   only ties that specificity — source order is what wins it back. */

.ob-cnote { margin-top: .5rem; font-family: var(--ob-sans); }

/* The note as the shopper will be charged for it. Serif is inherited from
   td.product-name; this is data, not a dish name. */
.ob-cnote__text {
	margin: 0 0 .35rem;
	font-family: var(--ob-sans); font-size: .8rem; line-height: 1.45; color: var(--ob-ink);
}
.ob-cnote__badge {
	display: inline-block; margin-right: .4rem;
	font-size: .62rem; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
	color: var(--ob-tan-ink);
}

.ob-cnote__edit { margin: 0; }
.ob-cnote__toggle {
	display: inline-flex; align-items: center; gap: .3rem;
	font-size: .76rem; color: var(--ob-copper); cursor: pointer;
	/* Both are needed to drop the disclosure triangle: Safari and older WebKit
	   only honour the pseudo-element, everything else only honours list-style. */
	list-style: none;
}
.ob-cnote__toggle::-webkit-details-marker { display: none; }
.ob-cnote__toggle:hover { color: var(--ob-walnut); }
.ob-cnote__toggle:focus-visible { outline: 2px solid var(--ob-copper); outline-offset: 2px; border-radius: 2px; }
.ob-cnote__toggle svg { width: 13px; height: 13px; flex: 0 0 auto; }

.ob-cnote__panel {
	display: flex; flex-direction: column; align-items: flex-start; gap: .45rem;
	max-width: 340px; margin-top: .5rem;
}
.woocommerce-cart button.ob-cnote__save {
	padding: .42rem .9rem; font-size: .78rem; border-radius: 3px;
}

@media (max-width: 560px) {
	.ob-cnote__panel { max-width: none; width: 100%; }
}

/* --- Cart actions bar (coupon + update cart) ---
   Framed bar so the controls read as one unit instead of floating in whitespace.
   NB: the .actions <td> must stay a table-cell (NOT display:flex) — flexing it inside
   this table-layout:fixed table collapses its width. Lay children out with floats. */
.woocommerce-cart .cart .actions {
	margin-top: 1.25rem; padding: 1rem 1.2rem;
	background: var(--ob-surface); border: 1px solid var(--ob-line); border-radius: 6px;
	overflow: hidden; /* contain the floated children */
}
/* Coupon = one attached control [ input | Apply ], pinned left */
.woocommerce-cart .cart .actions .coupon {
	float: left; display: flex; align-items: stretch; width: 440px; max-width: 100%; margin: 0;
}
/* Hide the "Coupon:" label — the placeholder already names the field */
.woocommerce-cart .cart .actions .coupon > label {
	position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
	overflow: hidden; clip: rect(0 0 0 0); border: 0;
}
.woocommerce-cart .cart .actions .coupon input#coupon_code {
	flex: 1 1 auto; min-width: 0; padding: .7rem .9rem; font: inherit;
	border: 1px solid var(--ob-line); border-right: 0; border-radius: 3px 0 0 3px;
	background: #fff; color: var(--ob-ink);
}
.woocommerce-cart .cart .actions .coupon input#coupon_code:focus { outline: none; border-color: var(--ob-tan); }
.woocommerce-cart .cart .actions .coupon button[name="apply_coupon"] {
	border-radius: 0 3px 3px 0 !important; white-space: nowrap; padding: .7rem 1.1rem;
}
/* Update cart pinned right; secondary weight so "Proceed to checkout" stays the hero */
.woocommerce-cart .cart .actions button[name="update_cart"] {
	float: right; white-space: nowrap; padding: .7rem 1.3rem;
}
/* Small screens: the coupon and the update button stack, each full width — see the
   phone-cart block at the end of this section. It is written at Woo's own 768px
   breakpoint rather than at a number of ours, for the reason set out there. */

/* ---------- Cart totals: the order summary panel ----------
   Rebuilt 2026-08-21. The old panel put the heading inside a 6px box and then gave
   the label column a fixed `width: 58%`, which left the value column 42% of 400px to
   hold the entire shipping CHOOSER — a radio, a wrapped Georgian label, a three-line
   destination paragraph and a two-line "calculate shipping" link, all under
   `text-align: right`. It read as broken because a form was being laid out by a
   right-aligned table cell.

   The chooser and the address calculator are gone from this page entirely (see
   woocommerce/cart/cart-totals.php for why), so what is left is what a summary
   actually is: label/value money rows. Which means this is now deliberately the SAME
   component as the checkout's order summary rather than a second design of it — the
   heading sits outside the card on a hairline, the card is --ob-surface at 8px, and the
   label typography is inherited from the shared `table.shop_table th` rule instead of
   being re-declared here. Compare .ob-co__aside / #order_review below; the two panels
   should stay in step. */
.cart-collaterals { display: flex; justify-content: flex-end; margin-top: 1.5rem; }
.cart-collaterals .cart_totals { width: 100%; max-width: 400px; }

/* Same declaration as .woocommerce-checkout h3 / #order_review_heading. */
.ob-sum__title {
	font-family: var(--ob-serif); font-size: 1.3rem; margin: 0 0 1.1rem;
	padding-bottom: .7rem; border-bottom: 1px solid rgba(var(--ob-tan-rgb), .34);
}
.ob-sum__card {
	background: var(--ob-surface);
	border: 1px solid rgba(var(--ob-tan-rgb), .34);
	border-radius: 8px;
	padding: clamp(1.1rem, 2.5vw, 1.5rem);
}
/* The card is the only frame — `.woocommerce-cart table.shop_table` styles every
   shop_table as a bordered card of its own. */
.woocommerce-cart .cart_totals table.ob-sum__table {
	margin: 0; border: 0; border-radius: 0; background: transparent; width: 100%;
}
/* The label column takes what it needs and the AMOUNT column absorbs the slack — the
   exact opposite of the old `width: 58%`, which is what starved the value column.
   `width: 1%` with nowrap is the shrink-to-fit idiom for a table cell. */
.woocommerce-cart .cart_totals table.ob-sum__table th {
	border: 0; padding: .55rem 0; width: 1%; white-space: nowrap;
	vertical-align: top; font-size: .78rem;
}
.woocommerce-cart .cart_totals table.ob-sum__table td {
	border: 0; padding: .55rem 0 .55rem 1rem; text-align: right; vertical-align: top;
}
/* The chosen method's own name, under the row label. Undoes the inherited uppercase
   eyebrow treatment: this is a proper noun, not a field label. */
.ob-sum__method {
	display: block; margin-top: .25rem;
	font-size: .82rem; font-weight: 400; line-height: 1.35;
	letter-spacing: 0; text-transform: none;
	color: var(--ob-ink); white-space: normal;
}
/* Spans both columns so it gets the full width of the card rather than the ~200px the
   amount column leaves — at 320px this sentence is wider than the panel. */
.woocommerce-cart .cart_totals tr.ob-sum__ship-note td {
	text-align: left; padding: 0 0 .55rem;
	font-size: .82rem; line-height: 1.4; color: var(--ob-ink-soft);
	font-variant-numeric: normal;
}
.ob-sum__free { font-weight: 600; }
.woocommerce-cart .cart_totals tr.order-total th,
.woocommerce-cart .cart_totals tr.order-total td {
	border-top: 1px solid rgba(var(--ob-tan-rgb), .45); padding-top: .9rem;
}
.woocommerce-cart .cart_totals tr.order-total .amount { font-size: 1.25rem; }
.wc-proceed-to-checkout { margin-top: 1.2rem; }
.wc-proceed-to-checkout a.checkout-button { display: block; text-align: center; width: 100%; font-size: 1rem; }

/* ---------- The cart on a phone, at WooCommerce's own breakpoint ----------
   Woo enqueues woocommerce-smallscreen.css with `media="only screen and (max-width:
   768px)"`, and that stylesheet re-lays the cart out by itself: thead hidden, every `tr`
   and `td` display:block, `text-align: right !important`, each `data-title` floated in
   front of its value as a bold label, zebra striping on the cells, the product PHOTO
   display:none, and `width: 48%` on both the coupon input and its button.

   Everything above describes the DESKTOP table — `table-layout: fixed` with
   44/84/92/110/100px columns and 1rem cell padding — and it was never turned off, so on
   a phone both designs applied at once and what shipped was neither. Measured at 320px:
   stacked full-width rows whose cells were still pinned to their desktop pixel widths (a
   92px price cell holding a floated label and a right-aligned amount on separate lines,
   the quantity cell overflowing by 5px and the subtotal by 8), 360px of height per dish,
   no photograph, and კუპონის გამოყენება — 177px of Georgian — inside a 114px
   button with 63px of the label cropped away.

   So from here down the cart is ours: one card per line item, laid out as a grid — photo
   left, name and remove on the first line, unit price under the name, quantity and line
   total on a footer row. The fixed-row idea from `.ob-pcard`, in the shape people already
   know from the delivery apps this site is measured against.

   768px is not a choice, it is Woo's number. Any other value leaves a band of widths
   where half of each design applies, which is the bug this block exists to end. */
@media (max-width: 768px) {
	/* The table stops being a table. The frame moves to the rows, so the table's own
	   border, background and radius would draw a second box around the lot. */
	.woocommerce-cart table.cart,
	.woocommerce-cart table.cart tbody { display: block; width: 100%; }
	.woocommerce-cart table.cart {
		border: 0; border-radius: 0; overflow: visible; background: none; margin-bottom: 1.2rem;
	}
	.woocommerce-cart table.cart thead { display: none; }

	/* TWO columns, photo and everything else — deliberately not three.
	   A third `auto` column for the remove x plus the line total is sized by the widest
	   thing in it, and at 320px that total ("ჯამი 49.00 ₾", 102px) left the dish NAME
	   71px to wrap in, 11px of which overflowed the cell: the name, the most important
	   text on the screen, came out narrower than the price beside it. So the remove x is
	   taken out of flow into the corner it belongs in, and the two amounts share the
	   footer row by alignment instead of by columns. */
	.woocommerce-cart table.cart tr.cart_item {
		position: relative;
		display: grid;
		grid-template-columns: 56px minmax(0, 1fr);
		column-gap: .8rem;
		row-gap: .45rem;
		align-items: center;
		margin: 0 0 .7rem;
		padding: .8rem .9rem;
		background: var(--ob-surface);
		border: 1px solid var(--ob-line);
		border-radius: 8px;
	}
	/* Woo stripes alternate rows by colouring the CELLS, which here is the inside of the
	   card — it read as one of the dishes being selected. */
	.woocommerce-cart table.cart tr:nth-child(2n) td { background: none; }

	/* Cells: shed the desktop widths, the cell padding, the hairlines and Woo's forced
	   right-alignment (that one is `!important` in their sheet, so ours has to be too).
	   Scoped to `tr.cart_item td` so the actions bar below keeps its own layout. */
	.woocommerce-cart table.cart tr.cart_item td {
		display: block; width: auto; max-width: none; padding: 0; border: 0;
		text-align: left !important; vertical-align: baseline;
	}
	/* Placed by line, not by name: the two footer cells deliberately occupy the SAME
	   grid area and separate by alignment, which a named-areas template cannot say. */
	/* `align-self: start`, not the row's centring: open the kitchen-note editor and the
	   name cell grows to ~150px, which left the photograph floating in the middle of the
	   card beside it. Top-aligned it stays level with the first line of the dish name in
	   both states. */
	.woocommerce-cart table.cart tr.cart_item td.product-thumbnail {
		grid-row: 1 / 3; grid-column: 1; align-self: start;
	}
	.woocommerce-cart table.cart tr.cart_item td.product-name { grid-row: 1; grid-column: 2; }
	.woocommerce-cart table.cart tr.cart_item td.product-price { grid-row: 2; grid-column: 2; }
	.woocommerce-cart table.cart tr.cart_item td.product-quantity {
		grid-row: 3; grid-column: 1 / 3; justify-self: start;
	}
	.woocommerce-cart table.cart tr.cart_item td.product-subtotal {
		grid-row: 3; grid-column: 1 / 3; justify-self: end;
		text-align: right !important; white-space: nowrap;
	}

	/* The photograph comes back. Woo hides it at (0,3,1) and this is (0,3,3): a list of
	   pastry names was the one screen on the site with no picture on it. */
	.woocommerce-cart table.cart tr.cart_item td.product-thumbnail { display: block; }
	.woocommerce-cart table.cart td.product-thumbnail a { display: block; }

	/* The x, in the corner. Out of flow, so it costs the name no width; the name cell is
	   padded to keep its text from running under it, and the note field below then takes
	   that padding back — a 38px-narrower textarea is 38px the note needs more. Its 40px
	   box comes from the touch-target block, which owns that for both cart layouts. */
	.woocommerce-cart table.cart tr.cart_item td.product-remove {
		position: absolute; top: .3rem; right: .3rem;
	}
	/* `tr.cart_item td` and not `td.product-name`: the reset above is (0,3,3) and sets
	   `padding: 0`, so a (0,3,2) selector here loses the padding no matter that it comes
	   later — which is exactly what happened, and the note then bled 24px past the card
	   and 5px past the 320px viewport. */
	.woocommerce-cart table.cart tr.cart_item td.product-name {
		padding-right: 2.4rem; font-size: .98rem; line-height: 1.3;
	}
	.woocommerce-cart table.cart tr.cart_item td.product-name .ob-cnote { margin-right: -2.4rem; }
	/* Full width, both of them: `შენიშნის შენახვა` is 125px of label, which is
	   wider than the button's own content box gets in a 320px card. */
	.woocommerce-cart button.ob-cnote__save { width: 100%; min-height: var(--ob-touch); }

	/* Woo's `data-title` labels are KEPT on the two amounts — "49.00 ₾" above "49.00 ₾"
	   with nothing to say which is the unit price and which the line total is the "weird"
	   half of the report — but as a quiet eyebrow instead of a bold floated word. Dropped
	   on the name, the quantity and the photo, all of which name themselves. */
	.woocommerce-cart table.cart tr.cart_item td::before {
		float: none; display: inline; font-weight: 400;
		font-size: var(--ob-eyebrow-tight); letter-spacing: .1em; text-transform: uppercase;
		color: var(--ob-tan-ink); margin-right: .3rem;
	}
	/* The remove cell is in this list because our own `display: inline` above brought
	   Woo's label BACK: they hide `td.product-remove::before` at (0,3,2), which the rule
	   above out-specifies at (0,3,3) — and `td.product-remove` carries no `data-title`,
	   so what returned was a bare ": " floating over the x. */
	.woocommerce-cart table.cart tr.cart_item td.product-name::before,
	.woocommerce-cart table.cart tr.cart_item td.product-quantity::before,
	.woocommerce-cart table.cart tr.cart_item td.product-remove::before,
	.woocommerce-cart table.cart tr.cart_item td.product-thumbnail::before { display: none; }
	.woocommerce-cart table.cart td.product-price { font-size: .84rem; color: var(--ob-ink-soft); }
	.woocommerce-cart table.cart td.product-subtotal { font-size: 1rem; }

	/* --- The actions bar: coupon over update, each full width ---
	   Woo puts `width: 48%` on the input AND the button at (0,5,2), which an equally
	   specific selector of ours cannot outrank on source order alone — hence
	   `!important`, as elsewhere in this file where Woo's own sheet has to be beaten
	   rather than out-specified. */
	.woocommerce-cart .cart .actions { padding: .9rem 1rem; }
	.woocommerce-cart table.cart .actions .coupon {
		float: none; display: grid; gap: .5rem; width: 100%; margin: 0 0 .6rem;
	}
	.woocommerce-cart table.cart .actions .coupon input#coupon_code,
	.woocommerce-cart table.cart .actions .coupon button[name="apply_coupon"] {
		width: 100% !important; float: none;
	}
	/* Stacked, the two are no longer one attached control: the input gets its right
	   border and both of its corners back. */
	.woocommerce-cart table.cart .actions .coupon input#coupon_code {
		border-right: 1px solid var(--ob-line); border-radius: 3px;
	}
	.woocommerce-cart table.cart .actions .coupon button[name="apply_coupon"] {
		border-radius: 3px !important;
	}
	.woocommerce-cart table.cart .actions button[name="update_cart"] {
		float: none; display: block; width: 100%;
	}
	/* .75rem of padding on a .9rem label comes to 39px — one under --ob-touch. */
	.woocommerce-cart table.cart .actions .button { min-height: var(--ob-touch); }

	/* Totals card: full width. The label column is not the fix here — the totals table
	   also carries `shop_table_responsive`, so Woo has hidden every `<th>` and moved the
	   label into the value cell's `::before` as a bold float. With no margin on that
	   float the shipping row read as "მიტანის ხერხი:აიღეთ ადგილზე", the two
	   running together, because that is the one row whose value is long enough to wrap
	   back alongside its own label. Same eyebrow treatment as the line-item labels above,
	   so the two halves of the page agree. */
	.cart-collaterals .cart_totals { max-width: none; }
	/* ✅ The `td::before` label float and the zebra-stripe reset that used to live here
	   are GONE, and so is the bug they were patching. Both existed only because the
	   totals table carried `shop_table_responsive`, which is the single class Woo's
	   smallscreen stylesheet keys its whole below-768px re-layout on. The rebuilt
	   template does not use that class, so nothing hides the `<th>`, nothing floats a
	   `data-title` in front of the value, and nothing bands alternate rows — the panel
	   is the same two-column list at every width. Do not re-add the class. */
}

/* ---------- Checkout ----------
   Two columns on desktop: fields left, a STICKY order summary right, so the
   total and the place-order button stay in view instead of sitting ten fields
   below the fold. Wrappers come from woocommerce/checkout/form-checkout.php. */
.woocommerce-checkout form.checkout.ob-co {
	display: grid;
	grid-template-columns: minmax(0, 1.3fr) minmax(0, .92fr);
	gap: clamp(1.5rem, 3vw, 2.75rem);
	align-items: start;
	max-width: 1040px;
	margin-inline: auto;
}
.ob-co__main { min-width: 0; }
.ob-co__aside { min-width: 0; position: sticky; top: 5.5rem; }

/* Notices are injected as a DIRECT CHILD of form.checkout — checkout.js does
   `$('form.checkout').prepend(...)` on a failed submit. This form is a two-column
   grid whose template emits exactly the two panels above, so an injected notice
   became a THIRD grid item: it claimed row 1 / column 1, shoved the fields panel
   into column 2 at half width (error text wrapping three lines deep) and dropped the
   order summary to row 2. That is the broken checkout.
   Written as "anything that is not one of our two panels" rather than as a list of
   Woo's notice classes, so it also covers whatever a payment gateway prepends when
   Flitt lands. The grid `gap` supplies the spacing, hence margin-bottom: 0. */
.woocommerce-checkout form.checkout.ob-co > :not(.ob-co__main):not(.ob-co__aside) {
	grid-column: 1 / -1;
	margin-bottom: 0;
}

/* Woo's own float grid inside the fields column — flatten it. */
.woocommerce-checkout #customer_details .col2-set { display: block; }
.woocommerce-checkout #customer_details .col-1,
.woocommerce-checkout #customer_details .col-2 { width: 100%; float: none; margin: 0; }
.woocommerce-checkout #customer_details .col-2:not(:empty) { margin-top: 1.8rem; }

.woocommerce-checkout h3,
.woocommerce-checkout #order_review_heading {
	font-family: var(--ob-serif); font-size: 1.3rem; margin: 0 0 1.1rem;
	padding-bottom: .7rem; border-bottom: 1px solid rgba(var(--ob-tan-rgb), .34);
}

/* Fields panel. One card for the whole left column: the customer details and the
   order-notes textarea used to be two bordered boxes, which stopped making sense
   once the field cull left the second one holding a single optional field. */
.ob-co__panel {
	background: var(--ob-surface);
	border: 1px solid rgba(var(--ob-tan-rgb), .34);
	border-radius: 8px;
	padding: clamp(1.1rem, 2.5vw, 1.6rem);
}
.ob-co__panel .woocommerce-billing-fields h3 { margin-top: 0; }
/* The notes field is now a row of the same form, not a section of its own. */
.ob-co__panel .woocommerce-additional-fields__field-wrapper { margin-top: .4rem; }

/* Name / phone side by side; everything else full width. */
.woocommerce-checkout .woocommerce-billing-fields__field-wrapper { display: grid; grid-template-columns: 1fr 1fr; gap: 0 1rem; }
.woocommerce-checkout .woocommerce-billing-fields__field-wrapper > p.form-row { grid-column: 1 / -1; }
.woocommerce-checkout .woocommerce-billing-fields__field-wrapper > p.form-row-first { grid-column: 1; }
.woocommerce-checkout .woocommerce-billing-fields__field-wrapper > p.form-row-last { grid-column: 2; }
/* Woo sets width:47% on these; inside a grid track that shrank them to ~165px
   next to full-width siblings, which read as a broken form. */
.woocommerce form .form-row.form-row-first,
.woocommerce form .form-row.form-row-last,
.woocommerce form .form-row.form-row-wide { width: 100%; float: none; }

/* The country row is carried, not asked for — see ob_checkout_only_georgia().
   It is a one-option select that exists solely so the order, the address format
   and the courier handoff still have a country on them.

   The `.ob-co__carried` selector is what covers the ADDRESS BOOK (My Account →
   Addresses → Edit). ob-core has been marking the row with that class since 0.9.1
   and nothing ever styled it, so the class was a comment: the two `#…_country_field`
   rules below it are scoped to `.woocommerce-checkout` and the account page is not
   that, which is why a one-option "Country / Region" select sat at the top of the
   edit-address form. The ID rules are kept alongside rather than replaced — a
   visible country select on the checkout was a real bug once, and an id beats
   anything a stylesheet order accident could do to a class. */
.woocommerce form .form-row.ob-co__carried,
.woocommerce-checkout p#billing_country_field,
.woocommerce-checkout p#shipping_country_field { display: none; }

/* Below the two-column breakpoint the grid collapses, so the name/phone pair
   stacks like everything else. */
@media (max-width: 559px) {
	.woocommerce-checkout .woocommerce-billing-fields__field-wrapper { grid-template-columns: 1fr; }
	.woocommerce-checkout .woocommerce-billing-fields__field-wrapper > p.form-row-first,
	.woocommerce-checkout .woocommerce-billing-fields__field-wrapper > p.form-row-last { grid-column: 1; }
}

/* Order summary card */
.woocommerce-checkout #order_review {
	border: 1px solid rgba(var(--ob-tan-rgb), .34); border-radius: 8px;
	padding: clamp(1.1rem, 2.5vw, 1.5rem); background: var(--ob-surface);
}
.woocommerce-checkout #order_review table.shop_table { border: 0; margin: 0 0 1.2rem; background: transparent; }
.woocommerce-checkout #order_review table.shop_table td,
.woocommerce-checkout #order_review table.shop_table th { padding-left: 0; padding-right: 0; }
.woocommerce-checkout #order_review table.shop_table thead th { padding-top: 0; }
.woocommerce-checkout #order_review td.product-name { font-size: .95rem; line-height: 1.4; }
.woocommerce-checkout #order_review .product-quantity { color: var(--ob-ink-soft); font-weight: 400; }
/* The price shares the name's first line, so it has to share its type metrics too —
   inheriting body size left the two line boxes a pixel out of step even once both
   cells aligned to the top. Scoped to cart rows: the totals below are deliberately
   larger. */
.woocommerce-checkout #order_review tr.cart_item td.product-total {
	font-size: .95rem;
	line-height: 1.4;
}
/* The amount column is the LAST cell of every row, whatever element it happens to be.
   This was `td.product-total, td[data-title]`, and the `[data-title]` half matched
   nothing here: review-order.php emits the subtotal and total rows as a bare <td> with
   neither class nor data-title (that attribute only exists on the cart page's
   responsive table). So those two amounts — including the order total — stayed
   left-aligned in a column of right-aligned product totals, as did the "ჯამი" heading
   above them. Selecting by position covers all three and cannot drift when Woo
   changes a class. */
.woocommerce-checkout #order_review table.shop_table tr > :last-child {
	text-align: right;
	white-space: nowrap;
}
/* Top, not the default middle. A product name long enough to wrap (the summary column
   is ~280px, and the real dish names run to "ლისტი ხორციანი ღვეზელი(20 ნაჭრიანი)")
   made the row 71px tall, and a vertically-centred price then hung ~10px below the
   name's first line — reading as detached from the item it belongs to. */
.woocommerce-checkout #order_review table.shop_table td,
.woocommerce-checkout #order_review table.shop_table th { vertical-align: top; }
.woocommerce-checkout #order_review tr.cart-subtotal th,
.woocommerce-checkout #order_review tr.order-total th { font-size: .78rem; }
.woocommerce-checkout #order_review tr.order-total th,
.woocommerce-checkout #order_review tr.order-total td {
	border-top: 1px solid rgba(var(--ob-tan-rgb), .45); padding-top: .9rem;
}
.woocommerce-checkout #order_review tr.order-total .amount { font-size: 1.25rem; }

/* ---- Shipping choice: takeout vs courier delivery ----
   New in theme 0.9.14. Nothing here existed before, for a blunt reason: the site had
   no shipping methods at all, so WooCommerce's shipping list had never once rendered
   on this theme and inherited plain <ul> bullets sitting in the order summary.

   Deliberately compact and familiar rather than decorated — radio + label + price,
   the way every delivery app presents the same choice. */
#shipping_method {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: .55rem;
}
#shipping_method li {
	margin: 0;
	padding: 0;
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: .45rem;
	text-align: left;
}
#shipping_method li input.shipping_method { margin: 0; flex: 0 0 auto; }
#shipping_method li label {
	margin: 0;
	flex: 1 1 auto;
	/* The amount is a child of the label in Woo's markup, so the label carries both
	   the name and the price and is what has to space them apart. */
	display: flex;
	justify-content: space-between;
	align-items: baseline;
	gap: .6rem;
	font-size: .92rem;
	line-height: 1.35;
	color: var(--ob-ink);
	cursor: pointer;
	/* Overrides the uppercase eyebrow treatment that .form-row label sets for the
	   text fields — a shipping choice is a sentence, not a field label. */
	letter-spacing: 0;
	text-transform: none;
	font-weight: 400;
}
#shipping_method li label .woocommerce-Price-amount {
	font-weight: 600;
	white-space: nowrap;
	font-variant-numeric: tabular-nums;
}

.woocommerce-shipping-totals th { font-size: .78rem; }

/* Undo the inherited nowrap for this one row.
   `#order_review table.shop_table tr > :last-child` sets white-space:nowrap so that
   an AMOUNT never breaks across lines — correct for every other row, because every
   other row's last cell holds nothing but a price. The shipping row's last cell holds
   the entire method chooser, and inheriting nowrap meant the collection address, the
   courier ETA and QuickShipper's own button copy were all unbreakable single lines.

   Measured on a 390px viewport before the fix: the widget laid out 365.8px wide
   inside a 354.8px column and dragged the layout viewport out to 478px. The price
   spans keep their own nowrap above, so amounts are still safe.

   The selector has to out-specify `... table.shop_table tr > :last-child`, and
   `:last-child` counts as a class — so matching that rule's specificity needs
   `.shop_table` and `:last-child` named here too, not just the row class. A shorter
   selector was written first and lost silently. */
.woocommerce-checkout #order_review table.shop_table tr.woocommerce-shipping-totals > td:last-child {
	white-space: normal;
}
/* min-width:0 so these flex/grid children may actually shrink below their content's
   intrinsic width instead of forcing the column open. */
.ob-ship__note,
.ob-ship__widget { min-width: 0; }
.ob-ship__widget > button,
.ob-ship__widget .buttonContainer {
	width: 100% !important;
	max-width: 100% !important;
	min-width: 0 !important;
	box-sizing: border-box;
}
/* Their header is a two-item flex row (title + a 160px powered-by image) with no
   wrapping, which is the narrowest point of the whole control. */
.ob-ship__widget .quickshipper-delivery-header {
	flex-wrap: wrap;
	gap: .25rem .5rem;
	width: 100% !important;
	max-width: 100% !important;
}

/* The detail hanging under a method: the collection address, or the chosen delivery
   address and the widget that sets it. --ob-tan-ink, never --ob-tan: this is small
   text on a light ground, where --ob-tan measures 4.05:1 and fails AA. */
.ob-ship__note {
	flex: 1 1 100%;
	display: flex;
	flex-direction: column;
	gap: .15rem;
	margin: 0 0 .15rem;
	font-size: .8rem;
	line-height: 1.45;
	color: var(--ob-tan-ink);
}
.ob-ship__addr { font-weight: 600; }
.ob-ship__eta,
.ob-ship__hours { font-variant-numeric: tabular-nums; }
.ob-ship__msg { color: var(--ob-ink-soft); }
.ob-ship__msg.is-error { color: var(--ob-err); font-weight: 600; }

/* The address control is only meaningful once courier delivery is the chosen method,
   so it stays collapsed until delivery.js marks it active. `display` rather than
   opacity: an invisible-but-present widget button is still a tab stop. */
.ob-ship__note--delivery { display: none; }
.ob-ship__note--delivery.is-active { display: flex; }

/* QuickShipper's widget ships its own stylesheet and its own markup, neither of which
   we own — and its stylesheet loads AFTER this file, so the handful of properties we
   have to win are marked !important. That is not laziness: measured, our `border` on
   .buttonContainer applied while our `background` and `border-radius` on the same rule
   both lost to theirs, which is the signature of a later sheet at equal specificity.

   What is being corrected, all measured rather than eyeballed:
     - The vendor button is a GRADIENT BORDER — padding:2px over
       linear-gradient(45deg, rgb(199,50,111), rgb(133,41,168)) — which drew a
       crimson-to-purple ring (sampled at rgb(194,50,116)) around a walnut-and-copper
       checkout. This site has no decorative gradients anywhere by design.
     - Their #f7f7f7 fill is the one cold grey on the page.
     - Their section heading is rgb(121,121,121), off-palette grey. */
.ob-ship__widget { margin-top: .35rem; max-width: 100%; }
.ob-ship__widget * { font-family: var(--ob-sans) !important; }
.ob-ship__widget > button {
	/* Kills the gradient ring and the 2px of padding that made it visible. */
	background-image: none !important;
	background-color: transparent !important;
	padding: 0 !important;
	border: 0 !important;
	width: 100%;
	cursor: pointer;
}
.ob-ship__widget .buttonContainer {
	border-radius: 3px !important;
	border: 1px solid rgba(var(--ob-tan-rgb), .55) !important;
	background: var(--ob-surface-2) !important;
	transition: border-color var(--ob-dur-2) var(--ob-ease),
	            background var(--ob-dur-2) var(--ob-ease);
}
/* Copper on hover, so the control behaves like every other actionable thing here. */
.ob-ship__widget > button:hover .buttonContainer {
	border-color: var(--ob-copper) !important;
	background: var(--ob-surface) !important;
}
.ob-ship__widget .buttonContainer h6 { color: var(--ob-ink) !important; }
.ob-ship__widget .buttonContainer p { color: var(--ob-ink-soft) !important; }
/* Their own "Address Details" heading, matched to the site's eyebrow treatment. */
.ob-ship__widget .quickshipper-delivery-header h6 {
	color: var(--ob-tan-ink) !important;
	font-size: .78rem !important;
	letter-spacing: .04em;
	text-transform: uppercase;
}
/* The powered-by mark is a magenta SVG we cannot recolour, and it is an attribution
   we should not remove — so it is desaturated to a quiet grey instead of shouting a
   second brand's pink from the middle of the order summary. */
.ob-ship__widget .quickshipper-delivery-header img {
	filter: grayscale(1);
	opacity: .55;
}

/* A free method prints no amount at all in WooCommerce, which left the pickup row
   looking like its price had failed to load next to a delivery row showing one. */
.ob-ship__free { font-weight: 600; }

/* On a phone the summary's label column is ~100px of a ~215px cell, so the chooser
   was building "კურიერით მიტანა — Wolt:" and "9.90 ₾" on separate lines inside a
   third of the screen. Stacking the row's heading above its content hands the whole
   width to the options. Scoped to this ONE row so the product and totals rows keep
   their two-column alignment. */
@media (max-width: 600px) {
	/* The ROW has to become a block as well. Setting display:block on the cells alone
	   leaves them children of a table-row, so the browser wraps them back up in an
	   anonymous table cell and the column width is still imposed: measured, the widget
	   went from 215px to only 252px of an available 320px. */
	.woocommerce-checkout #order_review tr.woocommerce-shipping-totals { display: block; }
	.woocommerce-checkout #order_review tr.woocommerce-shipping-totals > th,
	.woocommerce-checkout #order_review tr.woocommerce-shipping-totals > td {
		display: block;
		width: 100%;
		text-align: left;
	}
	.woocommerce-checkout #order_review tr.woocommerce-shipping-totals > th {
		padding-bottom: .35rem;
	}
}

/* Form fields — one control style for text inputs, textareas, native selects
   AND select2 (the country field is select2-enhanced, and its own stylesheet was
   giving it a grey 28px-tall box that matched nothing else on the page). */
.woocommerce form .form-row { display: flex; flex-direction: column; gap: .35rem; margin: 0 0 1rem; padding: 0; }
.woocommerce form .form-row label {
	font-size: .78rem; letter-spacing: .04em; text-transform: uppercase;
	font-weight: 600; color: var(--ob-ink-soft);
}
.woocommerce form .form-row .required { color: var(--ob-copper); border: 0; text-decoration: none; }
.woocommerce form .form-row input.input-text,
.woocommerce form .form-row textarea,
.woocommerce form .form-row select,
.woocommerce .select2-container--default .select2-selection--single {
	font: inherit; width: 100%; box-sizing: border-box;
	min-height: 2.9rem; padding: .62rem .8rem;
	border: 1px solid var(--ob-line); border-radius: 4px;
	background: var(--ob-surface); color: var(--ob-ink);
}
.woocommerce form .form-row textarea { min-height: 6rem; resize: vertical; }
/* Placeholder carries real content here (the address lines are placeholder-only),
   so it has to clear AA as text. opacity .9 is the floor: .65 measured 2.12:1 and
   .85 still misses on the page ground. */
.woocommerce form .form-row input.input-text::placeholder,
.woocommerce form .form-row textarea::placeholder { color: var(--ob-ink-soft); opacity: .9; }

/* select2 shell: the container is only a positioning box — the visible control is
   .select2-selection--single, styled with the inputs above. */
.woocommerce .select2-container { width: 100% !important; border: 0; padding: 0; background: none; }
.woocommerce .select2-container--default .select2-selection--single { display: flex; align-items: center; height: auto; }
.woocommerce .select2-container--default .select2-selection--single .select2-selection__rendered {
	padding: 0; line-height: 1.5; color: var(--ob-ink);
}
.woocommerce .select2-container--default .select2-selection--single .select2-selection__arrow {
	height: 100%; top: 0; right: .55rem;
}
.woocommerce .select2-container--default .select2-selection--single .select2-selection__arrow b { border-top-color: var(--ob-ink-soft); }
.select2-dropdown {
	border-color: var(--ob-tan); border-radius: 4px; background: var(--ob-surface);
	font-family: var(--ob-sans);
}
.select2-container--default .select2-results__option--highlighted[aria-selected] { background: var(--ob-copper); color: #fff; }
.select2-search--dropdown .select2-search__field { border: 1px solid var(--ob-line); border-radius: 3px; padding: .45rem .55rem; }

.woocommerce form .form-row input.input-text:focus,
.woocommerce form .form-row textarea:focus,
.woocommerce form .form-row select:focus,
.woocommerce .select2-container--open .select2-selection--single {
	outline: 2px solid var(--ob-tan-2); outline-offset: 1px; border-color: var(--ob-tan);
}
/* Woo marks invalid fields with a red border; keep it in the palette. */
.woocommerce form .form-row.woocommerce-invalid input.input-text,
.woocommerce form .form-row.woocommerce-invalid select,
.woocommerce form .form-row.woocommerce-invalid .select2-selection--single { border-color: var(--ob-err); }
/* The country dropdown needs Woo's OWN selector shape, mirrored exactly. Woo styles
   it as `.woocommerce form .form-row.woocommerce-{state} .select2-container:not(
   .select2-container--open) .select2-selection` — six classes plus a type, which
   outranks the `.select2-selection--single` line above (four plus a type). So that
   line never actually reached the country field in either state; it only ever won on
   plain <select> elements. Matching the specificity and relying on source order is
   what makes it apply, without resorting to !important. */
.woocommerce form .form-row.woocommerce-invalid .select2-container:not(.select2-container--open) .select2-selection {
	border-color: var(--ob-err);
}
.woocommerce form .form-row.woocommerce-validated .select2-container:not(.select2-container--open) .select2-selection {
	border-color: var(--ob-line);
}

/* Coupon toggle — a quiet line, not a full-width info banner. */
.woocommerce-form-coupon-toggle { max-width: 1040px; margin-inline: auto; }
.woocommerce-form-coupon-toggle .woocommerce-info {
	display: block; background: none; border: 0; border-radius: 0;
	padding: 0; margin: 0 0 1.4rem; font-size: .9rem; color: var(--ob-ink-soft);
}
.woocommerce-form-coupon-toggle .woocommerce-info a { color: var(--ob-copper); }
form.checkout_coupon {
	max-width: 1040px; margin: 0 auto 1.6rem; padding: 1.1rem;
	background: var(--ob-surface); border: 1px solid rgba(var(--ob-tan-rgb), .34); border-radius: 8px;
}
form.checkout_coupon .form-row { margin: 0; }

/* Payment */
.woocommerce-checkout #payment { background: none; border: 0; border-radius: 0; padding: 0; }
.woocommerce-checkout #payment ul.payment_methods {
	list-style: none; margin: 0 0 1rem; padding: 0;
	border: 0; border-top: 1px solid rgba(var(--ob-tan-rgb), .34); padding-top: 1.1rem;
}
.woocommerce-checkout #payment ul.payment_methods li { margin: 0 0 .6rem; }
.woocommerce-checkout #payment ul.payment_methods li:last-child { margin-bottom: 0; }
/* "No payment methods available" until the Flitt gateway lands (Phase 3) — a
   quiet note here, not an alarming banner inside the summary card. */
.woocommerce-checkout #payment ul.payment_methods li.woocommerce-notice,
.woocommerce-checkout #payment .woocommerce-info {
	display: block; background: none; border: 0; border-left: 0;
	padding: 0; margin: 0; font-size: .86rem; line-height: 1.5; color: var(--ob-ink-soft);
}
.woocommerce-checkout #payment div.payment_box {
	background: var(--ob-surface-2); border-radius: 4px; padding: .8rem 1rem;
	font-size: .88rem; color: var(--ob-ink-soft); margin: .6rem 0 0;
}

/* Cash on handover — how much the shopper is bringing, and what we owe them back.
   Lives inside the payment box, which WooCommerce reveals only while cash is the
   selected method, so none of this needs its own show/hide. Markup and wording:
   ob_cash_render_field() in ob-core/includes/class-payments.php. */
.woocommerce-checkout #payment div.payment_box .ob-cash__intro { margin: 0 0 .75rem; }
.woocommerce-checkout #payment div.payment_box .ob-cash__row { margin: 0; padding: 0; }
.ob-cash__row > label { display: block; margin-bottom: .35rem; color: var(--ob-ink); font-size: .88rem; }
.ob-cash__input { position: relative; display: block; }
/* Room on the right for the currency sign, which sits over the field rather than
   next to it so the input can still be full width on a phone.
   This needs the THEME's own selector shape, not a shorter one: the input padding is
   set at .woocommerce form .form-row input.input-text (three classes and an element),
   which outranks `.ob-cash__input .input-text` and quietly kept the padding at .8rem
   with the currency sign sitting over where a long amount would be typed. Measured
   before the fix: computed padding-right 12.8px, not 38.4px. */
.woocommerce form .form-row.ob-cash__row input.input-text {
	width: 100%; padding-right: 2.4rem; text-align: left;
}
.ob-cash__currency {
	position: absolute; right: .8rem; top: 50%; transform: translateY(-50%);
	color: var(--ob-ink-soft); font-size: .95rem; pointer-events: none;
}
/* min-height, not a conditional margin: the line is empty until something is typed,
   and reserving its row stops the place-order button jumping down a line the moment
   it appears. */
.ob-cash__change {
	display: block; min-height: 1.2rem; margin-top: .45rem;
	font-size: .84rem; line-height: 1.2rem; color: var(--ob-ink-soft);
}
.ob-cash__change--error { color: var(--ob-err); }
.woocommerce-checkout #payment .place-order { padding-top: 1.1rem; margin-top: 1.1rem; border-top: 1px solid rgba(var(--ob-tan-rgb), .34); }
.woocommerce-checkout #place_order { width: 100%; font-size: 1rem; padding-block: .85rem; }
.woocommerce-checkout .woocommerce-terms-and-conditions-wrapper { margin-bottom: .9rem; font-size: .84rem; color: var(--ob-ink-soft); }

/* One column below the two-column threshold; the summary follows the fields, which
   is also the order the place-order button needs to be in. */
@media (max-width: 900px) {
	.woocommerce-checkout form.checkout.ob-co { grid-template-columns: 1fr; }
	.ob-co__aside { position: static; }
	.woocommerce-checkout #order_review_heading { margin-top: 1.8rem; }
}

/* ---------- Footer ----------
   Four columns: brand, navigation, address, hours — over a thin copyright bar.
   Markup and the data it reads: footer.php. */
.site-footer {
	background: var(--ob-walnut-deep);
	color: var(--ob-cream-soft);
	border-top: 1px solid rgba(var(--ob-tan-rgb), .3);
	font-size: .86rem;
}
.site-footer__inner {
	max-width: var(--ob-max);
	margin-inline: auto;
	padding: clamp(2.2rem, 5vw, 3.2rem) var(--ob-gap) clamp(1.8rem, 4vw, 2.6rem);
	display: grid;
	/* The brand column carries the logo + tagline, so it gets the wider track. */
	grid-template-columns: 1.5fr 1fr 1.2fr 1fr;
	gap: clamp(1.6rem, 3.5vw, 2.8rem);
	align-items: start;
}
.site-footer a { color: var(--ob-cream-soft); text-decoration: none; }
.site-footer a:hover { color: var(--ob-tan-2); }

/* Column headings — the same uppercase eyebrow device as the rest of the site,
   in tan-2 because tan proper is too dark to sit on walnut-deep. */
.ob-foot__h { color: var(--ob-tan-2); font-size: var(--ob-eyebrow); margin: 0 0 1rem; }

/* Brand column */
.ob-foot__logo-link { display: inline-flex; align-items: center; gap: .65rem; color: var(--ob-cream); }
.ob-foot__logo-link:hover { color: var(--ob-tan-2); }
.ob-foot__logo { width: 46px; height: 46px; display: block; flex: none; }
.ob-foot__tag { margin: .9rem 0 0; max-width: 30ch; color: var(--ob-cream-soft); }
.ob-foot__social { display: flex; gap: .5rem; flex-wrap: wrap; margin-top: 1.2rem; }
.ob-foot__social a {
	display: inline-flex; align-items: center; gap: .45rem;
	font-size: .8rem; padding: .4rem .85rem;
	border: 1px solid rgba(var(--ob-tan-rgb), .45); border-radius: 999px;
	color: var(--ob-tan-2);
}
.ob-foot__social a:hover { background: rgba(var(--ob-tan-rgb), .14); color: var(--ob-cream); }
.ob-foot__social svg { width: 16px; height: 16px; flex: none; }

/* Link + text columns */
.site-footer ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .55rem; }
.ob-foot__line { margin: 0 0 .5rem; line-height: 1.6; }
.ob-foot__line:last-child { margin-bottom: 0; }
.ob-foot__line a { border-bottom: 1px solid rgba(var(--ob-tan-rgb), .4); }
.ob-foot__cta { margin-top: 1.1rem; font-size: .82rem; padding: .55rem 1.1rem; }

/* ---------- Payment marks ---------- */
/* A slim row between the four columns and the copyright bar. It is deliberately
   NOT inside that bar: the bar is a two-child space-between layout whose wrap
   behaviour is measured to 860px below, and a third sibling re-opens that bug.

   The divider is lighter than the bar's own (.10 against .18) on purpose, so the
   footer reads as content — payments — legal rather than as three equal slabs. */
.ob-foot__pay { border-top: 1px solid rgba(var(--ob-tan-rgb), .10); }
.ob-foot__pay-inner {
	max-width: var(--ob-max); margin-inline: auto;
	padding: .85rem var(--ob-gap);
	display: flex; align-items: center; gap: .75rem; flex-wrap: wrap;
}
/* .ob-foot__h's 1rem bottom margin is for a COLUMN heading with a list under it.
   This one sits beside its list, so the margin goes and the label is nudged up
   by a hair's letter-spacing overhang instead. */
.ob-foot__pay-h { color: var(--ob-tan-2); margin: 0; }
/* `.site-footer ul` is a column with a .55rem gap — the navigation column's
   shape. This list is the one horizontal list in the footer, so both of those
   have to be overridden or the four cards stack vertically.

   ⚠️ The `.site-footer` prefix is load-bearing, not tidiness: `.site-footer ul`
   scores (0,1,1) and a lone `.ob-foot__pay-list` scores (0,1,0), so the bare
   class LOSES and the cards stack in a 36px column. Measured, not guessed —
   the first cut of this rule shipped without the prefix and did exactly that. */
.site-footer .ob-foot__pay-list {
	display: flex; flex-direction: row; align-items: center;
	gap: .4rem; flex-wrap: wrap;
}
/* Fixed box, not `height + width:auto`. The four cards are already one uniform
   48×32 geometry (see _project/tools/build-pay-marks.py), so pinning both axes
   keeps them exact and — because the same numbers are on the <img> attributes —
   reserves the space before the SVGs load, which is what stops the copyright bar
   jumping on a cold cache. */
.site-footer .ob-foot__pay-list img { display: block; width: 36px; height: 24px; }

@media (max-width: 520px) {
	/* Stack the label above the cards rather than letting one card wrap onto a
	   line by itself: at 320px the label plus four cards measures 300px against a
	   ~284px track, and a lone trailing card reads as a rendering fault. */
	.ob-foot__pay-inner { flex-direction: column; align-items: flex-start; gap: .5rem; }
}

/* Copyright bar */
.site-footer__bar { border-top: 1px solid rgba(var(--ob-tan-rgb), .18); }
.site-footer__bar-inner {
	max-width: var(--ob-max); margin-inline: auto;
	padding: 1rem var(--ob-gap);
	display: flex; justify-content: space-between; gap: 1rem; flex-wrap: wrap;
	font-size: .78rem; color: var(--ob-cream-soft);
}
.site-footer__bar-inner p { margin: 0; }
/* The registered entity, under the wordmark it trades as. Its own LINE rather than a
   run-on continuation of the copyright: "© 2026 Old Baraqa შპს კალტი · ს/კ 405480055"
   reads as one mangled name, and the two are different kinds of fact. Block inside the
   paragraph, so it needs no second `<p>` and cannot be pushed elsewhere by the bar's
   space-between. */
.ob-foot__entity { display: block; margin-top: .2rem; }
/* The middot between the copyright and the rights sentence. An ELEMENT rather than the
   `::before` the legal row uses, because those two sit in one flowing paragraph and a
   generated marker cannot be told which of them it belongs to when the line breaks.
   --ob-tan for the same reason as the legal row's separator, and it is a mark rather
   than text so 3.94:1 is the bar it has to clear. */
.ob-foot__sep { color: var(--ob-tan); margin-inline: .15rem; }

/* The legal row: the privacy policy, the delivery and returns policy, and the cookie
   re-open control. Separated by a middot drawn on every child AFTER the first, so the row
   still reads correctly when neither policy is published and the button is the only thing
   in it. Both links render only when their page exists, so the count is 1 to 3. */
.ob-foot__legal { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
/* --ob-tan, not --ob-tan-ink: on walnut-deep the ink shade measures 3.12:1, which clears
   the 3:1 bar for a non-text mark by 0.12 and nothing more. --ob-tan is 3.94:1. The
   tan-is-not-a-text-colour rule is about LIGHT grounds; this is a dark one. */
.ob-foot__legal > * + *::before { content: "\00B7"; margin-inline-end: .5rem; color: var(--ob-tan); }
/* Underlined, to match the button beside it. The two sit side by side doing the same kind
   of job, and only one of them carrying an underline made the row look half-finished — the
   button has one because it has to read as a link rather than as a control. The rest of the
   footer's links stay plain, which is right: those are navigation and this row is not. */
.ob-foot__legal a { color: var(--ob-cream-soft); text-decoration: underline; text-underline-offset: 2px; }
.ob-foot__legal a:hover { color: var(--ob-cream); }
/* A button, because it acts on this page rather than navigating (see footer.php), but
   it belongs to a row of links and has to read as one — so the UA button box is
   stripped back to inherited type and colour. `font: inherit` is what stops it
   rendering at the browser's 13.33px default beside 0.78rem text. */
.ob-foot__cookies {
	appearance: none;
	background: none;
	border: 0;
	padding: 0;
	font: inherit;
	color: var(--ob-cream-soft);
	text-decoration: underline;
	text-underline-offset: 2px;
	cursor: pointer;
	transition: color var(--ob-dur-2) var(--ob-ease);
}
.ob-foot__cookies:hover { color: var(--ob-cream); }

/* ⚠️ Below 860px the items STACK and the separator goes, and both halves of that are
   required together. A wrapped flex row carries the `::before` separator down with the
   item it belongs to, so it lands at the START of the next line and reads as a bullet in
   front of a label — first seen at 390px, where two Georgian labels came to 432px against
   a ~355px track. There is no selector for "did this wrap", so the breakpoint is set from
   the longest language rather than detected.

   ⚠️ 560px WAS that width, and 2026-08-31 moved it: the delivery-and-returns policy is a
   THIRD link, and Georgian's three labels measure 226 + 267 + 206 = 699px, which is 715px
   with the separators. The bar's content box is `vw - 128`, so one honest line needs
   vw >= 843 — rounded up to 860 for the shortest safe round number. English and Russian
   are shorter and simply stack earlier than they must, which is the same trade 560 made.
   Re-measure this number if a label or a language is ever added. */
@media (max-width: 860px) {
	.ob-foot__legal { flex-direction: column; align-items: flex-start; gap: .3rem; }
	.ob-foot__legal > * + *::before { content: none; }
}

@media (max-width: 900px) {
	.site-footer__inner { grid-template-columns: 1fr 1fr; }
	.ob-foot__brand { grid-column: 1 / -1; }
}
@media (max-width: 520px) {
	.site-footer__inner { grid-template-columns: 1fr; }
	/* Stack, don't wrap: side by side the two lines read as one run-on sentence. */
	.site-footer__bar-inner { flex-direction: column; gap: .35rem; }
}

/* ---------- Touch targets ---------- */
/* Audited on 2026-08-18 across 14 pages by 8 widths. The site had NO horizontal overflow
   and nothing crossing a viewport edge anywhere — that part was already right — but below
   1024px it carried eleven distinct control heights, and the short ones were the ones
   that mattered: the cart icon 30px tall sitting immediately beside a 40px nav toggle in
   the same cluster, the language codes 27px, the quick-add 34px (the primary action on the
   whole catalogue), the menu chips 37px, and a `tel:` link people are meant to TAP at
   22px. `--ob-touch` is 40px, which is the nav toggle's own height — so this brings the
   rest into line with what was already there rather than inventing a number.

   ## Two techniques, and when each applies

   1. Where a control's height comes from ONE declaration and nothing is positioned
      against its box, raise that declaration. `--ob-qadd-h` is the ideal case: both
      quick-add states read it, so raising it once cannot desynchronise the equal-height
      contract that makes the +/stepper swap cost no layout shift.

   2. Everywhere else, an invisible `::before` overlay that grows the HIT AREA and leaves
      the visual box alone. That matters because these boxes are load-bearing: the cart's
      badge is positioned against it, the language switcher's underline is pinned to the
      anchor's bottom edge, and `.ob-more` sits on a heading's baseline. Padding any of
      them moves something that was measured.

   ⚠️ VERTICAL ONLY, with one deliberate exception. A 40px-wide overlay centred on a 19px
   anchor with 5px of gap beside it overlaps its neighbour by ~16px, and the later sibling
   wins the overlap — so tapping EN would select RU. Height is the axis that was failing;
   width is only ever grown into a gap that already exists. */
@media (max-width: 1023px) {
	.brand,
	.ob-cart,
	.ob-acct-link,
	.lang-switcher a,
	.ob-more,
	.ob-post__more,
	.ob-visit__val--num,
	.woocommerce .show-password-input,
	.ob-foot__legal > * {
		position: relative;
	}

	/* `.brand` is here for the cluster's sake rather than its own: at 36px it was the last
	   thing in the header row not matching the other three, and it only misses by 4. */
	.brand::before,
	.ob-cart::before,
	.ob-acct-link::before,
	.lang-switcher a::before,
	.ob-more::before,
	.ob-post__more::before,
	.ob-visit__val--num::before,
	/* WooCommerce's own password-reveal eye, 22x22 as it ships. Ours is the form it sits
	   in, so the target is ours to fix. */
	.woocommerce .show-password-input::before,
	/* `::after` on the legal row alone: its `::before` is already the middot separator. */
	.ob-foot__legal > *::after {
		content: "";
		position: absolute;
		top: 50%;
		left: 50%;
		transform: translate(-50%, -50%);
		width: 100%;
		height: var(--ob-touch);
		/* Over the element's own ink so it takes the tap, under everything else. */
		z-index: 1;
	}

	/* The one width exception, and it is a gap being claimed rather than a neighbour: at
	   this breakpoint `.lang-switcher ul` has a .3rem gap, so +.3rem per anchor makes
	   adjacent hit areas meet exactly instead of overlapping. 19px becomes ~24px wide.

	   ⚠️ 24 is where this stops, and that is a decision rather than an oversight. Three
	   two-letter codes cannot each be 40px WIDE without spending ~120px of a 296px header
	   row, which is the compact-header requirement this site is built to. 24px clears the
	   WCAG AA floor (24x24), the height is a comfortable 40, and the hit areas are exactly
	   disjoint — verified as 0px overlap, because overlapping them would mean tapping EN
	   and getting RU, which is worse than a narrow target. Do not "finish the job" here. */
	.lang-switcher a::before { width: calc(100% + .3rem); }

	/* The cart icon's own box is 39px wide, one short, and it has .55rem of gap on both
	   sides — so unlike the language codes it can afford the pixel. */
	.ob-cart::before { min-width: var(--ob-touch); }

	/* Technique 1. One custom property drives both the "+" and the `− n +` stepper, so
	   this cannot pull them out of step.
	   +2px, not --ob-touch exactly: the stepper has a 1px border and its − and + are
	   `calc(var(--ob-qadd-h) - 2px)` tall, so a 40px box left the two buttons people
	   actually press at 38. The outer box being 42 costs nothing; the inner pair reaching
	   40 is the point. */
	.ob-qadd { --ob-qadd-h: calc(var(--ob-touch) + 2px); }

	/* The cart's own controls. The first pass missed every one of them because an EMPTY
	   cart renders none — no line item, no coupon bar, no totals. Above 768px these are
	   the desktop table's cells, so the phone-cart block cannot reach them either.
	   As it shipped: the remove x 18x18, the kitchen-note Save 30px tall, the coupon and
	   update pair 39, and the quantity field 39.6. (The shipping-calculator link was the
	   fifth; it was 23px, and it no longer exists — the cart summary was rebuilt without
	   the address calculator on 2026-08-21.) */
	.woocommerce-cart td.product-remove a.remove {
		display: grid; place-items: center;
		width: var(--ob-touch); height: var(--ob-touch);
		font-size: 1.3rem; line-height: 1;
	}
	.woocommerce-cart button.ob-cnote__save,
	.woocommerce-cart .cart .actions .button,
	.woocommerce-cart .quantity input.qty { min-height: var(--ob-touch); }

	/* And WooCommerce's own "view cart" button inside the add-to-cart notice — 33px tall,
	   the first thing a shopper is invited to tap after adding something, and another
	   control that only exists once the cart is not empty. inline-flex so the label stays
	   optically centred in the taller box. */
	.woocommerce-message a.button,
	.woocommerce-info a.button,
	.woocommerce-error a.button {
		display: inline-flex; align-items: center; min-height: var(--ob-touch);
	}

	/* The chips were 37px — three short. A real min-height rather than an overlay,
	   because a chip is a button with nothing positioned against it, and growing it is
	   the honest fix: what you tap and what you see are then the same object. */
	.ob-mchip { min-height: var(--ob-touch); }

	/* Checkboxes and radios: 13x13 as the browser ships them, and an `<input>` is a
	   replaced element that grows no pseudo-elements — so the overlay technique cannot
	   reach them. The LABEL carries the target instead, which works because clicking a
	   label toggles the control it wraps, and the box itself goes to ~18px because 13 is
	   small to aim at even with a large label beside it.

	   Two of these: WooCommerce's "remember me" on the login form, and OUR OWN
	   personal/company chooser on the registration form (ob-core's class-accounts.php),
	   which was 13px radios inside a 24px label. */
	.woocommerce-form__label-for-checkbox,
	.ob-acct-type label {
		display: inline-flex;
		align-items: center;
		gap: .5rem;
		min-height: var(--ob-touch);
	}
	.woocommerce-form__input-checkbox,
	.ob-acct-type input[type="radio"] {
		width: 1.15rem;
		height: 1.15rem;
		margin: 0;
		flex: none;
	}
}

/* ---------- Cookie banner ---------- */
/* Markup and behaviour are ob-core's (includes/class-consent.php, assets/js/consent.js);
   only the look is here, which is the usual split. Two things this depends on and must
   not be "tidied":

   1. The bar is printed with the `hidden` ATTRIBUTE and JavaScript is what removes it,
      because production is behind a page cache that does not key on cookies — markup
      that varied with somebody's choice would be cached and served to the next visitor.
      So do not add a `.is-open` class dance here; `[hidden]` is already doing the work,
      and it works in a theme that has never heard of this banner.
   2. It must clear the sticky header (z-index 50) and WooCommerce's own overlays.

   Walnut-deep with a tan hairline, i.e. the footer's own band: this is site furniture,
   not a dialog, and giving it a light surface of its own would put a fourth ground into
   a palette that has three. */
.ob-consent {
	position: fixed;
	inset-inline: 0;
	bottom: 0;
	z-index: 60;
	background: var(--ob-walnut-deep);
	border-top: 1px solid rgba(var(--ob-tan-rgb), .28);
	box-shadow: 0 -8px 26px rgba(20, 10, 4, .34);
	color: var(--ob-cream-soft);
	animation: ob-consent-in var(--ob-dur-3) var(--ob-ease);
}
.ob-consent__inner {
	max-width: var(--ob-max);
	margin-inline: auto;
	padding: .9rem var(--ob-gap);
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 1.2rem;
}
/* The heading names the region for assistive tech; on screen the first line of the
   sentence already says "cookies" twice over, so it is not repeated visually. */
.ob-consent__title {
	position: absolute;
	width: 1px; height: 1px;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
}
.ob-consent__text {
	margin: 0;
	font-size: .84rem;
	line-height: 1.55;
	max-width: 68ch;
}
.ob-consent__link { color: var(--ob-cream); text-underline-offset: 2px; }
.ob-consent__link:hover { color: var(--ob-tan-2); }
/* Both buttons the same size, side by side. Refusing must be exactly as easy as
   accepting; `flex-shrink: 0` is what stops the pair being squeezed into two lines of
   wrapped label while the sentence beside them keeps its width. */
.ob-consent__actions { display: flex; align-items: center; gap: .6rem; flex-shrink: 0; flex-wrap: wrap; }
/* nowrap so a two-word refusal label never becomes a two-line button beside a one-line
   one. `flex-wrap` on the row above is the insurance that goes with it: a longer
   translation pushes the pair onto two rows instead of off the side of the screen, which
   is what happened at 390px when the buttons were `flex: 1` — `min-width: auto` plus
   nowrap meant flex could not shrink them and the second ran 6px past the viewport. */
.ob-consent__btn { white-space: nowrap; }
/* The bar itself takes focus when it is re-opened from the footer, so it needs a ring
   like anything else — but not the 2px inset one, which on a full-width fixed bar reads
   as a border rather than a focus state. */
.ob-consent:focus-visible { outline: none; box-shadow: 0 -8px 26px rgba(20, 10, 4, .34), inset 0 3px 0 var(--ob-tan-2); }

@keyframes ob-consent-in {
	from { opacity: 0; transform: translateY(100%); }
	to   { opacity: 1; transform: none; }
}

/* Two steps down, not one, because the bar's height is screen the visitor cannot use and
   at 320px it was measured at 287px — 41% of the viewport.

   First, at 720px, the sentence takes the full width and the buttons drop below it, still
   side by side. Then at 480px they stack full width. 480 is where the pair stops fitting
   and it was measured, not chosen: the two Georgian labels come to 368px plus their gap,
   which needs a 378px track, and the content box is 443px at 481 and 355px at 390. The
   first attempt kept them in a row down to 400px with `flex: 1` and the refusal ran 6px
   off a 390px screen — flex cannot shrink a `white-space: nowrap` button below its text.
   */
@media (max-width: 720px) {
	.ob-consent__inner { flex-direction: column; align-items: stretch; gap: .8rem; }
	.ob-consent__btn { justify-content: center; }
}
@media (max-width: 480px) {
	.ob-consent__actions { flex-direction: column; align-items: stretch; }
}

/* ---------- Reveal ---------- */
/* Reveal-on-scroll. --ob-rise-d is a per-element stagger set by main.js so the
   children of a grid arrive in sequence rather than as one slab. */
.ob-rise { opacity: 0; transform: translateY(18px); transition: opacity var(--ob-dur-3) var(--ob-ease) var(--ob-rise-d, 0ms), transform var(--ob-dur-3) var(--ob-ease) var(--ob-rise-d, 0ms); }
.ob-rise.is-in { opacity: 1; transform: none; }

:focus-visible { outline: 2px solid var(--ob-tan-2); outline-offset: 2px; }

/* ---------- Mobile ---------- */
/* The header is ONE row on a phone: brand · language · cart · toggle, with the nav
   panel wrapping underneath only while open.
   It used to wrap to two rows — wordmark + a text "მენიუ" button, then KA/cart/
   შეკვეთა stranded left-aligned below — because those five items need ~372px and a
   390px viewport only gives 359px inside --ob-gap. Shrinking type would have been
   the wrong fix; the row simply had one item too many. So the order CTA moves into
   the panel and the toggle becomes an icon, which buys ~116px.
   Visual order is set with `order`, NOT by reordering the markup, so the toggle
   still sits immediately before the panel it controls in tab order.
   Was ≤780px. It now covers everything below 1024 as well, because that is where
   the one-row desktop header stops fitting with any cushion — see the note at the
   `min-width: 1024px` block. A tablet gets this layout, which is designed and measured, instead of a
   desktop row hanging 89–164px off the side of the document. */
@media (max-width: 1023px) {
	.site-header__inner  { flex-wrap: wrap; gap: .5rem; }
	/* auto margin, not space-between: the language/cart/toggle cluster has to stay
	   glued together at the end of the row rather than being spread across it. */
	.site-branding       { order: 1; margin-inline-end: auto; }
	.site-header__right  { order: 2; gap: .55rem; }
	.nav-toggle          { order: 3; }
	.site-nav            { order: 4; flex-basis: 100%; }
	.site-header__cta    { display: none; }
	/* The fifth icon is what pushed this header onto two rows. Text link in the
	   nav panel instead. */
	.ob-acct-link        { display: none; }

	/* Three languages put the row back over the edge, and by a measured 12px: at 390px
	   the branding (174) + the cart/language cluster (137) + the toggle (40) plus two
	   8px gaps came to 367 in a 355px track, so the toggle wrapped onto a second line.
	   The 16px of optical inset on the switcher is what pays for it, and it costs
	   nothing here: that padding exists to line "KA" up with the ACCOUNT icon's own
	   transparent margin (see the desktop rule), and the account icon is display:none
	   on this breakpoint. Tightening the gap as well leaves ~10px of headroom, so a
	   fourth language does not immediately reopen this.
	   Measured after: toggle back on row 1, zero horizontal overflow at 390 and 360. */
	.site-header__right .lang-switcher { padding-inline: 0; }
	.lang-switcher ul    { gap: .3rem; }

	/* 40px still reads as the carved roundel and gives the sticky header back 8px of
	   the screen on every page. */
	.brand { gap: .5rem; }
	.brand__logo { width: 40px; height: 40px; }

	.nav-toggle {
		display: inline-flex;
		align-items: center;
		justify-content: center;
		/* 40px square: a 20px icon on its own would be under the 44px touch target
		   guidance, and this matches the cart's optical size beside it. */
		width: 40px; height: 40px;
		padding: 0;
		background: none;
		border: 1px solid rgba(var(--ob-tan-rgb), .5);
		color: var(--ob-cream);
		border-radius: 3px;
		cursor: pointer;
		font: inherit;
		transition: border-color var(--ob-dur-2) var(--ob-ease), background var(--ob-dur-2) var(--ob-ease);
	}
	.nav-toggle:hover { border-color: var(--ob-tan-2); background: rgba(var(--ob-tan-rgb), .12); }

	/* On desktop the count badge can hang 9px outside the cart because there is a
	   1rem gap after it. In the packed mobile row it landed 1–3px ON TOP of the
	   toggle's border as soon as the cart was non-empty. Fixed by reserving the
	   badge's width inside the cart's own box rather than by widening the gap — the
	   cart now owns its badge's footprint, so no neighbour can collide with it at
	   any width. */
	.ob-cart { padding-right: .75rem; }
	.ob-cart__count { right: 0; }

	.site-nav { display: none; }
	/* A hard edge divides the panel from the row — never a fade. */
	.site-nav.is-open {
		display: block;
		margin-top: .35rem;
		border-top: 1px solid rgba(var(--ob-tan-rgb), .3);
		animation: ob-nav-in var(--ob-dur-2) var(--ob-ease) both;
	}
	.site-nav ul { flex-direction: column; gap: 0; padding-block: .3rem; }
	/* Full-width rows: the tap target is the row, not the word. */
	.site-nav li { border-bottom: 1px solid rgba(var(--ob-tan-rgb), .14); }
	.site-nav li:last-child { border-bottom: 0; }
	.site-nav ul a { display: block; padding: .8rem .15rem; font-size: 1rem; }
	/* The desktop underline would land at the bottom of a full-width row, right on
	   top of the row divider, and read as a misaligned border. So the panel marks the
	   current page with colour and weight instead. */
	.site-nav ul a::after { display: none; }
	.site-nav .current-menu-item > a { color: var(--ob-cream); font-weight: 600; }
	/* Sits with the nav links, not with the CTA: it is navigation, and the copper
	   button below it is the one action. */
	.site-nav__acct {
		display: block;
		padding: .55rem 0;
		border-top: 1px solid rgba(var(--ob-tan-rgb), .18);
		margin-top: .4rem;
		color: var(--ob-cream);
		text-decoration: none;
		font-size: .95rem;
	}
	.site-nav__acct:hover { color: var(--ob-tan-2); }

	.site-nav__cta { display: flex; justify-content: center; margin: .6rem 0 .8rem; }
}
/* At 320px (iPhone SE 1, Fold cover screen) --ob-gap bottoms out at its 1.1rem floor
   rather than 4vw, so the content box is only 285px and the row still overflowed by
   ~8px. Claw it back from the header's own padding and the two gaps — NOT from
   --ob-gap, which would re-margin every section on the page for one row's benefit.
   The wordmark drops a notch with it; below this width the roundel plus 12 Georgian
   letters is simply the widest thing on screen. */
@media (max-width: 360px) {
	.site-header__inner { padding-inline: .75rem; gap: .4rem; }
	.site-header__right { gap: .4rem; }
	.brand { gap: .4rem; }
	.brand__mark { font-size: .9rem; }
	/* 36px keeps the roundel the same share of a 320px screen that 40px is of 360.
	   Trimmed alongside the cart's badge reserve to leave the row ~8px of slack
	   instead of landing flush on the content edge, where a font-metric difference
	   between platforms would be enough to wrap it again. */
	.brand__logo { width: 36px; height: 36px; }
	.ob-cart { padding-right: .6rem; }

	/* ...and it still did not fit, which the note above had assumed rather than
	   re-measured after the ACCOUNT icon and the third language landed. Measured at
	   320px before this rule: branding 150 + cluster 110 + toggle 40 + two 6.4px gaps
	   = 313 in a 296px box, so the toggle wrapped and the header stood 103px tall on
	   every page of the site.

	   The 17px could only come from the wordmark or from the switcher, and trimming the
	   wordmark again means ~11px type for a brand name. So the switcher moves into the
	   nav panel — the same move the order CTA and the account link already made at this
	   breakpoint, and the third time it has been the right answer. Header keeps
	   brand · cart · toggle: 227 + 12.8 = 240 in 296, i.e. 56px of slack, which a
	   fourth language cannot spend because it is no longer in this row. */
	.site-header__right .lang-switcher { display: none; }

	.lang-switcher--nav {
		display: block;
		padding-block: .15rem .5rem;
		margin-bottom: .2rem;
		border-bottom: 1px solid rgba(var(--ob-tan-rgb), .18);
	}
	/* ⚠️ EVERY selector below is prefixed `.site-nav` for specificity, not for scope, and
	   removing the prefix silently breaks the switcher.

	   This copy lives INSIDE the nav panel, so the panel's own rules claim it: at this
	   breakpoint `.site-nav ul` is `flex-direction: column`, `.site-nav ul a` is
	   `display:block; padding:.8rem .15rem; font-size:1rem`, `.site-nav li` has a
	   hairline, and `.site-nav ul a::after` is `display:none`. Unprefixed
	   `.lang-switcher--nav a` (0-1-1) loses to `.site-nav ul a` (0-1-2), so the three
	   codes came out STACKED as 51px full-width rows with the current-language underline
	   gone and the whole switcher 209px tall — measured, not guessed. `.site-nav` in
	   front makes each of these 0-2-x, which wins.

	   Roomier than the header copy: this is a panel row, so the codes get a real tap
	   height. The extra space is bought with the list's gap and the anchor's
	   padding-BLOCK only — inline padding on the anchor stretches the underline, which is
	   pinned left:0/right:0 on it. Same trap as the note at the
	   `.site-header__right .lang-switcher` rule; it is easy to walk into twice. */
	.site-nav .lang-switcher--nav ul { flex-direction: row; gap: 1.1rem; padding-block: 0; }
	.site-nav .lang-switcher--nav li { border-bottom: 0; }
	.site-nav .lang-switcher--nav a { display: block; padding: .45rem 0; font-size: .92rem; }
	.site-nav .lang-switcher--nav a::after { display: block; }
}

/* The panel's arrival is animated with transform + opacity only. Its height is not
   transitioned — that would animate a reflow, which nothing on this site does. */
@keyframes ob-nav-in {
	from { opacity: 0; transform: translateY(-8px); }
	to   { opacity: 1; transform: none; }
}

/* Someone who asked the OS for less motion gets none of it: no keyframes, no
   transforms, no transitions. Colour changes stay, so hover/focus states are still
   legible — removing those would cost usability, not motion. */
@media (prefers-reduced-motion: reduce) {
	*, *::before, *::after {
		animation-duration: .001ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: .001ms !important;
		transition-delay: 0ms !important;
		scroll-behavior: auto !important;
	}
	.ob-rise { opacity: 1; transform: none; }
	/* The hero's own animations are flattened to their end state by the blanket
	   rule above, which is the right resting composition for all of them. The
	   Ken Burns drift is the exception: its end state is the zoomed-in frame, so
	   park it at the start instead. */
	.ob-hero--photo .ob-hero__media::before { transform: scale(1.04); }
	.ob-more:hover .ob-more__ic { transform: none; }
	.ob-btn:hover, .ob-btn:active,
	.ob-pcard:hover,
	.ob-post:hover,
	.ob-post__more:hover span,
	.ob-mchip:active,
	.ob-cart:active,
	.ob-qadd__add:hover, .ob-qadd__add:active,
	.ob-qadd__pm:active:not(:disabled) { transform: none; }
	.ob-menu__row:hover .ob-menu__thumb img,
	.ob-gallery__item:hover img,
	.ob-post:hover .ob-post__media img,
	.ob-shop ul.products li.ob-pcard:hover .ob-pcard__media img { transform: none; }
}

/* ── Account: registration / login ──────────────────────────────────────────
   WooCommerce's account forms arrive unstyled apart from what the checkout
   rules already give them. This is the minimum that stops them reading as a
   different website: the same card, the same field shapes, the same two-column
   rhythm. The account TABLES (orders, downloads) are left to Woo's defaults for
   now — they are behind a login and nobody has an order history yet. */

/* .entry-content caps at 720px — a reading measure, right for prose and wrong for
   a form layout. Two 20rem columns plus the gap do not fit in 720px, so without
   this the grid below silently collapses to one column and both forms sit in a
   narrow ribbon down the left of a 1280px screen. Measured, not guessed: the
   container computed to 720px while `display` was already `grid`. */
.woocommerce-account .entry-content { max-width: none; }

.woocommerce-account .woocommerce {
	max-width: 1040px;
	margin-inline: auto;
	padding-block: clamp(1.5rem, 4vw, 3rem);
}

/* Login and register sit side by side on desktop, stacked on a phone. Woo emits
   them as two sibling columns, so the grid goes on their parent. Cards are top
   aligned: the register form is taller and stretching the login one to match left
   a large dead area under its button. */
.woocommerce-account .u-columns.col2-set {
	display: grid;
	gap: clamp(1.25rem, 3vw, 2.25rem);
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr));
	align-items: start;
}

/* Woo clears its floats with ::before/::after { content:" "; display:table }. In a
   GRID container those pseudo-elements become grid items, so they claimed the first
   and last track and pushed both real columns one track right — a 3-track layout
   with an empty column on the left. Measured: gridTemplateColumns reported three
   322px tracks for two children. */
.woocommerce-account .u-columns.col2-set::before,
.woocommerce-account .u-columns.col2-set::after { display: none; }

/* And the floats themselves. Woo sizes .col-1/.col-2 at 48% for a float layout, so
   inside a grid track each card was 48% of 322px = 155px, with 97px inputs. Grid
   places them now, so the float and the percentage both have to go. */
.woocommerce-account .u-columns .u-column1,
.woocommerce-account .u-columns .u-column2 {
	float: none;
	width: 100%;
	margin: 0;
}

/* Inputs fill their card. Woo leaves them at the UA default width, which in a
   narrow column reads as a broken form rather than a deliberate one. */
.woocommerce-account form.login .input-text,
.woocommerce-account form.register .input-text,
.woocommerce-account form.woocommerce-ResetPassword .input-text {
	width: 100%;
	box-sizing: border-box;
}

/* Woo's own buttons arrive at #e9e6ed on grey — a different product's styling
   sitting in the middle of ours. Same shape and colour as .ob-btn--pom, without
   reaching for that class in markup we do not own. */
.woocommerce-account .woocommerce-button,
.woocommerce-account button.button,
.woocommerce-account input.button {
	display: inline-block;
	font-family: var(--ob-sans);
	font-weight: 600;
	font-size: .92rem;
	/* .75, not .7: at .7rem these came to 39px, one pixel under --ob-touch, at every width.
	   Padding rather than min-height so the label stays optically centred. */
	padding: .75rem 1.35rem;
	border-radius: 2px;
	border: 1px solid transparent;
	cursor: pointer;
	background: var(--ob-copper);
	color: #fff;
	box-shadow: var(--ob-shadow-1);
	transition: background var(--ob-dur-2) var(--ob-ease),
	            box-shadow var(--ob-dur-2) var(--ob-ease);
}

.woocommerce-account .woocommerce-button:hover,
.woocommerce-account button.button:hover,
.woocommerce-account input.button:hover {
	background: var(--ob-copper-br);
	color: #fff;
	box-shadow: var(--ob-shadow-2);
}

.woocommerce-account form.login,
.woocommerce-account form.register {
	border: 1px solid var(--ob-line);
	/* 3px: the theme's dominant radius (13 uses). `var(--ob-radius)` was used here
	   at first and that token does not exist in :root, so it resolved to nothing
	   and these cards rendered with square corners while everything else was 3px. */
	border-radius: 3px;
	background: var(--ob-cream);
	padding: clamp(1.1rem, 3vw, 1.75rem);
}

.ob-acct-type {
	border: 0;
	margin: 0 0 1rem;
	padding: 0;
}

.ob-acct-type legend {
	padding: 0;
	margin-bottom: .5rem;
	font-weight: 600;
}

/* Radios read as a pair of choices, not a list. */
.ob-acct-type label {
	display: inline-flex;
	align-items: center;
	gap: .45rem;
	margin-inline-end: 1.25rem;
	cursor: pointer;
}

.ob-acct-type input { accent-color: var(--ob-copper); }

/* The company block appears and disappears, so it needs a visible edge of its
   own or the form looks like it grew a random tail. */
.ob-acct-company {
	border-inline-start: 3px solid var(--ob-copper);
	padding-inline-start: clamp(.75rem, 2vw, 1rem);
	margin-block: 1rem;
}

.ob-acct-note {
	font-size: .875rem;
	line-height: 1.5;
	opacity: .8;
	margin-block: .5rem 0;
}

/* Business-price caption. Quiet on purpose: it labels the number, it is not a
   badge competing with it. Copper ties it to the same "this is yours" signal the
   logged-in account icon uses. */
.ob-b2b-tag {
	display: inline-block;
	margin-inline-start: .35rem;
	font-size: .72rem;
	font-weight: 600;
	letter-spacing: .04em;
	text-transform: lowercase;
	color: var(--ob-copper-br);
	white-space: nowrap;
}

/* ── Account area (logged in) ────────────────────────────────────────────────
   WooCommerce ships the account pages as a bare <ul> of links beside a
   paragraph of prose. On this site that was the last surface still rendering
   like an unstyled document, and it gave no current-page state on a screen
   whose only job is moving between five sub-pages.

   The language here is borrowed from components that already exist rather than
   invented: rows behave like the nav links (idle tan, copper when current),
   the panel uses the checkout card's surface and hairline, and the one filled
   button is the same .ob-btn--pom as everywhere else. One accent, copper. */

/* Woo floats these at 30%/68%. Grid instead, so the sidebar has a real minimum
   and the panel takes the rest, and so the two stop depending on clearfixes. */
.woocommerce-account .woocommerce-MyAccount-navigation,
.woocommerce-account .woocommerce-MyAccount-content { float: none; width: auto; }

@media (min-width: 781px) {
	/* `.logged-in` matters: logged OUT, this same .woocommerce wrapper holds the
	   login/register columns, and the sidebar grid gave that page a dead 232px
	   track down its left side. Measured: tracks came out `232px 764.8px` with
	   nothing in the first one. */
	.logged-in.woocommerce-account .woocommerce {
		display: grid;
		grid-template-columns: minmax(190px, 232px) 1fr;
		gap: clamp(1.5rem, 3vw, 2.75rem);
		align-items: start;
	}
	/* Woo's clearfix pseudo-elements become grid items and would each take a
	   track. Same trap as the login/register columns above. */
	.logged-in.woocommerce-account .woocommerce::before,
	.logged-in.woocommerce-account .woocommerce::after { display: none; }
}

/* ---- sidebar ---- */
.ob-acct-nav ul { list-style: none; margin: 0; padding: 0; }

.ob-acct-nav li + li { margin-top: 2px; }

.ob-acct-nav a {
	display: flex;
	align-items: center;
	gap: .7rem;
	padding: .62rem .8rem;
	border-radius: 3px;
	text-decoration: none;
	color: var(--ob-ink-soft);
	font-size: .94rem;
	line-height: 1.2;
	transition: color var(--ob-dur-2) var(--ob-ease),
	            background var(--ob-dur-2) var(--ob-ease);
}

.ob-acct-nav__ic { width: 19px; height: 19px; flex: none; opacity: .75; }

.ob-acct-nav a:hover {
	color: var(--ob-ink);
	background: rgba(var(--ob-tan-rgb), .16);
}
.ob-acct-nav a:hover .ob-acct-nav__ic { opacity: 1; }

/* Current page reads copper and carries a marker, the same way the site nav
   marks the current page. Two signals, because colour alone is not one. */
.ob-acct-nav .is-active > a {
	color: var(--ob-copper);
	background: rgba(var(--ob-tan-rgb), .22);
	font-weight: 600;
	box-shadow: inset 3px 0 0 var(--ob-copper);
}
.ob-acct-nav .is-active .ob-acct-nav__ic { opacity: 1; }

/* Logging out is not a peer of "orders" and should not sit in the same block. */
.ob-acct-nav .woocommerce-MyAccount-navigation-link--customer-logout {
	margin-top: .55rem;
	padding-top: .55rem;
	border-top: 1px solid var(--ob-line);
}

/* ---- panel ---- */
.woocommerce-account .woocommerce-MyAccount-content {
	background: var(--ob-cream);
	border: 1px solid var(--ob-line);
	border-radius: 3px;
	padding: clamp(1.1rem, 2.6vw, 1.9rem);
}

.ob-acct-dash__head { margin-bottom: 1.1rem; }
.ob-acct-dash__head h2 { margin: 0; font-size: clamp(1.35rem, 2.6vw, 1.75rem); }
.ob-acct-dash__org {
	margin: .25rem 0 0;
	color: var(--ob-ink-soft);
	font-size: .95rem;
}

/* The standing pricing flag. Copper, because it is the same "this is yours"
   signal the logged-in account icon and the business price caption use. */
.ob-acct-flag {
	margin: 0 0 1.1rem;
	padding: .7rem .95rem;
	border: 1px solid rgba(var(--ob-tan-rgb), .34);
	border-left: 3px solid var(--ob-copper);
	border-radius: 3px;
	background: var(--ob-surface-2);
	font-size: .92rem;
	line-height: 1.5;
}
/* Pending is the same shape in a quieter voice: it is a wait, not a warning. */
.ob-acct-flag--pending { border-left-color: var(--ob-tan); color: var(--ob-ink-soft); }

/* Last order / empty state. A link-shaped block, so the whole thing is the
   target rather than a small "view" link at the end of a row. */
.ob-acct-card {
	display: grid;
	gap: .3rem;
	padding: .95rem 1.05rem;
	border: 1px solid var(--ob-line);
	border-radius: 3px;
	background: var(--ob-surface);
	text-decoration: none;
	color: inherit;
	transition: border-color var(--ob-dur-2) var(--ob-ease),
	            transform var(--ob-dur-1) var(--ob-ease);
}
a.ob-acct-card:hover { border-color: var(--ob-copper); }
a.ob-acct-card:active { transform: translateY(1px); }

.ob-acct-card__lbl {
	font-size: .72rem;
	font-weight: 600;
	letter-spacing: .08em;
	text-transform: uppercase;
	color: var(--ob-ink-soft);
}
.ob-acct-card__main { font-size: 1.05rem; line-height: 1.35; }
.ob-acct-card__meta { font-size: .88rem; color: var(--ob-ink-soft); }

.ob-acct-card--empty { background: transparent; border-style: dashed; }

.ob-acct-dash__cta { margin: 1.2rem 0 0; }

/* ---- the tables Woo renders on Orders and Addresses ---- */
.woocommerce-account .woocommerce-orders-table,
.woocommerce-account .shop_table {
	width: 100%;
	border-collapse: collapse;
	font-size: .94rem;
}
.woocommerce-account .shop_table th {
	text-align: start;
	font-size: .72rem;
	font-weight: 600;
	letter-spacing: .08em;
	text-transform: uppercase;
	color: var(--ob-ink-soft);
	padding: .5rem .6rem;
	border-bottom: 1px solid var(--ob-line);
}
.woocommerce-account .shop_table td {
	padding: .7rem .6rem;
	border-bottom: 1px solid var(--ob-line);
}
.woocommerce-account .shop_table tr:last-child td { border-bottom: 0; }

/* Addresses: two columns on desktop, stacked on a phone. */
.woocommerce-account .woocommerce-Addresses {
	display: grid;
	gap: clamp(1rem, 2.5vw, 1.75rem);
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
}
.woocommerce-account .woocommerce-Addresses::before,
.woocommerce-account .woocommerce-Addresses::after { display: none; }
.woocommerce-account .woocommerce-Address { float: none; width: auto; }
.woocommerce-account .woocommerce-Address address { font-style: normal; line-height: 1.6; }

/* Below the grid breakpoint the sidebar becomes a horizontal scroller so it
   costs one row instead of six, which is what a phone can spare above the
   content the user came for. */
@media (max-width: 780px) {
	.ob-acct-nav {
		margin-bottom: 1.1rem;
		overflow-x: auto;
		-webkit-overflow-scrolling: touch;
	}
	.ob-acct-nav ul { display: flex; gap: .3rem; }
	.ob-acct-nav li + li { margin-top: 0; }
	.ob-acct-nav a { white-space: nowrap; }
	.ob-acct-nav .is-active > a { box-shadow: inset 0 -3px 0 var(--ob-copper); }
	.ob-acct-nav .woocommerce-MyAccount-navigation-link--customer-logout {
		margin-top: 0;
		padding-top: 0;
		border-top: 0;
		border-left: 1px solid var(--ob-line);
		margin-left: .3rem;
		padding-left: .3rem;
	}
}

/* `.entry-content a` is copper at 0-2-0 and outranks `.ob-btn--pom` at 0-1-0, so a
   filled button placed inside page content had a copper label on a copper fill: a
   button that measured 14.72px of text and read as an empty orange block. Fixed
   generally rather than on the account page alone, because any .ob-btn dropped
   into content would have hit it. */
.entry-content a.ob-btn--pom { color: #fff; }
.entry-content a.ob-btn--ghost { color: var(--ob-cream); }

/* Order status sits apart from the date and total rather than being strung on
   after a second middle dot: it is the fact a customer opens this page to check. */
.ob-acct-card__status {
	display: inline-block;
	margin-inline-start: .5rem;
	padding: .1rem .45rem;
	border: 1px solid rgba(var(--ob-tan-rgb), .5);
	border-radius: 3px;
	font-size: .8rem;
	color: var(--ob-ink);
}

/* Addresses: the title and its action.
   Woo emits <header class="woocommerce-Address-title"> holding an <h2> and an
   <a class="edit">, with no styling of its own. Unstyled that gave a heading with
   a bare underlined link centred beneath it -- the one control on the page read as
   a stray piece of text rather than the action it is. The link becomes a compact
   outlined button, sitting on the same row as the title on desktop. */
/* Stacked, not a title/action row. Measured: the column is 333px and a Georgian
   address title alone is 217-230px, so title + button never fit on one line and
   flex-wrap dropped the button onto its own line ANYWAY -- but as a wrapped
   fragment that read as a centred orphan under the heading. Stacking it on purpose
   and aligning it to the start makes the same two lines look deliberate. */
.woocommerce-account .woocommerce-Address-title {
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: .45rem;
	margin-bottom: .6rem;
}

.woocommerce-account .woocommerce-Address-title h2 {
	margin: 0;
	font-size: clamp(1.05rem, 2vw, 1.2rem);
}

/* Outlined, not filled: there are two of these side by side and neither is the
   page's primary action. Same shape and hairline as the .ob-btn scale. */
.woocommerce-account .woocommerce-Address-title .edit {
	flex: none;
	display: inline-block;
	padding: .34rem .7rem;
	border: 1px solid var(--ob-line-2);
	border-radius: 3px;
	font-size: .82rem;
	font-weight: 600;
	line-height: 1.25;
	text-decoration: none;
	/* Ink, not copper. Copper on this panel measured 4.02:1, under the 4.5:1 AA
	   floor for text this size -- it is a copper that was calibrated against the
	   cream page background, not against the tan panel. The border and the hover
	   carry the brand instead, which is what a secondary button needs to do. */
	color: var(--ob-ink);
	transition: border-color var(--ob-dur-2) var(--ob-ease),
	            background var(--ob-dur-2) var(--ob-ease),
	            color var(--ob-dur-2) var(--ob-ease);
}
.woocommerce-account .woocommerce-Address-title .edit:hover {
	border-color: var(--ob-copper);
	background: rgba(var(--ob-tan-rgb), .18);
}
.woocommerce-account .woocommerce-Address-title .edit:active { transform: translateY(1px); }

/* The "you have not set this address yet" line, and the address itself. */
.woocommerce-account .woocommerce-Address address { color: var(--ob-ink); }
.woocommerce-account .woocommerce-Address p { color: var(--ob-ink-soft); margin: 0; }

/* ── Blog: listing, cards, archives ─────────────────────────────────────────
   Templates: home.php (the posts page), index.php (category / tag / date /
   search / 404) and template-parts/post-card.php.

   The card is deliberately the .ob-pcard idea applied to a post rather than a
   second card design: same surface, same tan hairline, same 8px radius, same
   3px lift on hover — and the same rule that nothing may depend on the length
   of the copy. Eyebrow, headline and excerpt each hold a fixed number of lines,
   so three cards in a row line their dates and their "read more" up whatever
   the client writes. What differs is only what a post has instead of a price:
   a date, and no add-to-cart. */

.ob-blog { padding-block: clamp(2.5rem, 6vw, 4rem); }

.ob-blog__grid {
	display: grid;
	/* 272px rather than the shop's 228px: a headline plus two lines of standfirst
	   needs a wider measure than a dish name, and it lands on three columns at
	   full width and two on a tablet. */
	grid-template-columns: repeat(auto-fill, minmax(272px, 1fr));
	gap: clamp(1rem, 2.2vw, 1.5rem);
	align-items: stretch;
}

.ob-post {
	display: flex;
	flex-direction: column;
	margin: 0;
	background: var(--ob-surface);
	border: 1px solid rgba(var(--ob-tan-rgb), .38);
	border-radius: 8px;
	overflow: hidden;
	transition: transform var(--ob-dur-2) var(--ob-ease),
	            border-color var(--ob-dur-2) var(--ob-ease),
	            box-shadow var(--ob-dur-2) var(--ob-ease);
}
.ob-post:hover {
	transform: translateY(-3px);
	border-color: var(--ob-tan);
	box-shadow: var(--ob-shadow-3);
}

/* 16/9, not the shop's 4/3: a news photograph is usually a scene rather than an
   object, and the wider frame keeps three cards from becoming a tall grid. */
.ob-post__media {
	display: block;
	position: relative;
	aspect-ratio: 16 / 9;
	background: var(--ob-surface-2);
	border-bottom: 1px solid rgba(var(--ob-tan-rgb), .3);
	overflow: hidden;
}
.ob-post__media img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
	transition: transform var(--ob-dur-3) var(--ob-ease);
}
.ob-post:hover .ob-post__media img { transform: scale(1.05); }
/* Same treatment the shop card gives it: the shared line-art panel is a warm
   gradient tile that shouts in a grid, so inside a card it becomes a quiet
   parchment panel. */
.ob-post__media .ob-media-ph {
	display: grid;
	place-items: center;
	width: 100%;
	height: 100%;
	background: var(--ob-surface-2);
	color: var(--ob-tan);
}
.ob-post__media .ob-media-ph svg { width: 30%; opacity: .5; }

.ob-post__body {
	flex: 1;
	display: flex;
	flex-direction: column;
	padding: .95rem 1rem 1.05rem;
}

/* Rendered even when the post has no category, so the row still holds its line.
   --ob-tan-ink rather than the eyebrow's --ob-tan: at this size it is body-weight
   text and needs 4.5:1, which --ob-tan misses on the card surface.

   line-height and min-height are deliberately the SAME number. At the shop card's
   1.1em an EMPTY eyebrow reserves 11.3px where a filled one occupies a 16.4px line
   box, so a row of uncategorised posts came out 5px shorter than a row of filed
   ones — measured as card heights [391, 386] in one grid. It never shows on
   .ob-pcard because every product has a category; posts often have none. */
.ob-post__cat {
	font-size: .64rem;
	line-height: 1.6;
	letter-spacing: .18em;
	color: var(--ob-tan-ink);
	min-height: 1.6em;
	margin: 0 0 .35rem;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

/* Exactly two lines, always. */
.ob-post__title {
	font-family: var(--ob-serif);
	font-size: 1.05rem;
	font-weight: 600;
	line-height: 1.34;
	margin: 0;
	min-height: calc(2 * 1.34em);
	display: -webkit-box;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
	text-wrap: initial; /* balancing would fight the clamp */
}
.ob-post__title a { color: var(--ob-ink); text-decoration: none; }
.ob-post__title a:hover { color: var(--ob-copper); }
.ob-post__title a:focus-visible { outline: 2px solid var(--ob-copper); outline-offset: 3px; border-radius: 2px; }

/* Three lines, always — the excerpt is trimmed to 24 words in the template as
   well, so a screen reader is not read a whole paragraph out of a card that
   shows three lines. */
.ob-post__excerpt {
	margin: .5rem 0 0;
	color: var(--ob-ink-soft);
	font-size: .88rem;
	line-height: 1.55;
	min-height: calc(3 * 1.55em);
	display: -webkit-box;
	-webkit-line-clamp: 3;
	-webkit-box-orient: vertical;
	overflow: hidden;
}

/* margin-top:auto is the safety net the shop card uses too: the rows above are
   fixed-height so it should never engage. */
.ob-post__foot {
	margin: .8rem 0 0;
	padding-top: .6rem;
	margin-top: auto;
	border-top: 1px solid var(--ob-line-2);
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: .6rem;
}
.ob-post__date {
	font-size: .78rem;
	color: var(--ob-tan-ink);
	font-variant-numeric: tabular-nums;
}
.ob-post__more {
	font-size: .82rem;
	font-weight: 600;
	color: var(--ob-copper);
	text-decoration: none;
	white-space: nowrap;
}
.ob-post__more span { display: inline-block; transition: transform var(--ob-dur-2) var(--ob-ease); }
.ob-post__more:hover { color: var(--ob-copper-br); }
.ob-post__more:hover span { transform: translateX(3px); }
.ob-post__more:focus-visible { outline: 2px solid var(--ob-copper); outline-offset: 3px; border-radius: 2px; }

.ob-blog__empty {
	text-align: center;
	color: var(--ob-ink-soft);
	max-width: 46ch;
	margin: 0 auto;
	padding-block: clamp(1.5rem, 5vw, 3rem);
}
.ob-blog__empty-cta { text-align: center; margin: 0; }

/* Pagination. WordPress's own markup (.navigation.pagination > .nav-links >
   .page-numbers), styled as the same pill scale as the menu chips so a second
   control language is not introduced for one row of numbers. */
.ob-blog .pagination { margin-top: clamp(2rem, 5vw, 3rem); }
.ob-blog .pagination .nav-links {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: .45rem;
}
.ob-blog .page-numbers {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 2.4rem;
	min-height: 2.4rem;
	padding: .35rem .7rem;
	border: 1px solid var(--ob-line);
	border-radius: 999px;
	background: var(--ob-surface);
	color: var(--ob-ink-soft);
	font-size: .85rem;
	font-variant-numeric: tabular-nums;
	text-decoration: none;
	transition: border-color var(--ob-dur-2) var(--ob-ease), color var(--ob-dur-2) var(--ob-ease);
}
.ob-blog .page-numbers:hover { border-color: var(--ob-tan); color: var(--ob-ink); }
.ob-blog .page-numbers.current {
	background: var(--ob-walnut);
	border-color: var(--ob-walnut);
	color: var(--ob-cream);
}
.ob-blog .page-numbers.dots { border-color: transparent; background: none; }
.ob-blog .page-numbers:focus-visible { outline: 2px solid var(--ob-copper); outline-offset: 2px; }

/* ── Blog: the post itself ──────────────────────────────────────────────────
   single.php. The reading column is the site's existing .entry-content measure,
   so a post reads like the About page rather than like a second design. */

/* The kicker links back to the blog from inside the dark hero band, so it takes
   the band's own eyebrow colour rather than copper, which is calibrated for the
   light grounds. */
.ob-article__kicker a { color: var(--ob-tan-2); text-decoration: none; }
.ob-article__kicker a:hover { color: var(--ob-cream); }
.ob-article__meta {
	margin: .9rem 0 0;
	color: var(--ob-cream-soft);
	font-size: .85rem;
	font-variant-numeric: tabular-nums;
}

/* Matched to the text measure, not to the full wrap: a 1120px photograph over a
   720px column reads as two different pages. */
.ob-article__media { margin: 0; padding-top: clamp(1.6rem, 4vw, 2.4rem); }
.ob-article__media img {
	display: block;
	max-width: 720px;
	border-radius: 8px;
	border: 1px solid rgba(var(--ob-tan-rgb), .3);
}
.ob-article__media figcaption {
	max-width: 720px;
	margin-top: .5rem;
	color: var(--ob-ink-soft);
	font-size: .8rem;
}

.ob-article__pages { margin-top: 1.6rem; font-size: .85rem; }
.ob-article__pages span { color: var(--ob-tan-ink); margin-right: .4rem; }

/* Categories and tags. The chips themselves are .ob-mchip — the menu page's own
   category pill, reused rather than redrawn, so filing a post does not introduce
   a third chip shape. Only the row they sit in is new. */
.ob-article__terms {
	display: flex;
	flex-wrap: wrap;
	gap: .45rem;
	max-width: 720px;
	margin: 2rem 0 0;
	padding-top: 1.4rem;
	border-top: 1px solid var(--ob-line-2);
}

.ob-article__nav {
	display: grid;
	gap: .8rem;
	max-width: 720px;
	margin-top: 2rem;
}
@media (min-width: 620px) {
	.ob-article__nav { grid-template-columns: 1fr 1fr; }
}
.ob-article__nav-link {
	display: block;
	padding: .8rem 1rem;
	border: 1px solid var(--ob-line);
	border-radius: 8px;
	background: var(--ob-surface);
	text-decoration: none;
	transition: border-color var(--ob-dur-2) var(--ob-ease), background var(--ob-dur-2) var(--ob-ease);
}
.ob-article__nav-link:hover { border-color: var(--ob-tan); background: var(--ob-surface-2); }
.ob-article__nav-link:focus-visible { outline: 2px solid var(--ob-copper); outline-offset: 2px; }
.ob-article__nav-link .ob-eyebrow { color: var(--ob-tan-ink); font-size: var(--ob-eyebrow-tight); display: block; }
.ob-article__nav-title {
	display: block;
	margin-top: .3rem;
	font-family: var(--ob-serif);
	font-size: .98rem;
	line-height: 1.35;
	color: var(--ob-ink);
	/* One line each, so a long headline cannot make the two boxes different
	   heights on desktop. */
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}
.ob-article__nav-link--next { text-align: right; }

.ob-article__back { margin-top: 2rem; }

/* The accessible-only label the pagination and the cart's note field both use.
   Defined here rather than borrowed from WooCommerce's stylesheet: an
   accessibility primitive that only works while a plugin's global CSS is loaded
   is one dequeue away from printing "Posts navigation" as a visible heading. */
.screen-reader-text {
	border: 0;
	clip-path: inset(50%);
	height: 1px;
	width: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	position: absolute !important;
	white-space: nowrap;
	word-wrap: normal;
}
.screen-reader-text:focus {
	clip-path: none;
	height: auto;
	width: auto;
	display: block;
	top: 5px;
	left: 5px;
	z-index: 100000;
	padding: .8rem 1.2rem;
	background: var(--ob-surface);
	color: var(--ob-ink);
	font-size: .9rem;
	text-decoration: none;
}
