/* ============================================================
   Bossert Custom Dog Tags, order page
   Matches the bossertmilsurp.com military-surplus design system.
   ============================================================ */

:root {
  --od-green:     #3D4A2A;   /* deep olive drab */
  --od-green-dk:  #2A3320;
  --od-green-lt:  #5B6B3F;
  --field-tan:    #B59B6A;   /* khaki / webbing */
  --field-tan-dk: #8B7344;
  --canvas:       #E8DCC4;   /* faded canvas paper */
  --canvas-warm:  #DDCDA9;
  --bone:         #F2EAD3;   /* field-manual off-white */
  --ink:          #1A1814;
  --ink-soft:     #3D3A30;
  --rust:         #8B3A22;   /* faded stamp red */
  --steel:        #4A4A42;   /* gunmetal, for the tag preview */
  --paper-line:   rgba(26, 24, 20, 0.20);
  --paper-line-lt:rgba(26, 24, 20, 0.10);

  /* ---- Tag preview finishes ---------------------------------
     Four stops per finish (light, mid, body, dark), plus one edge per finish
     and the inks. ONLY the .dt-tag-preview--<key> modifier rules consume these.
     The tag body itself names no colour at all, so replacing a hand tuned
     finish with a real product photograph later is a single declaration inside
     a single rule. The shop sells six finishes; all six live here.

     The inks are not interchangeable. Brass keeps a WARM near black because a
     cool one on gold reads as printed rather than stamped, and the mirror blank
     keeps a faintly COOL one because polished chrome reflects sky. Every pairing
     below is held above the WCAG AA 4.5 to 1 floor by tests/styles.test.js,
     which recomputes the arithmetic from these exact values. */
  --tag-steel-lt:  #d9d9d2;   /* dull brushed stainless */
  --tag-steel-md:  #b9b9b0;
  --tag-steel:     #cfcfc7;
  --tag-steel-dk:  #a7a79e;
  --tag-black-lt:  #3a3a40;   /* polished black */
  --tag-black-md:  #17171a;
  --tag-black:     #2c2c31;
  --tag-black-dk:  #0d0d10;
  --tag-red-lt:    #8f2226;   /* anodic crimson, not a signal red */
  --tag-red-md:    #6a1417;
  --tag-red:       #7d1c20;
  --tag-red-dk:    #540f12;
  --tag-monel-lt:  #d6d2c8;   /* the WWII tag was Monel, warmer than stainless */
  --tag-monel-md:  #b8b3a7;
  --tag-monel:     #cac6bb;
  --tag-monel-dk:  #a5a092;
  --tag-brass-lt:  #e6cb94;   /* limited edition brass */
  --tag-brass-md:  #c8a967;
  --tag-brass:     #d9bc7d;
  --tag-brass-dk:  #b39158;
  --tag-mirror-lt: #fbfbfc;   /* retired mirror palette (was the silver medical mapping); kept for a possible future polished style */
  --tag-mirror-md: #d4d7dd;
  --tag-mirror:    #f0f2f5;
  --tag-mirror-dk: #bfc3ca;

  --tag-edge-steel:  #8f8f86;
  --tag-edge-black:  #55555c;
  --tag-edge-red:    #4a0d10;
  --tag-edge-monel:  #8a8477;
  --tag-edge-brass:  #8f7038;
  --tag-edge-mirror: #9aa0a8;

  --tag-ink-dark:  #23231f;   /* the shipped preview ink, promoted to a token */
  --tag-ink-light: #F2EAD3;   /* same value as --bone */
  --tag-ink-brass: #241c08;
  --tag-ink-cool:  #1e1e22;

  /* Opaque approximation of what sits BEHIND the tag, so the WWII notch reads as
     a cut rather than a window: the panel's rgba(242,234,211,0.55) composited
     over the body wash, tuned by eye. It cannot be exact, because a translucent
     fill would show the tag's own gradient through it and the backdrop varies
     slightly down the page. It is a decorative cue on a preview, not a photoreal
     cut, and it is one line to retune. */
  --tag-notch-fill: #EAE1CB;

  --font-stencil: 'Big Shoulders Stencil Display', Impact, sans-serif;
  --font-display: 'Oswald', 'Arial Narrow', sans-serif;
  --font-serif:   'Crimson Pro', 'EB Garamond', Georgia, serif;
  --font-mono:    'Special Elite', 'Courier New', monospace;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: var(--font-serif);
  font-size: 18px;
  line-height: 1.6;
  color: var(--ink);
  background-color: var(--canvas);
  /* aged-paper wash: warm pool top-center, OD shadow lower-right */
  background-image:
    radial-gradient(120% 80% at 50% -10%, rgba(242,234,211,0.85), transparent 60%),
    radial-gradient(90% 70% at 110% 120%, rgba(42,51,32,0.16), transparent 55%),
    radial-gradient(70% 60% at -10% 0%, rgba(139,115,68,0.14), transparent 50%);
  background-attachment: fixed;
  min-height: 100vh;
}

