/* Shared by every poster family. Tokens are copied from the site stylesheet --
   posters and site must read as one identity, not two that nearly match. */
@import url('../fonts/fonts.css');

:root {
  --paper:     oklch(0.958 0.012 82);
  --paper-2:   oklch(0.928 0.016 80);
  --paper-3:   oklch(0.895 0.020 78);
  --ink:       oklch(0.185 0.018 60);
  --ink-2:     oklch(0.44  0.020 60);
  --accent:    oklch(0.575 0.185 38);
  --tri-blue:  oklch(0.44 0.14 258);
  --tri-red:   oklch(0.55 0.20 27);
  --tri-green: oklch(0.52 0.13 152);

  /* Type scales with the frame, so one template serves 800px and 4800px. */
  --u: 1vmin;
}

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

html, body { width: 100%; height: 100%; background: var(--paper); }

.poster {
  position: relative;
  width: 100vw;
  height: 100vh;
  overflow: hidden;
  background: var(--paper);
  color: var(--ink);
  font-family: 'Anek Devanagari', sans-serif;
  font-optical-sizing: auto;
  display: grid;
  grid-template-rows: 1fr auto;
}

.poster__bg {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  z-index: 0;
}

/* Grain as real material, per the v2 print thesis. 380-byte inline SVG, no
   network fetch, rasterised once. */
.poster::after {
  content: ''; position: absolute; inset: 0; z-index: 2; pointer-events: none;
  opacity: 0.20; mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='0.5'/%3E%3C/svg%3E");
  background-size: calc(20 * var(--u));
}

/* Default to a single column: a family template that reserves a second column
   for a photo (e.g. parichay's [data-photo] slot) must not leave a blank
   ~47%-of-frame hole when the renderer removes an absent photo. Widened only
   when an image slot is actually present. Plain-selector specificity (0,1,0
   for this rule, 0,2,0 for the :has() rule below) so a family's own
   `.poster__body:has(> [data-photo])` override -- same pattern, later in the
   cascade -- still wins; see parichay.html for the worked example. */
/* min-height: 0 here is half of the height-axis fix explained in full down
   by .poster__photo's min-height: 0 -- .poster__body is itself a grid item
   of .poster's outer `1fr auto` rows, and without this it can escape its
   1fr allocation the same way .poster__photo could escape its column. */
.poster__body { position: relative; z-index: 1; display: grid; grid-template-columns: 1fr; min-height: 0; }
.poster__body:has(> [data-photo]) { grid-template-columns: 1fr 1fr; }

/* --fit is the third instance of the silent-clipping failure mode the two
   `min-*: 0` fixes below already document, and the first one the type scale
   itself causes. --u is frame-relative (1vmin at :root), which says nothing
   about the width of the column the copy actually has to wrap inside: in
   parichay's two-column layout the text column is ~53% of the frame, so the
   headline that sets two lines at full width sets four in the column. At
   1080x1080 with the statutory notice present, ai-parichay-desk-sq's text block
   measured 1057px inside an 868px row, and the 189px of subhead that did not
   fit was painted over by the band (z-index 3 over this element's 1) rather
   than reflowed -- reported from a real render, and reproduced at 124.6px of
   the subhead hidden. The same copy fits at `story` (1670px row) and at sq
   without a photo (full-width column, two lines), so neither the copy nor the
   template alone is wrong: nothing was measuring the box.

   render.py::_fit_body picks the largest scale whose copy fits, once fonts have
   loaded and the row's real height is known. Scaling --u rather than any one
   font-size keeps every internal proportion (headline 11u, name 5.5u, subhead
   4u, the paddings and rules) exactly as drawn -- the block shrinks as a unit
   instead of relayouting. Re-pointed on .poster__body and never on .poster, for
   the same reason --ink-2 and --accent are further down: the statutory band is
   a sibling, and it must keep the frame's own vmin or its 13vh notice would
   scale with the body and stop covering the 12% of frame area the floor
   requires. Defaults to 1, so the 157 catalogue assets whose copy already fits
   render exactly as they did before this existed. */
.poster__body { --u: calc(1vmin * var(--fit, 1)); }

/* min-width: 0 overrides the grid default of `min-width: auto`, which for a
   replaced element resolves to its intrinsic width -- without it, a photo
   taller than it is wide (most portraits) forces its whole grid column, and
   with it the sibling [data-eci-label] footer that shares the same implicit
   grid column, wider than the 1080px frame. .poster's overflow:hidden then
   clips the excess, which is what silently cropped the seat number in the
   footer rather than the photo itself -- caught only by actually rendering a
   real photo, not by any unit test (see amendment-a-report.md). width: 100%
   (rather than auto) so the image fills its now-correctly-sized column, with
   object-fit doing the letterboxing.

   min-height: 0 is the same fix on the other axis, found while looking at
   Task 7's renders: base.css's own comment above promises "one template
   serves 800px and 4800px", but at the 4800x1200 flex-4x1 frame (short and
   very wide) a portrait photo's default min-height: auto let its
   aspect-ratio-derived height -- computed from the 100%-width column, which
   is itself wide relative to the 1200px frame -- inflate .poster__body's
   auto-sized row far past the viewport height. .poster's overflow:hidden
   then clipped everything below the visible band, which for uddharan.html
   silently dropped the entire quote text off-frame even though the
   rendered PNG's own dimensions were correct throughout -- a screenshot is
   always exactly the requested viewport size regardless of what got
   clipped inside it, so this was invisible to a dimensions-only test and
   only surfaced by actually looking at a wide-format render with a
   portrait photo supplied. Affects every two-column family that uses this
   default sizing (parichay, uddharan, sadasyata), not just the ones added
   in Task 7. */
