/* Art Immortal Tattoo — the Walk-In Board.
 *
 * Client-picked from six directions on 2026-09-05 (docs/design/
 * art-immortal-tattoo/DESIGN.md is normative; DIRECTIONS.md §C is the
 * original). A THEME rather than a custom template, on the operator's
 * constraint: "a custom design that uses the new section builder". The
 * precedent is black-lantern / delamort / twitchicide — palette, type and
 * shape carry the whole identity, over the SHARED section components.
 *
 * 🚨 Every rule here targets the REAL section markup
 * (`[data-theme] .slot[data-section=...]`), never invented utility classes.
 * twitchicide's first cut shipped `.tw-halftone` and friends as standalone
 * classes that ZERO components applied, so its entire visual identity was
 * inert. A theme can restyle markup the shared sections already emit; it
 * cannot introduce markup.
 *
 * The idea: the board on the counter. A studio with three shops and sixteen
 * artists is answering one question all day — who is working, and where —
 * so the page moves at the tempo of a shop with the door open, not a gallery
 * with the lights low. Warm off-white ground, white nav and bands, ink
 * rules, heavy condensed capitals.
 *
 * 🚨 THE GOLD IS SPLIT AND THE SPLIT IS THE RULE. --accent (#DCB96A) is a
 * SURFACE you could put your thumb on: chips, the lit board cell. It is
 * 1.9:1 on white and must never carry text. --accent-text (#856614) is the
 * same gold darkened for links and phone numbers. Gold under your finger,
 * dark gold in a sentence.
 *
 * 🚨 --accent-text is checked against BOTH grounds, because this site has
 * two. It was #8A6A14 until 2026-09-14 on a docblock claim of "5.1:1" that
 * was measured on white ONLY: on the warm ground (#F0EFEB) the same colour is
 * 4.39:1, under the 4.5 floor, which check-theme-a11y had been reporting as
 * serious x50. #856614 clears both (white 5.37, warm 4.67) and is a barely
 * perceptible darkening. Any future edit to this token must be measured
 * against #FFFFFF *and* #F0EFEB — the warm one is what fails first, and since
 * the 2026-09-18 swap it is the PAGE, not an occasional band, so a failure
 * there is now everywhere. Both are still on the page, so the pair of checks
 * is unchanged; only which is common has moved. Name the colours (--paper /
 * --warm), not the slots (--bg / --bg-mid), when recording a measurement.
 *
 * 🚨 Motion budget, in full: ONE continuous loop (the utility-bar ticker,
 * pausable on hover), entrance motion that fires once, feedback under 150ms.
 * No parallax, no Ken Burns, no video, no second marquee — the research
 * (MULTI-LOCATION-RESEARCH.md §3) found 1 of 10 studio sites honouring
 * reduced motion and none pausing a >5s loop, so this is where "tasteful"
 * is measurable rather than claimed.
 *
 * 🚨 No `:has()` and no `color-mix()` anywhere in this file. browserslist
 * pins `safari 12` for the in-studio kiosk iPads; both would fail silently
 * there, and a black screen on a lobby iPad is how that pin was earned.
 */