.dt-main {
  max-width: 720px;
  margin: 0 auto;
  padding: clamp(1.5rem, 5vw, 4rem) clamp(1.1rem, 4vw, 2rem) 3rem;
}

/* ---- Header ---------------------------------------------- */
.dt-header { text-align: center; margin-bottom: clamp(1.5rem, 4vw, 2.75rem); }

.dt-eyebrow {
  font-family: var(--font-display);
  text-transform: uppercase;
  letter-spacing: 0.22em;
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--field-tan-dk);
  margin: 0 0 0.7rem;
}

.dt-title {
  font-family: var(--font-stencil);
  font-weight: 800;
  text-transform: uppercase;
  font-size: clamp(2.6rem, 9vw, 5rem);
  line-height: 0.9;
  letter-spacing: -0.005em;
  color: var(--ink);
  margin: 0;
  text-wrap: balance;
}

.dt-lede {
  max-width: 46ch;
  margin: 0.9rem auto 0;
  color: var(--ink-soft);
  font-size: 1.02rem;
}

/* ---- Panels (spec cards) --------------------------------- */
.dt-panel {
  background: rgba(242, 234, 211, 0.55);
  border: 1.5px solid var(--paper-line);
  padding: clamp(1.2rem, 4vw, 2rem);
  margin-bottom: 1.6rem;
  box-shadow: 0 1px 0 rgba(255,255,255,0.4) inset, 0 3px 14px rgba(26,24,20,0.06);
}

.dt-panel-title {
  font-family: var(--font-display);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-size: clamp(1.35rem, 3.5vw, 1.9rem);
  color: var(--od-green);
  margin: 0 0 1.1rem;
  padding-bottom: 0.6rem;
  border-bottom: 2px solid var(--paper-line);
}

/* slot header: title + remove on one line */
.dt-slot-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
}
.dt-slot-head .dt-panel-title { flex: 1; }
.dt-slot-head .dt-remove {
  flex: none;
  font-family: var(--font-display);
  font-size: 0.8rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--rust);
  background: transparent;
  border: 1.5px solid var(--rust);
  border-radius: 0;
  width: auto;
  height: auto;
  padding: 0.35rem 0.7rem;
  cursor: pointer;
}
.dt-slot-head .dt-remove:hover { background: rgba(139,58,34,0.08); }
/* The chip computes to about 29.56px tall and cannot simply grow, because
   .dt-slot-head aligns on the BASELINE: a taller button would move its text
   baseline down and drag the panel heading with it, visibly shifting the title
   against its underline. Switching the row to center would drop the chip onto
   that border, and padding it would push it up out of the heading. So the hit
   area is a pseudo element: layout, baseline and appearance stay byte
   identical while the tappable box reaches 44px, overhanging about 7.22px top
   and bottom into padding that is already empty. min-width can never trigger
   at the current label width, and is kept only so the rule stays correct if
   the label is ever shortened. */
.dt-slot-head .dt-remove { position: relative; }
.dt-slot-head .dt-remove::after {
  content: "";
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  width: 100%;
  min-width: 44px;
  height: 44px;
}

.dt-set-note {
  font-size: 0.9rem;
  color: var(--ink-soft);
  font-style: italic;
  margin: 0 0 0.6rem;
}

.dt-slot-line {
  font-family: var(--font-display);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-size: 0.95rem;
  color: var(--ink);
  text-align: right;
  margin: 0.9rem 0 0;
  padding-top: 0.7rem;
  border-top: 1px solid var(--paper-line-lt);
}
.dt-slot-line strong { font-size: 1.15rem; }

/* Add-another-tag button: full width, ghost/olive outline */
.dt-btn-add-slot {
  display: block;
  width: 100%;
  margin: 0 0 1.6rem;
  font-family: var(--font-display);
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding: 0.9em 1.5em;
  background: transparent;
  color: var(--od-green);
  border: 2px dashed var(--field-tan-dk);
  cursor: pointer;
  transition: background 0.2s ease, border-color 0.2s ease;
}
.dt-btn-add-slot:hover { background: rgba(61,74,42,0.06); border-color: var(--od-green); }
.dt-btn-add-slot:focus-visible { outline: 3px solid var(--od-green-lt); outline-offset: 2px; }

/* ---- Fields ---------------------------------------------- */
.dt-field { display: block; margin-bottom: 1.2rem; }