.poster__photo {
  height: 100%; width: 100%; min-width: 0; min-height: 0;
  object-fit: contain; object-position: bottom center;
}

.headline {
  font-family: 'Rozha One', serif;
  font-size: calc(11 * var(--u));
  line-height: 1.06;
  text-wrap: balance;
  hanging-punctuation: first;
}

/* text-wrap: balance over `pretty` -- matches .headline's own choice above,
   avoids depending on `pretty`'s newer, less broadly landed heuristic, and is
   enough to stop a short trailing fragment like "(रामविलास)" from stranding
   itself on its own line in the narrowed two-column layout. */
.subhead { font-size: calc(4 * var(--u)); font-weight: 500; color: var(--ink-2); text-wrap: balance; }
/* .name reads as an attribution beneath the headline, not a third line of
   the slogan. A margin alone was tried first and rejected on review: at
   ~1/8th of the headline's font-size, with .name sharing .headline's heavy
   Rozha One mass and inherited var(--ink) colour, it still read as part of
   the slogan when actually rendered and looked at. Four things now carry the
   separation together: a materially larger, headline-proportional gap; the
   accent colour (in the spirit of .subhead's var(--ink-2), but distinct from
   it so .name still outranks .subhead); a lighter weight that stops matching
   .headline's mass; and a small divider rule (echoing parichay's own
   accent-coloured .parichay__rule) directly above the text. */
.name {
  font-size: calc(5.5 * var(--u)); font-weight: 600; color: var(--accent);
  margin-top: calc(3 * var(--u)); padding-top: calc(1.5 * var(--u));
  position: relative;
}
.name::before {
  content: ''; position: absolute; top: 0; left: 0;
  width: calc(6 * var(--u)); height: calc(0.35 * var(--u));
  background: var(--accent);
}
.numeral { font-family: 'Khand', sans-serif; font-weight: 600; }

/* Tricolour as a structural rule, never as page palette. */
.tricolour {
  height: calc(0.9 * var(--u));
  background: linear-gradient(90deg,
    var(--tri-blue) 0 33.33%, var(--tri-red) 33.33% 66.66%, var(--tri-green) 66.66%);
}

/* A supplied background is full-bleed photography under type that was drawn
   for paper. Without this the headline is near-black ink over a mid-tone
   photograph and a secondary line like shikayat's place name disappears into
   the road it is printed over -- both seen in the first AI-background render,
   not hypothesised. The scrim only engages when a background is actually
   present: render.py removes the [data-bg] element outright when the asset
   names no background, so :has(> .poster__bg) is exactly the test for it.

   Deliberately a gradient veil rather than a `filter` on .poster__bg itself,
   because filter does not compose -- this rule would silently replace the
   grayscale that the solemn register applies to the same element.

   Tokens are re-pointed on .poster__body, never on .poster: the statutory band
   is a sibling and paints var(--paper) on var(--ink), so redefining --ink at
   the poster level would leave the ECI notice light-on-light. */
.poster:has(> .poster__bg)::before {
  content: ''; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: linear-gradient(to bottom,
    oklch(0.15 0.012 60 / 0.62) 0%,
    oklch(0.15 0.012 60 / 0.28) 44%,
    oklch(0.15 0.012 60 / 0.70) 100%);
}
.poster:has(> .poster__bg) .poster__body {
  --ink-2: oklch(0.88 0.015 82);
  --accent: oklch(0.80 0.145 48);
  color: var(--paper);
  text-shadow: 0 calc(0.2 * var(--u)) calc(0.9 * var(--u)) oklch(0.14 0.010 60 / 0.55);
}

/* Condolence drops party colour entirely: branding on a death notice reads as
   campaigning off a bereavement. */
.poster[data-register='solemn'] { --accent: var(--ink-2); background: var(--paper); }
.poster[data-register='solemn'] .tricolour { display: none; }
.poster[data-register='solemn'] .poster__photo,
.poster[data-register='solemn'] .poster__bg { filter: grayscale(1); }
/* The footer band's [data-copy="target"] slot (partials/label.html's
   .eci__notice) is a catalogue-supplied campaign target line (e.g. "लक्ष्य
   2027") -- electoral ambition stated in words, which is worse on a
   condolence notice than the tricolour this register already strips: that
   required inferring intent from a colour, this says it outright. The seat
   number stays -- it identifies who is offering condolences, the same
   reasoning that keeps .name in the body. This selector's three classes/
   attributes (0,3,0) beat .eci__notice's bare one (0,1,0), so it wins on
   specificity regardless of the label partial's <style> block coming later
   in the document than base.css. */
.poster[data-register='solemn'] .eci__notice { display: none; }
/* With .eci__notice gone, .eci__row's justify-content: space-between has
   only one flex child left; a single flex item under space-between sits at
   the row's start, which stranded the seat number hard against the left
   edge on solemn posters (rendered and looked at). Centring it reads as a
   deliberate single-item footer rather than an orphaned one. */
.poster[data-register='solemn'] .eci__row { justify-content: center; }