@layer theme {
  [data-theme="art-immortal"] {
    /* 🚨 TWO GROUNDS, named by WHAT THEY ARE rather than by which one is
       currently the page. They traded places on 2026-09-18 (operator: *"swap
       the background colors so the nav bar is the white and content off
       white"*) — the nav and the alternating band now take the white, and the
       page itself takes the warm. The recipe in frameworks.css alternates --bg
       and --bg-mid, so swapping this pair moved every section at once.
       🚨 --bg / --bg-mid hold the LITERALS because tokens/themes.json is the
       registry for them and build-tokens --check compares the two; swap the
       values in BOTH or the guard fails. --paper / --warm are this file's own
       names for the same two colours, so a rule downstream can say which
       COLOUR it wants rather than which slot — which is what kept the footer
       and the board hover unchanged through the swap. */
    --bg: #F0EFEB;
    --bg-mid: #FFFFFF;
    /* Captured BY REFERENCE, which is what makes them usable inside the footer
       block below: a custom property substitutes its var() on the element that
       declares it, so these hold the ROOT's two grounds even after the footer
       re-points --bg at the ink. Same trick as --ink. No new literals — these
       name the two colours already above, they do not restate them. */
    --paper: var(--bg-mid);
    --warm: var(--bg);
    /* Captured by reference so the footer can swap them: a custom property
       resolves its var() on the element that declares it, so this inherits as
       the resolved ink, not as a live alias. */
    --ink: var(--text);
    --text: #0B0B0B;
    --accent: #DCB96A;
    --accent-text: #856614;
    --muted: #4A4A4A;
    --rule: #0B0B0B;

    --font-display: 'Archivo Black', Impact, 'Arial Black', sans-serif;
    --font-body: 'Rubik', system-ui, sans-serif;

    /* Square, heavy, board lettering. Archivo Black has one weight and needs
       no tracking to shout; the button carries a little for legibility at
       small caps sizes. */
    --btn-transform: uppercase;
    --btn-tracking: 0.06em;
    --btn-weight: 700;
    --btn-radius: 0;
  }

  /* Display: all-caps, tight, no tracking. A board's lettering, not a
     fashion logotype. `balance` keeps two-line headings from orphaning. */
  [data-theme="art-immortal"] :is(h1, h2, h3) {
    font-family: var(--font-display);
    text-transform: uppercase;
    letter-spacing: -0.01em;
    line-height: 0.95;
    text-wrap: balance;
  }

  /* Every rule on this site is ink, full strength — no grey hairlines. The
     4px rule under a section head is the board's own edge.
     🚨 DESCENDANT, not `>`. Each variant wraps its own head — the roster's
     h2 sits at `.slot > .roster-square-ig > .roster-square-ig__head > h2` —
     so a direct-child selector matches NOTHING and the theme ships inert.
     Verified against the real rendered markup, not assumed. */
  [data-theme="art-immortal"] .slot[data-section] h2 {
    border-bottom: 4px solid var(--rule);
    padding-bottom: 0.4em;
  }

  /* The address ticker. ONE continuous motion on the page, and the only
     marquee: three shops' NAP as a single line, paused on hover so a reader
     can catch an address (WCAG 2.2.2 wants a stop for anything over 5s —
     the visible control lives in the utility-bar variant's own markup). */
  [data-theme="art-immortal"] .slot[data-section="utility-bar"] {
    background: var(--text);
    color: var(--bg);
    font-family: var(--font-display);
    font-size: 0.8rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
  }
  [data-theme="art-immortal"] .slot[data-section="utility-bar"] a {
    color: var(--bg);
  }

  /* Gallery: full density, captions ALWAYS on. The work is the point and a
     hover-revealed caption is a caption nobody reads. */
  [data-theme="art-immortal"] .slot[data-section="gallery"] figcaption {
    background: var(--text);
    color: var(--bg);
    font-weight: 700;
    font-size: 0.8rem;
    opacity: 1;
  }

  /* The roster is the signature, and Roster J (the walk-in board) is the
     variant that carries it: rows separated by ink, the shop row by the same
     4px rule the headings wear, and a hovered row taking the warm ground so
     the eye can track across to the shop columns.

     🚨 Every line here is a CUSTOM PROPERTY, not a restated declaration, and
     that is not a style preference. sections.css lives in `@layer section` —
     the last layer — so it outranks this file whatever the selector, and a
     theme rule that restates `border-bottom` or `width` on board markup is
     INERT. Measured 2026-09-06: an earlier cut of this block asked for a 4px
     head rule and a 16px mark and the page rendered 2px and 13px, with nothing
     failing to say so. That is the same class of silent nothing twitchicide
     shipped with `.tw-halftone`. The knobs are declared once by the shared
     block as `var(--board-*, fallback)` and never set there, so what is below
     is the only declaration in play and inherits straight down. */
  [data-theme="art-immortal"] {
    --board-head-rule: 4px;
    --board-row-rule: 2px;
    --board-mark-size: 16px;
    --board-mark-rule: 2px;
    /* The hovered row lifts to the OTHER ground. That used to be the warm
       band on a white page; since the 2026-09-18 swap the page is the warm
       one, so the lift is to white. Pointed at --paper rather than --bg-mid
       so it says which colour it wants instead of which slot. */
    --board-row-hover: var(--paper);
    /* Square faces and a squarer phone: no radius anywhere on this site. */
    --board-face-radius: 0;
    --board-phone-radius: 4px;
    /* Shop pills in the utility bar: square and hard-ruled, same as every
       other chip on this site. */
    --ubshops-radius: 0;
    --ubshops-rule: 2px;
  }

  /* Interior pages (artist profile, shop pages, image detail) are styled by
     interior.css, which is UNLAYERED — it beats this file at any specificity,
     same as sections.css above. Knobs only. */
  [data-theme="art-immortal"] {
    --ti-chip-radius: 0;      /* no radius anywhere on this site */
    --ti-facts-rule: 2px;
    --ti-shop-rule: 2px;
  }
  /* interior.css paints the primary button `background: var(--accent);
     color: var(--bg)` — white on the surface gold, 1.9:1, which is exactly
     the pairing the split-gold rule forbids. Re-pointing --accent on the
     button itself makes it the ink block every other button on this site
     is, with the page's white text on it. */
  [data-theme="art-immortal"] .ti-btn--primary {
    --accent: var(--text);
  }

  /* Buttons are square blocks of ink, or gold you could press. No radius
     anywhere on this site. */
  [data-theme="art-immortal"] .btn-primary {
    background: var(--text);
    color: var(--bg);
    border: 0;
  }
  [data-theme="art-immortal"] .btn-secondary {
    background: var(--accent);
    color: var(--text);
    border: 0;
  }

  /* Links are the DARK gold, never the surface gold. */
  [data-theme="art-immortal"] :is(p, li, address, dd) a {
    color: var(--accent-text);
    font-weight: 600;
  }

  /* Footer: reversed, the three shops side by side. */
  [data-theme="art-immortal"] .slot[data-section="footer"] {
    /* Paper and ink swap places, and they swap as TOKENS, because every
       shared footer rule reads `var(--text)` / `var(--muted)` for its copy
       and links and those rules outrank this file. Measured 2026-09-06 with
       only `background`/`color` set here: the address and the "Also in"
       shop links rendered ink-on-ink, invisible but for their gold underline.
       Re-declared on the footer, the tokens inherit into every rule that
       reads them. --paper/--ink are held apart so the swap can reference the
       originals after they are overwritten. */
    --text: var(--paper);
    /* The warm off-white, named directly: it was --bg-mid until the grounds
       swapped on 2026-09-18, and following that alias would have made the
       footer's muted copy BRIGHTER than its body copy. */
    --muted: var(--warm);
    --bg: var(--ink);
    --rule: var(--paper);
    --accent-text: var(--accent);
    background: var(--ink);
    color: var(--paper);
  }
  /* Gold stays a SURFACE even here. On the ink footer the gold would in fact
     pass as text (10.5:1), but the platform's rule is that --accent never
     sits in a `color:` position (check-css-vocab, R-8b) — and honouring it
     lands somewhere truer to this theme anyway: the link is the page's white,
     underlined in gold you could put your thumb on. */
  [data-theme="art-immortal"] .slot[data-section="footer"] a {
    color: var(--bg);
    border-bottom: 2px solid var(--accent);
    text-decoration: none;
    padding-bottom: 1px;
  }

  /* Entrance motion fires ONCE and only from an already-visible state, so a
     reader who lands mid-page never meets an invisible section. Reduced
     motion removes it outright — the page is complete without it. */
  @media (prefers-reduced-motion: reduce) {
    [data-theme="art-immortal"] .slot[data-section] {
      animation: none !important;
    }
  }
}