.dt-field-label,
.dt-legend {
  display: block;
  font-family: var(--font-display);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--ink-soft);
  margin-bottom: 0.45rem;
}

.dt-select,
.dt-line-input,
.dt-qty input {
  font-family: var(--font-display);
  font-size: 1rem;
  color: var(--ink);
  background: var(--bone);
  border: 1.5px solid var(--field-tan-dk);
  padding: 0.6rem 0.7rem;
  width: 100%;
}

.dt-select { letter-spacing: 0.01em; }

.dt-fieldset {
  border: 1px dashed var(--paper-line);
  padding: 1rem;
  margin: 0 0 1.2rem;
}
.dt-legend { padding: 0 0.5rem; }

/* stamped-tag character rows, echoes Don's paper grid: line number + boxes + count */
.dt-lines {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin-bottom: 0.9rem;
}
.dt-line-row {
  display: flex;
  align-items: center;
  gap: 0.6rem;
}
.dt-line-num {
  font-family: var(--font-head, var(--font-display));
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--field-tan-dk);
  width: 1.1rem;
  text-align: right;
  flex: none;
}
.dt-line-input {
  flex: 1 1 auto;
  font-family: var(--font-mono);
  letter-spacing: 0.22em;
  text-transform: uppercase;
}
.dt-line-count {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  color: var(--ink-soft);
  width: 3.2rem;
  text-align: right;
  flex: none;
  font-variant-numeric: tabular-nums;
}
/* The qty input no longer owns a border, so a focus ring on it would draw
   inside the stepper group. The group lights up via :focus-within instead. */
.dt-line-input:focus,
.dt-select:focus {
  outline: 3px solid var(--od-green-lt);
  outline-offset: 1px;
  border-color: var(--od-green);
}

/* ---- The stamped metal tag preview -----------------------
   The preview shows the FINISH the customer picked, with their own live text
   on it. The body names no colour: it consumes five indirections, and one
   .dt-tag-preview--<key> modifier per style sets them. Two consequences worth
   stating, because both are the point of doing it this way.

   1. A style key with NO modifier rule renders today's standard stainless tag
      rather than a transparent box, because the standard stainless values are
      declared right here as the defaults. newSlot() starts on standard_ss and
      previewClass() falls back to it, so the default has to be a real tag.
   2. Swapping a hand tuned finish for a real product photograph is ONE line
      inside ONE rule: --dt-tag-fill: url("/img/tag-brass.jpg") center / cover
      no-repeat. Nothing else moves. Turning the grain off for a photographed
      finish is a second one line change, --dt-tag-grain: none, and the WWII
      notch has its own one line off switch. The CSP in deploy/_headers already
      allows img-src 'self' data:, so a self hosted file needs no header change.

   A modifier rule may set --dt-tag-* properties and NOTHING else. No height, no
   padding, no font-size, no alignment. That restriction is what keeps the fixed
   height and the left justification below out of reach of a per style change,
   and tests/styles.test.js enforces it rather than trusting the convention. */
.dt-tag-preview {
  font-family: var(--font-mono);
  font-size: clamp(1rem, 3.6vw, 1.3rem);
  letter-spacing: 0.16em;
  line-height: 1.7;
  text-transform: uppercase;
  margin: 0;
  padding: 1em 1.5rem;
  /* Fixed tag body: always reserves all ROWS lines (5 x 1.7 line-height) plus
     vertical padding, so the tag stays one constant size and the text fills
     into it. Without this the <pre> hugged its content and the tag grew or
     shrank with each line, which misrepresented the finished product. */
  height: calc(5 * 1.7em + 2em + 4px);
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  justify-content: center;
  /* Left-justified, per DA PAM 600-8-14: every line starts at a common left
     margin with a ragged right edge. This is how the embossing machines
     actually stamp, across all eras and both notched and non-notched tags.
     Centered text is not military spec. The block stays vertically centered
     on the tag face; only horizontal alignment is flush left. */
  align-items: flex-start;
  text-align: left;
  border-radius: 34px;
  /* Positioning context for the WWII notch. Harmless on a flex container: it
     establishes a containing block and changes no layout by itself. */
  position: relative;
  /* The defaults, which ARE the standard stainless treatment. */
  --dt-tag-fill: linear-gradient(135deg, var(--tag-steel-lt) 0%, var(--tag-steel-md) 30%, var(--tag-steel) 55%, var(--tag-steel-dk) 100%);
  --dt-tag-grain: repeating-linear-gradient(102deg, rgba(0,0,0,0.055) 0 1px, transparent 1px 3px);
  --dt-tag-edge: var(--tag-edge-steel);
  --dt-tag-text: var(--tag-ink-dark);
  --dt-tag-sheen: inset 0 1px 2px rgba(255,255,255,0.70), inset 0 -2px 5px rgba(0,0,0,0.25);
  --dt-tag-emboss: 0 1px 0 rgba(255,255,255,0.35), 0 -1px 1px rgba(0,0,0,0.35);
  color: var(--dt-tag-text);
  /* Grain over fill, always in that order: the wash is what the contrast
     arithmetic composites against the extreme stop of the fill. */
  background: var(--dt-tag-grain), var(--dt-tag-fill);
  border: 2px solid var(--dt-tag-edge);
  box-shadow: var(--dt-tag-sheen), 0 3px 10px rgba(26,24,20,0.18);
  text-shadow: var(--dt-tag-emboss);
  white-space: pre-wrap;
  word-break: break-word;
  overflow-x: auto;
}

