/* ==========================================================================
   3DOptix redesign — blog index page-unique CSS.

   Depends on: dxr-tokens.css -> dxr-components.css -> dxr-shell.css
   Enqueued CONDITIONALLY from page-templates/dxr-blog.php (handle
   'dxr-page-blog', dependency 'dxr-shell'), so it ships on this page only and
   can never reorder the shared layer.

   The approved design does not specify a blog index. Everything here is
   transcribed from the ONE collection view the prototype does contain — the
   Academy index, '3DOptix Website.dc.html' lines 628-741 — so the blog reads
   as part of the same system. The line references below point at that block.

   RULES FOR THIS FILE:
   - SCOPE. Every selector is scoped to .dxr-page-blog, the wrapper class the
     template emits. Legacy Elementor / Academy / WooCommerce markup keeps its
     own list bullets, paragraph spacing and link underlines. No bare element
     selectors, ever, and nothing here may leak to a sibling page — other
     agents are writing sibling templates in parallel.
   - No new colour. Every value resolves from the token layer; the only raw
     numbers are geometry transcribed verbatim from the prototype, and each one
     is named in §0 rather than repeated as a literal below (same convention as
     dxr-page-technology.css §0).
   - No new keyframe. The three that exist are enough; the only motion here is
     a border-colour transition, already neutralised by the shared
     prefers-reduced-motion block in dxr-components.css §2.
   - The spectrum gradient appears ZERO times in this file.
   ========================================================================== */

/* ==========================================================================
   §0 Page-local custom properties

   Prototype values with no entry in the token layer.
   ========================================================================== */
.dxr-page-blog{
  --dxr-blog-head-top:clamp(27px,3.3vw,44px);   /* proto 632 */
  --dxr-blog-head-bot:clamp(32px,3.9vw,52px);   /* proto 632 */
  --dxr-blog-gap:24px;                          /* proto 659 — NOT --dxr-gap-panels (20px) */
  --dxr-blog-field-h:52px;                      /* proto 643 */
  --dxr-blog-page-h:44px;                       /* pagination cell, derived — see §5.
                                                   44px, not 40: the cell is a touch
                                                   target and the design transcribes
                                                   no value for it. */
}

/* ==========================================================================
   §1 Page header — dark band (proto 630-639)

   Deliberately NOT .dxr-hero: no glow, no CTA row, no spectrum eyebrow bar.
   An index is a directory, not a pitch. The 64px blueprint is the design's one
   documented 64px instance and .dxr-blueprint--64 already exists for it.

   The rhythm is the prototype's, not the system's, so .dxr-section's
   --dxr-section-y is overridden here rather than in the shared layer. The
   two-class selector outranks .dxr-section without !important.
   ========================================================================== */
.dxr-page-blog .dxr-blog__head{
  padding:var(--dxr-blog-head-top) 0 var(--dxr-blog-head-bot);
}

/* The breadcrumb occupies the eyebrow slot — it is already mono, and it is
   real existing content on this page. That is why dxr_eyebrow() is not called. */
.dxr-page-blog .dxr-blog__crumbs{
  display:flex;align-items:center;gap:10px;flex-wrap:wrap;
  margin-bottom:24px;
  font:400 12px/1 var(--dxr-font-mono);
  color:var(--dxr-on-dark-caption);
}
.dxr-page-blog .dxr-blog__crumbs a{position:relative;color:var(--dxr-on-dark-body-alt)}
.dxr-page-blog .dxr-blog__crumbs a:hover{color:var(--dxr-on-dark)}
/* TOUCH TARGET. The 12px mono line box gives the crumb link a ~12px-tall hit
   area. The pseudo-element enlarges the hit area WITHOUT moving anything:
   12 + 16 + 16 = 44px tall, and 4px of horizontal bleed against the row's 10px
   gap leaves the neighbouring crumb its own 2px of clearance. The band's own
   top padding is >=27px and the row's margin-bottom is 24px, so the overhang
   never reaches another control. */
.dxr-page-blog .dxr-blog__crumbs a::after{
  content:"";position:absolute;inset:-16px -4px;
}

/* Prototype 636. Smaller than .dxr-h1--page on purpose — an index H1 is not a
   product H1. The shared type file is off-limits to this batch, so the role is
   authored here rather than added to §4 of dxr-components.css. */