/* 🚨 UNLAYERED for the same reason as the page-header rule below: these
   headings are painted by sections.css, which lives in `@layer section` —
   the LAST layer — so it outranks `@layer theme` at any specificity and the
   `:is(h1, h2, h3)` block above cannot reach them. That is the inert-theme-
   rule trap this file documents twice. Unlayered beats every layer, so this
   needs no specificity games.

   WHY: Archivo Black ships ONE weight. Every heading asking for 500, 600 or
   700 gets a browser-synthesized faux-bold — a smear on a letterform that is
   already black, and thicker strokes on some headings than others for no
   reason a reader could name. Measured live on the home page before this:
   the gallery head rendered 600, the consult head 500 and the FAQ head 500,
   while the hero, roster and shops heads rendered a true 400.

   Scoped to h1-h3 to match the display rule above — the range actually
   measured — and to this theme, so no other tenant's headings move. */
[data-theme="art-immortal"] :is(h1, h2, h3) {
  font-weight: 400;
}

/* 🚨 The top of an interior page, where TWO paddings were stacking.
   Measured live on /piercing at 1440px: from the breadcrumb to the first
   line of content was **144px of nothing**, and on /faq the same 144px.
   It is two separate reserves, neither of which knows about the other:

   1. PageHeader's bannerless content padding, 88px top / 48px bottom. The
      88px exists to clear a transparent nav that OVERLAYS the header. This
      theme's nav is solid and sits above it (the header starts at y=126, the
      nav's own height), so those 88px clear nothing.
   2. The first section's own `--section-pad`, 96px top, applied directly
      under that.

   🚨 The section's padding is an INLINE style — `padding: var(--section-pad,
   40px 24px 64px)` written on the element — so no stylesheet rule can beat
   it and no CSS guard in this repo can see it (the bypass family documented
   for app/area/[location]/page.tsx). But it READS A TOKEN, and the token is
   not inline: setting `--section-pad` on that same element from CSS is
   enough, because the inline declaration resolves its var() against whatever
   `--section-pad` has cascaded to there. Re-point the token, never try to
   out-specify the padding.

   Set on `.tn-page-header + section` so it reaches only the FIRST section,
   the one sitting under the header — every later section keeps the page's
   96px rhythm. Measured after: /piercing 144 -> 60px at 1440 and 128 -> 44px
   at 390; /faq 144 -> 60px. `/artists` and `/gallery` draw `.ti-title`
   instead of PageHeader and are untouched, which is the intent. */