/* ---- The six finishes, matched to the stock on Don's shelf ----
   Colour only. Every grain is a single rgba wash whose POLARITY matches its
   text: black on a dark text body, white on a light text body. That is not a
   stylistic choice, it is the invariant the contrast proof rests on. Grain that
   can only darken a light body means the worst pixel under dark text is the
   darkest stop plus grain and nothing else needs checking; grain that can only
   lighten a dark body is the same argument inverted. A white sheen added to a
   light body would move the worst pixel somewhere the test never looks. */

/* Dull matte silver, dark text. The shipped look, kept verbatim as the baseline
   so this change is visibly additive. Brushed: the grain is a 1px repeating rule
   at 102 degrees, near vertical against the 135 degree fill so the two do not
   moire. Worst case 5.84 to 1 on #9e9e95, the darkest stop under the grain. */
.dt-tag-preview--standard_ss {
  --dt-tag-fill: linear-gradient(135deg, var(--tag-steel-lt) 0%, var(--tag-steel-md) 30%, var(--tag-steel) 55%, var(--tag-steel-dk) 100%);
  --dt-tag-grain: repeating-linear-gradient(102deg, rgba(0,0,0,0.055) 0 1px, transparent 1px 3px);
  --dt-tag-edge: var(--tag-edge-steel);
  --dt-tag-text: var(--tag-ink-dark);
  --dt-tag-sheen: inset 0 1px 2px rgba(255,255,255,0.70), inset 0 -2px 5px rgba(0,0,0,0.25);
  --dt-tag-emboss: 0 1px 0 rgba(255,255,255,0.35), 0 -1px 1px rgba(0,0,0,0.35);
}

/* Glossy near black, LIGHT text. The dark ink used everywhere else would have
   been about 1.13 to 1 here, which is not hard to read, it is invisible, and
   this is a surface someone proofreads before metal is cut. The emboss inverts
   with the text, dark below and light above, so the letters still read as
   pressed rather than as a colour swap. Gloss is a single wide specular sweep
   rather than a brush grain, which is the visual difference between polished
   and brushed, and it is capped at 0.055 alpha so the lightest reachable pixel
   stays computable. Worst case 7.93 to 1 on #45454b, the LIGHTEST stop under
   the sweep. */
.dt-tag-preview--polished_black {
  --dt-tag-fill: linear-gradient(158deg, var(--tag-black-lt) 0%, var(--tag-black-md) 34%, var(--tag-black) 58%, var(--tag-black-dk) 100%);
  --dt-tag-grain: linear-gradient(158deg, rgba(255,255,255,0.055) 0 14%, transparent 32%);
  --dt-tag-edge: var(--tag-edge-black);
  --dt-tag-text: var(--tag-ink-light);
  --dt-tag-sheen: inset 0 1px 2px rgba(255,255,255,0.22), inset 0 -2px 6px rgba(0,0,0,0.55);
  --dt-tag-emboss: 0 1px 0 rgba(0,0,0,0.55), 0 -1px 1px rgba(255,255,255,0.20);
}

/* Matte silver plus the notch, dark text. Shifted a few points warm and
   desaturated against standard stainless, because the WWII tag was Monel rather
   than stainless and because two of six finishes reading as the same grey would
   leave the customer unsure the selector did anything. The notch is the primary
   cue, the warmth the secondary one. The first draft of this fill was rejected:
   its darkest stop computed to 4.87 worst case, inside rounding distance of the
   floor, so the stop was lightened. The treatment changed, the bar did not.
   Worst case 5.41 to 1 on #9c978a. */