.dxr-page-blog .dxr-blog__title{
  margin:0 0 14px;
  font:800 clamp(27px,4.2vw,46px)/1.08 var(--dxr-font-sans);
  letter-spacing:-.038em;
  color:var(--dxr-on-dark);
}

/* ==========================================================================
   §2 Controls band — sunken (proto 641-652)

   Opens on the header's own top rhythm and closes on the standard
   --dxr-section-y, which is what .dxr-section already supplies.

   The search field is genuinely new: the design layer contains NO form-control
   rules of any kind (dxr-tokens.css, dxr-components.css and dxr-shell.css
   carry no input/form/search selector), so the appearance reset below is
   required, not defensive.
   ========================================================================== */
.dxr-page-blog .dxr-blog__body{padding-top:var(--dxr-blog-head-top)}

/* The blog has no taxonomy, so the prototype's filter-chip row never renders
   and the search field carries the band's closing rule instead (proto 648). */
.dxr-page-blog .dxr-blog__controls{
  padding-bottom:28px;
  border-bottom:1px solid var(--dxr-border);
}

.dxr-page-blog .dxr-blog__search{
  display:flex;align-items:stretch;
  max-width:min(100%,720px);
  height:var(--dxr-blog-field-h);
  background:var(--dxr-surface);
  border:1px solid var(--dxr-border-strong);
  border-radius:var(--dxr-radius-md);
  overflow:hidden;
}
.dxr-page-blog .dxr-blog__search-input{
  flex:1;min-width:0;
  -webkit-appearance:none;appearance:none;
  margin:0;padding:0 18px;
  border:0;background:transparent;
  /* 16px is a FLOOR, not a design choice: iOS Safari auto-zooms any focused
     form control whose computed font-size is below 16px, and it does not undo
     the zoom on blur — the visitor is left on a 300px visual viewport with 20px
     of the page off-screen to the right. The field is a fixed 52px and the UA
     centres the text, so nothing else moves. */
  font:400 16px/1 var(--dxr-font-sans);
  color:var(--dxr-ink);
}
.dxr-page-blog .dxr-blog__search-input::placeholder{color:var(--dxr-text-disabled);opacity:1}
.dxr-page-blog .dxr-blog__search-input::-webkit-search-cancel-button{-webkit-appearance:none}

/* Not .dxr-btn: the prototype's submit is a flush-mounted segment of the field
   with no radius and no independent height. Colour, weight and hover still
   come from the primary-button tokens, so the two stay in step. */
.dxr-page-blog .dxr-blog__search-submit{
  -webkit-appearance:none;appearance:none;
  display:inline-flex;align-items:center;white-space:nowrap;
  margin:0;padding:0 26px;border:0;cursor:pointer;
  background:var(--dxr-primary);
  color:var(--dxr-on-dark);
  font:700 13px/1 var(--dxr-font-sans);
  letter-spacing:.05em;text-transform:uppercase;
  transition:background-color .15s ease;
}
.dxr-page-blog .dxr-blog__search-submit:hover{background:var(--dxr-primary-hover)}

/* ==========================================================================
   §3 Results line (proto 654-657)

   Rendered only while a search is active — see the template. The heading role
   is the shared .dxr-h3-product; only the row and the mono count live here.
   ========================================================================== */
.dxr-page-blog .dxr-blog__results{
  display:flex;align-items:baseline;gap:12px;flex-wrap:wrap;
  margin:36px 0 22px;
}
/* The heading echoes the visitor's raw query. An unbroken 40-character token at
   the clamp minimum (19px/800) measures ~418px against the 280px container at a
   320px viewport, and nothing in the ancestor chain clips or scrolls — the
   document itself would scroll sideways. `anywhere` only engages when the word
   genuinely does not fit, so ordinary search terms are unaffected. */
.dxr-page-blog .dxr-blog__results .dxr-h3-product{overflow-wrap:anywhere}
/* ACCESSIBILITY: --dxr-text-subtle is 3.69:1 on white and fails WCAG AA at
   this size. It is a client-approved palette value — see the note in
   dxr-tokens.css §1.2. Do not darken it here; escalate. */
.dxr-page-blog .dxr-blog__count{
  font:400 13px/1 var(--dxr-font-mono);
  color:var(--dxr-text-subtle);
}