/* 🚨 The page header is CENTRED on the same column as the body, and this is
   the whitespace complaint that two rounds of vertical trimming could not
   touch (operator, 2026-09-18: "You see the extra weight space here, right???").
   The gap was HORIZONTAL. Measured at 1684 there were THREE grids stacked on
   one page: the nav full-bleed with 56px of padding, the page header pinned
   LEFT at max-width 1200 with 88px of padding so its title began at x=88, and
   the body a 1040px CENTRED column beginning at x=322. A 234px step between a
   page's own title and everything under it, and 484px of dead space to the
   right of the header.
   Centring it — and widening the piercing body to the same 1200 — puts the
   eyebrow, the title, the breadcrumb and the reel on one left edge. 1248 is
   1200 of column plus the 24px gutter, so the INNER text lands exactly where
   the body does, and below 1248 it degrades to full width with that gutter. */
[data-theme="art-immortal"] .tn-page-header:not([data-banner="1"]) .tn-page-header__content {
  padding-top: 18px;
  padding-bottom: 10px;
  padding-left: 24px;
  padding-right: 24px;
  max-width: 1248px;
  margin-left: auto;
  margin-right: auto;
}
/* 🚨 Four separate reserves stack between the nav and the first section, and
   only shaving all four moves anything (operator, 2026-09-18, twice: "tighten
   up the white space", then "still whitespace"). Measured at 1676 before this:
   header padding 26 + eyebrow margin 16 + crumb margin 24 + a crumb ROW that
   is 52px tall + header padding 18 + section padding 16 = the reel starting at
   y=357 with ~180px of it being type.
   The crumb row is the surprising one: its <nav> is 20px, but the link inside
   is a 40px tap target that overhangs the row by 10px at each end, so the
   flex line measures 52. That padding is NOT reduced — it is the WCAG target
   and the same block interior.css protects on phones — the MARGIN above it is,
   since a 24px gap over a control that already carries 10px of its own is
   spacing paid twice. */
[data-theme="art-immortal"] .tn-page-header__eyebrow { margin-bottom: 10px; }
[data-theme="art-immortal"] .tn-page-header__crumbs { margin-top: 8px; }
[data-theme="art-immortal"] .tn-page-header + section {
  --section-pad: 8px 24px 96px;
}
@media (max-width: 720px) {
  [data-theme="art-immortal"] .tn-page-header:not([data-banner="1"]) .tn-page-header__content {
    padding-top: 28px;
    padding-bottom: 20px;
  }
  [data-theme="art-immortal"] .tn-page-header + section {
    --section-pad: 24px 24px 64px;
  }
}