.dt-tag-preview--notched_wwii {
  --dt-tag-fill: linear-gradient(135deg, var(--tag-monel-lt) 0%, var(--tag-monel-md) 30%, var(--tag-monel) 55%, var(--tag-monel-dk) 100%);
  --dt-tag-grain: repeating-linear-gradient(102deg, rgba(0,0,0,0.055) 0 1px, transparent 1px 3px);
  --dt-tag-edge: var(--tag-edge-monel);
  --dt-tag-text: var(--tag-ink-dark);
  --dt-tag-sheen: inset 0 1px 2px rgba(255,255,255,0.60), inset 0 -2px 5px rgba(0,0,0,0.28);
  --dt-tag-emboss: 0 1px 0 rgba(255,255,255,0.32), 0 -1px 1px rgba(0,0,0,0.38);
}

/* Warm gold, WARM dark text. The one that failed and was changed: the gold I
   wanted had a darkest stop of #a5854a, which computes to 4.408 against this ink
   once the grain is composited, under the 4.5 floor. Darkening the ink to pure
   black would have passed at 5.49 but throws away the warmth that makes brass
   read as brass, so the gold was lightened instead, which also reads more like
   polished brass and less like unlacquered bronze. The fix improved the
   treatment. Worst case 5.13 to 1 on #a98953. */
.dt-tag-preview--brass_le {
  --dt-tag-fill: linear-gradient(135deg, var(--tag-brass-lt) 0%, var(--tag-brass-md) 30%, var(--tag-brass) 55%, var(--tag-brass-dk) 100%);
  --dt-tag-grain: repeating-linear-gradient(102deg, rgba(0,0,0,0.055) 0 1px, transparent 1px 3px);
  --dt-tag-edge: var(--tag-edge-brass);
  --dt-tag-text: var(--tag-ink-brass);
  --dt-tag-sheen: inset 0 1px 2px rgba(255,248,225,0.65), inset 0 -2px 5px rgba(70,45,0,0.30);
  --dt-tag-emboss: 0 1px 0 rgba(255,246,214,0.40), 0 -1px 1px rgba(60,40,0,0.40);
}

/* RED, single tag. This IS the medical alert tag, corrected with Don present
   2026-07-21: a medical alert tag is a single crimson tag. The older silver
   mirror mapping and the separate red_anodized two tag set were both retired in
   the same change, so red now belongs to exactly one style. Brushed, so it takes
   the same 1px repeating grain as the other brushed finishes, but WHITE grain,
   because the text is light and the invariant flips. Deep saturated anodic
   crimson rather than a bright signal red, which is what keeps light text clear
   of the floor. Single tag style, so only one preview ever renders for it. Worst
   case 6.44 to 1 on #952e32. */
.dt-tag-preview--medical_single {
  --dt-tag-fill: linear-gradient(135deg, var(--tag-red-lt) 0%, var(--tag-red-md) 30%, var(--tag-red) 55%, var(--tag-red-dk) 100%);
  --dt-tag-grain: repeating-linear-gradient(102deg, rgba(255,255,255,0.055) 0 1px, transparent 1px 3px);
  --dt-tag-edge: var(--tag-edge-red);
  --dt-tag-text: var(--tag-ink-light);
  --dt-tag-sheen: inset 0 1px 2px rgba(255,255,255,0.20), inset 0 -2px 6px rgba(0,0,0,0.45);
  --dt-tag-emboss: 0 1px 0 rgba(0,0,0,0.50), 0 -1px 1px rgba(255,255,255,0.18);
}

/* ---- The WWII notch --------------------------------------
   A pseudo element in the tag's own top padding band, NOT clip-path. Support was
   not the objection; clip-path is Baseline and needs no prefix on iOS. Three
   concrete things break instead. path() takes ABSOLUTE PIXELS only, no
   percentages and no calc, while this tag is fluid on both axes, so a px path
   would be correct at exactly one viewport. polygon() does take percentages, but
   it replaces the entire silhouette, and squaring off a 34px border-radius
   destroys the strongest visual cue that this is a dog tag. And clip-path clips
   the whole paint: the outer drop shadow is deleted outright, and the 2px border
   and inset sheen are sliced along the cut, because both follow the
   border-radius shape rather than the clip path. Restoring all three means
   rebuilding the tag's entire edge treatment to add one decorative notch.

   THE TRAP, and why top is 0 rather than -2px. .dt-tag-preview carries
   overflow-x: auto, and a non visible value on one axis forces the other to
   auto, so the element clips its descendants at the PADDING edge. A notch
   reaching up through the 2px top border would have that overhang clipped away
   and the border would survive unbroken above it, reading as a drilled hole
   rather than a bite. So it sits flush at the inside of the border and opens
   upward, and the remaining 2px of border above it reads as the rolled edge of
   the stock seen end on, which is what a real tag shows there.

   IT CANNOT MOVE THE LAYOUT. position: absolute takes it out of flex flow
   entirely, so it is not a flex item and contributes nothing to the container's
   content size: the fixed five line height is untouched. It cannot collide with
   text either, because it lives in the top padding band, above the content box,
   at any width. At a 390px viewport the font size resolves to 16px, so the notch
   spans y = 2px to 11.92px while the text box starts at y = 18px, clearing by
   6.08px; at the 1.3rem ceiling it spans 2px to 14.90px against a text box
   starting at 22.8px, clearing by 7.9px. Top RIGHT because the text is flush
   LEFT, so the right side is the only place a decorative element can never crowd
   the first character of line one, and 2.6em keeps it well clear of the 34px
   corner radius where it would look like a rendering fault. Every dimension is
   in em, so it scales with the clamp() type exactly as the tag does.

   ONE LINE OFF SWITCH: adding --dt-tag-notch: none to the rule above removes the
   pseudo element entirely. That is the line to change on the day a real
   photograph replaces the fill for this finish, since the photograph carries its
   own notch. */