/* ==========================================================================
   §4 Card grid + card (proto 659-726)

   320px / 3-up is the tuned --dxr-min-3up: at the 1300px container the usable
   width is 1220px, so the row resolves to 3 x 390px (a 4th column would need
   4*320 + 3*24 = 1352px). 12 posts per page therefore fill four clean rows of
   three, with no ragged last row. The blog card carries a 16/9 image, a title,
   a three-line excerpt and a meta line — content-bearing cells, which is
   exactly what --dxr-min-3up is documented for.
   ========================================================================== */
.dxr-page-blog .dxr-blog__grid{
  display:grid;
  grid-template-columns:repeat(auto-fit,minmax(min(100%,var(--dxr-min-3up)),1fr));
  gap:var(--dxr-blog-gap);
  margin-top:36px;
}

/* Prototype 661: bordered, 12px radius, no background of its own, so the body
   sits on the sunken ground. Hover moves the BORDER only — the system owns
   exactly three shadows and none of them is a card shadow, so no lift and no
   scale. */
.dxr-page-blog .dxr-blog__card{
  display:flex;flex-direction:column;
  border:1px solid var(--dxr-border);
  border-radius:var(--dxr-radius-panel);
  overflow:hidden;
  color:inherit;
  transition:border-color .15s ease;
}
.dxr-page-blog .dxr-blog__card:hover{border-color:var(--dxr-accent-rule);color:inherit}

/* aspect-ratio rather than the prototype's fixed 172px: the card is 390px wide
   at 3-up and full-width on a phone, and one fixed height cannot serve both
   without letterboxing. object-fit:cover absorbs any source ratio, and the
   same box governs the hatch fallback (dxr_hatch is called with height => 0,
   so it emits no --hNNN class) — which is what keeps every card in a row the
   same height whether or not the post has a featured image. */
.dxr-page-blog .dxr-blog__media{
  aspect-ratio:16/9;
  flex-shrink:0;
  overflow:hidden;
}
/* The hatch fallback composes `.dxr-blog__media .dxr-hatch` on ONE element, and
   this two-class selector outranks the single-class .dxr-hatch (§9), so a solid
   background here would silently swallow the diagonal-hatch placeholder. Same
   trap, same fix, as .dxr-panel__media in dxr-components.css §12: the fill is
   applied only when the hatch is absent; the box metrics above stay
   unconditional. */
.dxr-page-blog .dxr-blog__media:not(.dxr-hatch){background:var(--dxr-surface-raised)}
.dxr-page-blog .dxr-blog__media img{display:block;width:100%;height:100%;object-fit:cover}

.dxr-page-blog .dxr-blog__card-body{
  display:flex;flex-direction:column;flex:1;
  padding:20px;
}
.dxr-page-blog .dxr-blog__card-title{margin:0 0 8px}

/* WordPress auto-excerpts run to 55 words and would leave card heights wildly
   unequal. Bounded VISUALLY — the copy itself is never rewritten or truncated
   server-side. */
.dxr-page-blog .dxr-blog__card-excerpt{
  margin:0;
  display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;
  overflow:hidden;
}

/* Mono, because everything in it is measured: a name and a date. */
.dxr-page-blog .dxr-blog__card-meta{
  display:flex;align-items:center;gap:8px;flex-wrap:wrap;
  margin-top:auto;padding-top:16px;
  border-top:1px solid var(--dxr-border-inner);
  font:400 11px/1.5 var(--dxr-font-mono);
  color:var(--dxr-text-subtle);
}
.dxr-page-blog .dxr-blog__card-meta time{font-variant-numeric:tabular-nums}
.dxr-page-blog .dxr-blog__card-sep{color:var(--dxr-border-strong)}

/* ==========================================================================
   §5 Pagination — derived, not in the prototype

   Derivation: the number cell IS the prototype's filter chip (line 649), and
   the chip's selected state IS the current page — the one "selected" idiom the
   design owns. Figures stay mono because they are measured; the prev/next
   labels are words, so they drop to sans. Left-aligned, because every band in
   this design aligns to the container's left edge and a centred element would
   be the only centred thing on the page.

   The class names are paginate_links()' own output, unchanged, so the emitted
   DOM stays identical to production's.
   ========================================================================== */