/* 🚨 OUTSIDE `@layer theme` DELIBERATELY, and that is the only way this rule
   can work. interior.css is UNLAYERED (see the knobs note above), and an
   unlayered declaration beats every layered one whatever the selector — so
   the same rule inside the block above would be inert.

   🚨 AND THE SELECTOR IS COMPOUND, NOT DESCENDANT. ThemeShell puts
   `data-hero-slim` on the SAME element as `data-theme` (measured live:
   `div[data-theme=art-immortal][data-hero-slim=editorial]`), so
   `[data-theme="art-immortal"] [data-hero-slim] .tn-page-header__title`
   matches NOTHING. That shipped once: the rule's other selector still
   applied, so the page took the font-weight and kept the old font-size, and
   the half-landing read as a cache problem rather than a dead selector.
   Chrome's `matchingSelectors: [0]` is what named it. Being unlayered,
   specificity decides against interior.css's own
   `[data-hero-slim] .tn-page-header__title` (0,2,0) — and a bare
   `[data-theme="art-immortal"] .tn-page-header__title` is (0,2,0) too, an
   exact tie that interior.css wins on source order because it loads second.
   The compound form is (0,3,0) and wins outright.

   Scoped to this theme: no other tenant's header moves.

   WHY: the shared PageHeader's slim interior hero and the piercing page's
   own section heading are on the SAME clamp slope — `clamp(24px, 3.2vw,
   38px)` and `clamp(22px, 3.2vw, 32px)` — so they track each other at every
   width and the page title can never pull away from the headings beneath it.
   Measured live at 1440px: title 38px over four 32px headings, a 1.19 ratio,
   while this site's OWN interior pages run their title at 46px
   (`.ti-title`, /artists and /gallery), /about at 48 and a shop hero at 76.
   The two pages on the platform header (/piercing, /faq) were the only ones
   off the ladder.

   So the title joins `.ti-title`'s rung — same clamp, same line-height — and
   the ladder reads 76 shop hero / 46-48 page title / 32 section heading,
   under the home page's 80. Nothing else moves.

   Weight is 400 because Archivo Black ships ONE weight (noted at the top of
   this file): 600 asked for a face that does not exist and got a synthesized
   faux-bold, smearing a letterform that is already black. The home hero and
   every `.ti-title` on this site render 400. */
[data-theme="art-immortal"] .tn-page-header__title {
  font-size: clamp(28px, 5vw, 46px);
  font-weight: 400;
  line-height: 1.05;
}
/* The live shape today — both attributes on the ThemeShell div. */
[data-theme="art-immortal"][data-hero-slim] .tn-page-header__title {
  font-size: clamp(28px, 5vw, 46px);
  font-weight: 400;
  line-height: 1.05;
}
/* Kept for the day the slim marker moves onto an inner wrapper: same weight
   of selector, so neither can strand the other. */
[data-theme="art-immortal"] [data-hero-slim] .tn-page-header__title {
  font-size: clamp(28px, 5vw, 46px);
  font-weight: 400;
  line-height: 1.05;
}

/* =====================================================================
   PHONE: the utility bar names the SHOP, not the number.

   Operator, 2026-09-14, looking at a 390px screen: "the utility bar up top
   should just show the location without the phone#". Measured before: each
   pill carried city + state + a 14-character phone, and the row scrolls
   sideways — so the number was costing about half of every pill's width to
   say something the shop page, the footer and the Contact page all already
   say, on the one surface with the least room to say it.

   Same mechanism and the same breakpoint the STREET already uses two rules
   up in sections.css, deliberately: `@container` there, `@container` here,
   so the two mobile omissions cannot drift to different widths. On a browser
   with no container queries neither rule applies, which is the behaviour
   today.

   The tel is its own element with a flex `gap`, so hiding it leaves no
   dangling separator. Tap-to-call survives on /locations/{slug}, the footer
   and /contact.
   ===================================================================== */