.dt-tag-preview--notched_wwii::after {
  content: var(--dt-tag-notch, "");
  position: absolute;
  top: 0;
  right: 2.6em;
  width: 1.05em;
  height: 0.62em;
  background: var(--tag-notch-fill);
  border: 2px solid var(--dt-tag-edge);
  border-top: 0;
  border-radius: 0 0 0.55em 0.55em;
  box-shadow: inset 0 -2px 3px rgba(0,0,0,0.28);
}

/* ---- Checkboxes / radios / options ----------------------- */
.dt-options { display: flex; flex-direction: column; gap: 0.65rem; margin-bottom: 1.4rem; }

.dt-check {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  font-family: var(--font-display);
  font-size: 0.98rem;
  color: var(--ink);
  cursor: pointer;
  /* The label wraps the control AND its text, so the whole row is one target.
     44px matches the stepper directly beneath it, so the two halves of the same
     form cannot drift apart again. min-height, not height: the pickup option
     wraps to two lines at 390px and must simply stay taller. */
  min-height: 44px;
}
.dt-check input[type="checkbox"],
.dt-check input[type="radio"] {
  /* 24px is the WCAG 2.2 SC 2.5.8 floor for the CONTROL itself; 1.15rem was
     18.4px and 5.6px short. Absolute px, not rem, for the same reason the
     quantity input pins 16px: the floor is specified in CSS px and must not
     float with a future root font size. */
  width: 24px; height: 24px;
  accent-color: var(--od-green);
  cursor: pointer;
  flex: none;
}
.dt-check em { font-style: normal; color: var(--field-tan-dk); font-size: 0.9em; }

/* Quantity: label on the left, a touch stepper on the right. flex-wrap drops
   the stepper onto its own line when the label and the 188px group cannot both
   fit, which makes horizontal overflow impossible at any viewport without
   needing a width breakpoint. */
.dt-qty {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 0.7rem;
  font-family: var(--font-display);
  font-size: 0.98rem;
  color: var(--ink);
}
.dt-qty-label { flex: 1 1 auto; cursor: pointer; }

.dt-stepper {
  display: flex;
  align-items: stretch;
  flex: 0 0 auto;
  background: var(--bone);
  border: 1.5px solid var(--field-tan-dk);
}
.dt-stepper:focus-within { outline: 3px solid var(--od-green-lt); outline-offset: 1px; border-color: var(--od-green); }

/* 44x44 CSS px: the Apple HIG minimum and WCAG 2.5.5 AAA. */
.dt-step-btn {
  flex: none;
  width: 44px;
  min-height: 44px;
  padding: 0;
  font-family: var(--font-display);
  font-size: 1.25rem;
  font-weight: 600;
  line-height: 1;
  color: var(--od-green);
  background: transparent;
  border: none;
  cursor: pointer;
  user-select: none;
  -webkit-user-select: none;
  -webkit-tap-highlight-color: transparent;
  /* Kills the 300ms tap delay and stops rapid repeat taps triggering
     double tap zoom. */
  touch-action: manipulation;
}
.dt-step-btn:first-child { border-right: 1.5px solid var(--field-tan-dk); }
.dt-step-btn:last-child  { border-left: 1.5px solid var(--field-tan-dk); }
/* Matches aria-disabled, not :disabled. The buttons stay focusable at 1 and at
   20 so a real disabled attribute can never yank focus out from under a
   keyboard or switch user mid press. They still have to LOOK unavailable. */
.dt-step-btn[aria-disabled="true"] { opacity: 0.35; cursor: default; }
.dt-step-btn:focus-visible { outline: 3px solid var(--od-green-lt); outline-offset: -3px; }
/* Gated so the buttons do not keep a stuck hover state after a tap on iOS. */
@media (hover: hover) {
  .dt-step-btn:hover:not([aria-disabled="true"]) { background: rgba(61,74,42,0.08); }
}