.dxr-page-blog .dxr-blog__pager{
  display:flex;align-items:center;gap:8px;flex-wrap:wrap;
  margin-top:48px;padding-top:28px;
  border-top:1px solid var(--dxr-border);
}
.dxr-page-blog .dxr-blog__pager .page-numbers{
  display:inline-flex;align-items:center;justify-content:center;
  min-width:var(--dxr-blog-page-h);height:var(--dxr-blog-page-h);padding:0 12px;
  border:1px solid var(--dxr-border);
  border-radius:var(--dxr-radius-md);
  background:var(--dxr-surface);
  color:var(--dxr-ink);
  font:500 13px/1 var(--dxr-font-mono);
  transition:border-color .15s ease,color .15s ease;
}
.dxr-page-blog .dxr-blog__pager a.page-numbers:hover{
  border-color:var(--dxr-accent-rule);color:var(--dxr-accent-text);
}
.dxr-page-blog .dxr-blog__pager .page-numbers.current{
  background:var(--dxr-ink);border-color:var(--dxr-ink);color:var(--dxr-on-dark);
}
/* prev/next carry prose ("Next »"), so they leave the mono role. */
.dxr-page-blog .dxr-blog__pager .page-numbers.prev,
.dxr-page-blog .dxr-blog__pager .page-numbers.next{
  padding:0 16px;font:600 13px/1 var(--dxr-font-sans);
}
.dxr-page-blog .dxr-blog__pager .page-numbers.dots{
  min-width:auto;padding:0 4px;
  border-color:transparent;background:transparent;
  color:var(--dxr-text-subtle);
}

/* ==========================================================================
   §6 Empty state — derived; the legacy template has none
   ========================================================================== */
.dxr-page-blog .dxr-blog__empty{
  margin-top:36px;
  max-width:min(100%,620px);
  background:var(--dxr-surface);
  border:1px solid var(--dxr-border);
  border-radius:var(--dxr-radius-panel);
  padding:var(--dxr-pad-panel);
}
/* TOUCH TARGET. The recovery link is the only way out of a zero-result search
   and the shared .dxr-cta-link is a 14px line box. It is padded HERE rather than
   in dxr-components.css because that primitive is shared with pages other agents
   own. 14 + 15 + 15 = 44px. The paragraph's closing margin drops from 20 to 5 so
   the new padding restores, not adds to, the prototype's 20px gap, and the
   negative bottom margin keeps the panel's own padding symmetrical. */
/* The 44px hit area for this link already comes from the shared
   .dxr-cta-link::after{inset:-16px 0} in dxr-components.css. Adding padding
   here stacked a second overlay 31px tall, which reached up into the
   paragraph above. Prototype margin restored instead. */
.dxr-page-blog .dxr-blog__empty-text{margin:8px 0 20px}

/* ==========================================================================
   §7 "Read More »" affordance — home.php only

   SHARED FILE, ADDITIVE ONLY. This stylesheet is enqueued by BOTH
   page-templates/dxr-blog.php and home.php, because both render the same
   .dxr-page-blog block. home.php is the one that serves the live posts index
   and it preserves the live card's "Read More »" label, which dxr-blog.php
   drops. dxr-blog.php never emits .dxr-blog__card-more, so every rule below is
   inert there — nothing in this section can change what that template renders.

   NOT a button and NOT .dxr-cta-link: it sits INSIDE the card anchor, so it is
   a <span> with no href, no hover state of its own and no hit area of its own.
   The whole card is already the 44px+ target. It borrows the CTA link's
   typographic arrow idiom — the » is content carried over from the live page,
   not an icon, which is why it is typed in the markup rather than drawn here.

   The card is a flex column and .dxr-blog__card-meta owns `margin-top:auto`,
   so the meta row stays pinned to the card's bottom edge and this label sits
   directly under the excerpt, exactly as it does on production.
   ========================================================================== */
/* align-self:flex-start is load-bearing, not tidiness: .dxr-blog__card-body is
   a flex COLUMN, whose default align-items:stretch would blow this span out to
   the full card width. Invisible today (the text is left-aligned either way),
   but it would surface the moment anything gives the label a background, a
   border or a hover area. Hugging its own text is the honest box. */
.dxr-page-blog .dxr-blog__card-more{
  align-self:flex-start;
  margin-top:12px;
  font:600 13px/1.4 var(--dxr-font-sans);
  color:var(--dxr-accent-text);
}

/* NO HOVER RULE HERE, DELIBERATELY. §4 above states the card's contract: hover
   moves the BORDER only. A colour shift on this label would break that, and
   would also advertise the span as a second, independently clickable target
   inside a card that is already one anchor. The static accent colour is enough
   to read as an affordance — the whole card is the control.
   (There is no --dxr-accent-text-hover token, and this is not the place to
   invent one: the accent channel is defined once in dxr-tokens.css §1.) */