@container (max-width: 768px) {
  [data-theme="art-immortal"] [data-section="utility-bar"] .ub-shops__tel {
    display: none;
  }
  /* 🚨 And the pills go edge to edge, which is only possible BECAUSE the
     number left. Operator, 2026-09-14: "Locations should be left and right
     justified." With the phone numbers gone the three pills stopped filling
     the row and clustered against the left with dead space after them —
     measured 57px of it at 390 and 97px at 430, against a 16px gutter on the
     left. `space-between` pins the first to the left gutter and the last to
     the right one: measured 57 -> 16 and 97 -> 16, matching the list's own
     padding on both sides.

     Safe when the row DOES overflow — a studio with five shops has no free
     space, so `space-between` behaves exactly as `flex-start` and the strip
     scrolls as before, keeping its scroll-snap and its 16px scroll padding.

     Desktop is untouched: above this breakpoint the list is `space-evenly`
     and already centred (measured 17px each side at 1440, unchanged). */
  [data-theme="art-immortal"] [data-section="utility-bar"] .ub-shops__list {
    justify-content: space-between;
  }
}

/* =====================================================================
   THE WALK-INS SIGN: room to breathe, a heavier rule, and lift.

   Operator, 2026-09-14: "Give the walk in a little breathing room and then
   make it a little thicker. Give it a little bit more maybe a drop shadow."
   Measured before: 4.8px / 8.8px of padding inside a 3px rule, sitting 8px
   under the subtitle — so it read as a caption crowded against the paragraph
   rather than a sign hung above the two buttons it labels.

   🚨 The shadow is a HARD OFFSET first and an ambient blur second, in that
   order. This theme has no radius anywhere and its whole grammar is ink
   rules and flat blocks; a soft-only drop shadow reads as a generic card and
   fights that. Offset ink is a printed sign lifted off the wall, which is
   what the stamp already is.

   Colours are literal rgba because these are TRANSLUCENT ink, and the theme's
   own `--ink` cannot be used inside rgba() — `color-mix()` would be the tool
   and it is banned here by the `safari 12` kiosk pin (see the top of this
   file). The values are the page's own #0B0B0B at low alpha.
   ===================================================================== */
[data-theme="art-immortal"] [data-section="hero"][data-variant="o"] .hero-statement__stamp {
  padding: 0.62rem 1rem;
  border-width: 4px;
  font-size: 0.78rem;
  letter-spacing: 0.08em;
  box-shadow: 5px 6px 0 rgba(11, 11, 11, 0.08), 0 9px 18px rgba(11, 11, 11, 0.10);
}
/* Breathing room above AND below, carried by the stamp's own margin rather
   than the act wrapper's.
   🚨 `margin-top` on `.hero-statement__act` was the obvious place and it is
   wrong: measured, 1.5rem there made the phone better (8 -> 12px under the
   subtitle) and the DESKTOP worse (18 -> 11px), because the text column
   already spaces that wrapper and the margin is partly absorbed. Moving the
   space onto the stamp adds on both.
   🚨 The bottom value looks large because the sign is ROTATED: -4deg on a
   full-width block adds ~12px to its bounding box, so 18px of margin rendered
   as a 6px visual gap above the buttons. 26px measures 13-14px, which is the
   gap that actually reads.
   Raised again 2026-09-14 — the first pass measured 18/14 on a phone and the
   operator's answer was still "it needs a little breathing room". Doubled to
   38/34, which is where the sign stops reading as wedged between the
   paragraph and the button stack. Deliberately NOT more: the whole point of
   the act wrapper is that this is a LABEL for the two buttons under it (see
   the sections.css note), and past roughly this it floats free of them.

   Measured after — sub -> stamp / stamp -> button: 38/34 at 390px,
   49/33 at 1440px. */
[data-theme="art-immortal"] [data-section="hero"][data-variant="o"] .hero-statement__act .hero-statement__stamp {
  margin: 30px 0 46px;
}
/* Now that the sign is a link on this studio, it has to say so on hover —
   within the theme's stated motion budget: "feedback under 150ms", no
   transform that moves layout. The shadow tightens and the rule fills in,
   which reads as the sign being pressed toward the page. */
[data-theme="art-immortal"] [data-section="hero"][data-variant="o"] a.hero-statement__stamp {
  transition: box-shadow 0.14s ease-out, background-color 0.14s ease-out;
}
[data-theme="art-immortal"] [data-section="hero"][data-variant="o"] a.hero-statement__stamp:hover {
  background: var(--bg-mid);
  box-shadow: 2px 3px 0 rgba(11, 11, 11, 0.10), 0 4px 10px rgba(11, 11, 11, 0.10);
}
@media (prefers-reduced-motion: reduce) {
  [data-theme="art-immortal"] [data-section="hero"][data-variant="o"] a.hero-statement__stamp {
    transition: none;
  }
}