.dt-qty input {
  width: 3.4rem;
  min-height: 44px;
  /* 16px absolute, NOT 1rem. iOS Safari zooms a focused input whose computed
     font size is under 16px. 1rem resolves to 16px today only because nothing
     sets a font size on :root, so an absolute value keeps this immune to any
     future root font size change. */
  font-size: 16px;
  text-align: center;
  border: none;
  background: transparent;
  padding: 0.6rem 0.25rem;
}
.dt-qty input:focus { outline: none; }

/* The limit note. Shown only while the typed text is outside 1 to 20, where the
   box and the line total would otherwise be showing two different numbers at
   once. flex-basis 100% drops it onto its own row under the stepper, so it never
   squeezes the label or pushes the group off a narrow screen. It is a live
   region that is always in the DOM, hence :empty rather than being mounted and
   unmounted; --rust is the existing stamp red, no new color. */
.dt-qty-note {
  flex: 1 1 100%;
  margin: 0;
  font-family: var(--font-display);
  font-size: 0.85rem;
  line-height: 1.35;
  color: var(--rust);
}
/* NOT display:none. That removes the node from the ACCESSIBILITY TREE, not just
   from view, so while idle the live region would not exist for assistive tech
   at all, and when the text arrived :empty would stop matching in the same
   commit and the region would enter the tree ALREADY populated. That is exactly
   the "inserted and filled in the same frame" case screen readers routinely
   miss, and exactly what the always mounted paragraph was added to prevent.
   A blind customer types 25, hears nothing, and is charged for 20.
   The visually hidden pattern keeps the node rendered and announced. Absolute
   positioning also takes it out of the flex flow, so an empty note contributes
   no row gap under the stepper and the layout is unchanged. */
.dt-qty-note:empty {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ---- Cart ------------------------------------------------ */
.dt-empty { color: var(--ink-soft); font-style: italic; }

.dt-cart { list-style: none; margin: 0 0 1.3rem; padding: 0; display: flex; flex-direction: column; gap: 0.6rem; }
.dt-cart-item {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 0.8rem;
  padding: 0.8rem 0.9rem;
  background: var(--bone);
  border-left: 4px solid var(--od-green);
  border-top: 1px solid var(--paper-line-lt);
  border-bottom: 1px solid var(--paper-line-lt);
}
.dt-cart-desc { display: flex; flex-direction: column; gap: 0.15rem; }
.dt-cart-desc strong { font-family: var(--font-display); font-weight: 600; }
.dt-cart-meta { font-family: var(--font-mono); font-size: 0.82rem; color: var(--ink-soft); letter-spacing: 0.03em; }
.dt-remove {
  font-family: var(--font-display);
  font-size: 1.3rem; line-height: 1;
  color: var(--rust);
  background: transparent;
  border: 1.5px solid transparent;
  width: 2rem; height: 2rem;
  cursor: pointer; flex: none;
}
.dt-remove:hover { border-color: var(--rust); background: rgba(139,58,34,0.08); }

.dt-delivery { display: block; }
.dt-delivery .dt-check { margin-bottom: 0.5rem; }

/* ---- Subtotal + fine print ------------------------------- */
.dt-subtotal {
  display: flex; justify-content: space-between; align-items: baseline;
  font-family: var(--font-display);
  text-transform: uppercase; letter-spacing: 0.08em;
  font-size: 1.05rem; font-weight: 600;
  color: var(--ink);
  border-top: 2px solid var(--paper-line);
  padding-top: 0.9rem;
  margin: 0.4rem 0 0.3rem;
}
.dt-subtotal-amt { font-size: 1.5rem; font-variant-numeric: tabular-nums; }
.dt-fineprint { font-size: 0.85rem; color: var(--ink-soft); margin: 0 0 1.2rem; }

/* The Turnstile iframe is a fixed 300px and cannot shrink. At a 375px viewport
   the panel leaves 298.4px (35.2px page gutters + 38.4px panel padding + 3px
   border = 76.6px of chrome), so iPhone SE 2, SE 3 and 13 mini overflow by
   about 1.6px and scroll the WHOLE page, since body has no overflow guard.
   The breakpoint below buys that width back. This contains whatever is left at
   the very narrow end, where padding cannot help: even at zero padding a 320px
   viewport leaves 281.8px against a 300px widget. Containing it here means the
   page never scrolls while every pixel of the gate stays reachable, unlike a
   body level clip, which would put about 18px of it permanently out of reach.
   Same pattern .dt-tag-preview already uses. */
.dt-turnstile { margin: 0 0 1rem; overflow-x: auto; }

/* ---- Buttons --------------------------------------------- */
.dt-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.7em;
  font-family: var(--font-display);
  font-size: 0.95rem;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  padding: 0.95em 1.7em 0.85em;
  background: var(--ink);
  color: var(--bone);
  border: 1.5px solid var(--ink);
  cursor: pointer;
  transition: background 0.2s ease, border-color 0.2s ease, transform 0.15s ease;
}
.dt-btn::after {
  content: "\2192";
  font-family: var(--font-mono);
  letter-spacing: 0;
  transition: transform 0.25s ease;
}
.dt-btn:hover { background: var(--od-green); border-color: var(--od-green); }
.dt-btn:hover::after { transform: translateX(4px); }
.dt-btn:focus-visible { outline: 3px solid var(--od-green-lt); outline-offset: 2px; }
.dt-btn:disabled { opacity: 0.55; cursor: wait; }

.dt-btn-add { background: var(--od-green); border-color: var(--od-green); }
.dt-btn-add:hover { background: var(--od-green-dk); border-color: var(--od-green-dk); }

.dt-btn-checkout { width: 100%; justify-content: center; font-size: 1.05rem; padding: 1.1em 1.7em 1em; }

/* ---- Error / footer -------------------------------------- */
.dt-error {
  font-family: var(--font-display);
  color: var(--rust);
  background: rgba(139,58,34,0.08);
  border-left: 4px solid var(--rust);
  padding: 0.7rem 0.9rem;
  margin: 0 0 1rem;
}

.dt-footer {
  text-align: center;
  margin-top: 2rem;
  padding-top: 1.4rem;
  border-top: 1px solid var(--paper-line-lt);
  font-size: 0.92rem;
  color: var(--ink-soft);
}
.dt-footer a { color: var(--od-green); font-weight: 600; }

/* ---- Success page ---------------------------------------- */
.dt-success { max-width: 640px; margin: clamp(2.5rem,10vw,5rem) auto; padding: 0 1.5rem; text-align: center; }
.dt-success h1 { font-family: var(--font-stencil); text-transform: uppercase; font-size: clamp(2.2rem, 7vw, 3.6rem); color: var(--od-green); margin: 0 0 1rem; }
.dt-success p { color: var(--ink-soft); }
.dt-success a { color: var(--od-green); font-weight: 600; }
/* The rule above is (0,1,1) and .dt-btn is only (0,1,0), so an anchor styled as
   a button would inherit od-green text on the near black .dt-btn fill and be
   unreadable. This is (0,2,0) so it wins, and it kills the anchor underline. */
.dt-success-actions { margin-top: 2rem; }
.dt-success .dt-btn,
.dt-success .dt-btn:hover { color: var(--bone); text-decoration: none; }
/* The label is long and .dt-btn adds 0.18em letter spacing plus 1.7em side
   padding, so on a 390px phone it would otherwise run past the viewport. Let it
   wrap and cap it at the container instead of trusting it to fit. */
.dt-success .dt-btn { max-width: 100%; white-space: normal; text-align: center; }

@media (prefers-reduced-motion: reduce) {
  .dt-btn, .dt-btn::after { transition: none; }
}

/* The 300px Turnstile iframe plus 76.6px of page and panel chrome needs a
   376.6px viewport. iPhone SE 2, SE 3 and 13 mini are 375. Trimming the panel
   gutter by 3.2px a side buys the 1.6px shortfall back with room to spare:
   375 - 35.2 - 3 - 32 = 304.8px available against 300px. The breakpoint sits at
   380px because the real threshold is 376.6px, so it catches 375, 360 and 320
   and leaves the 390px class of phones untouched. */
@media (max-width: 380px) {
  .dt-panel { padding-left: 1rem; padding-right: 1rem; }
}

/* ---- Static catalog section (server rendered, below the app) ----
   Read by humans who scroll and by every crawler that does not execute JS.
   Classes only: the CSP has no inline styles. */
.dt-static-info {
  max-width: 760px;
  margin: 56px auto 40px;
  padding: 0 20px 24px;
  font-family: 'Crimson Pro', Georgia, serif;
  font-size: 1.05rem;
  line-height: 1.6;
  color: #2a2a24;
}
.dt-static-info h2 {
  font-family: 'Oswald', Arial, sans-serif;
  text-transform: uppercase;
  letter-spacing: 1.5px;
  font-size: 1.05rem;
  color: #3D4A2A;
  margin: 30px 0 8px;
}
.dt-static-info h3 {
  font-family: 'Oswald', Arial, sans-serif;
  font-size: 1rem;
  margin: 16px 0 4px;
  color: #2a2a24;
}
.dt-static-info ul { padding-left: 22px; margin: 8px 0; }
.dt-static-info li { margin: 6px 0; }
.dt-static-info p { margin: 8px 0; }
.dt-static-info a { color: #3D4A2A; }