/* ---------------------------------------------------------------------
   THE SIGN LIGHTS UP WHILE A DOOR IS OPEN.

   Operator, 2026-09-19: "We want the Walk-in welcome tilted sign to be
   lighting up during business hours."

   🚨 `--accent` (#DCB96A) is the theme's SURFACE gold — 1.9:1 on white, and
   it must never carry text (check-css-vocab R-8b). Lit, it is the FACE of
   the sign, with the page's own ink on top: gold under your finger, exactly
   the "lit board cell" the theme's own header names. The dark gold
   (--accent-text) stays on the rule, so the outline still reads.

   🚨 NO PULSE, and this is the theme's stated budget rather than taste: ONE
   continuous loop on the page, and the utility-bar ticker already has it. A
   sign that breathes would be the second, would run on every visit for as
   long as the shop is open, and would be the one thing on the page that
   cannot be paused.

   🚨 The light NEVER runs on its own — OpenSign always renders the "Open now"
   phrase beside the operator's wording, so a state carried by gold is also
   carried by words. See sections.css and lib/open-now.ts.

   The shadow warms with the face: the hard ink offset stays (this theme has
   no radius and no soft cards) and an ambient gold sits under it, which is
   what a lit sign does to the wall behind it. Literal rgba because these are
   translucent inks and color-mix() is banned by the safari 12 kiosk pin.
   --------------------------------------------------------------------- */
[data-theme="art-immortal"] [data-section="hero"][data-variant="o"] .hero-statement__stamp[data-open="open"] {
  background: var(--accent);
  color: var(--ink);
  box-shadow: 5px 6px 0 rgba(11, 11, 11, 0.08), 0 10px 24px rgba(220, 185, 106, 0.55);
}
[data-theme="art-immortal"] [data-section="hero"][data-variant="o"] a.hero-statement__stamp[data-open="open"]:hover {
  background: var(--accent);
  box-shadow: 2px 3px 0 rgba(11, 11, 11, 0.10), 0 5px 14px rgba(220, 185, 106, 0.55);
}
[data-theme="art-immortal"] [data-section="hero"][data-variant="o"] .hero-statement__stamp-open {
  /* Set apart from the operator's own wording without a second colour: the
     face is already gold, so a second hue here would be a third thing to
     read. Letterspacing and the separator do the work. */
  letter-spacing: 0.12em;
}

/* =====================================================================
   GALLERY DETAIL: tighten the run-up to the photograph.

   Operator, 2026-09-14: "tighten the gallery detail hero section up."
   Measured live at 1440 before this, breadcrumb to the top of the image:
   283px of chrome — crumbs (20 + 20 margin), header (82 + 22), the Contact
   row (8 + 49 + 24) and the top pager (55 + 12) — on a page whose entire
   subject is one photograph.

   Every cut here is a MARGIN. Nothing structural moves and nothing is
   removed: the top pager stays (it was asked for on 2026-09-07, because on
   a phone the image fills the screen and the bottom pager is a full scroll
   away), and the compact pager's own link box stays at its 44px touch
   target from the 2026-09-07 tap-target audit — only its trailing padding
   comes in.

   Measured after: 283 -> 243px at 1440, and 107 -> 91px at 390, where the
   figure already renders FIRST (interior.css reorders the detail page on a
   phone, so the "hero" there is the photograph and this is the run-up to
   it rather than to the title).
   ===================================================================== */
[data-theme="art-immortal"] .ti-image-detail { padding-top: 18px; }
[data-theme="art-immortal"] .ti-image-detail > .ti-crumbs { margin-bottom: 12px; }
[data-theme="art-immortal"] .ti-image-detail > .ti-header { margin-bottom: 12px; }
[data-theme="art-immortal"] .ti-image-detail .ti-title { margin-bottom: 6px; }
[data-theme="art-immortal"] .ti-image-detail > .ti-actions { margin: 0 0 14px; }
[data-theme="art-immortal"] .ti-image-detail > .ti-pager-top { margin-bottom: 8px; }
[data-theme="art-immortal"] .ti-image-detail .ti-pager--compact { padding-bottom: 6px; }
