/*
  Card faces — the agenda and galactic-event text laid out the way it reads on
  the physical card.

  ## Why this is its own file

  Two surfaces render a face and they do not share a stylesheet: the library
  extends `base.html` and links `app.css`, while `tv.html` deliberately extends
  nothing and carries its own inline `<style>` so a television loads one
  document with no chrome in it. Putting the faces in `app.css` would mean the
  TV could not use them; inlining them in `tv.html` would mean two copies. So:
  one file, linked by both.

  It therefore **defines its own colours** rather than reaching for `app.css`'s
  custom properties. A card face is not part of the app's dark chrome — it is a
  pale card sitting on top of it — and it has to look identical on a page that
  has never heard of `--bg-raised`.

  ## How it is sized

  Every measurement is a multiple of `--card-unit`, which the *caller* sets. The
  library sets it in `rem`; the TV sets it in `vh`. Nothing in here assumes a
  pixel size, a breakpoint or a container query — the last of those is tempting
  and was rejected, because the primary surface is a television browser and
  those are frequently several years behind.

  `--card-text-scale` is applied to the prose only, and is computed per card in
  `core/cardface.py` from its character count. The frame keeps its proportions
  at every scale: a wordy card must read as a full card with smaller type, not
  as a differently shaped card.

  ## Both faces are landscape

  The agenda template is portrait (0.649 at the trim) and this is not, which is
  deliberate. The face's first home is a television, where vertical space is the
  scarce one — a portrait card on a 27vh rail sets its text at about half the
  size a landscape card can. Widescreen also lets a FOR/AGAINST agenda put its
  two outcomes in two columns, which is both how you read the card and another
  step up in type size.

  So both faces use the galactic event's ratio, 2130 x 1243 at the trim. That
  they match is a second benefit: a rail carrying an event beside two agendas
  sets all three at the same size, with no card looking like a different object.

  ## No art, and measured at the trim

  The two PSDs carry bleed and crop marks; every proportion here is read from
  inside the cut lines, not from the full canvas. The templates give half the
  galactic-event face to a painting and put a starfield behind the agenda. This
  ships neither — the frames are gradients and `clip-path` following those
  templates in shape and colour, and the text is the part that has to be right.
  This is an unofficial companion app.
*/

/*
  Self-contained on purpose. The TV page carries no reset of its own, so a face
  cannot assume the host has set `border-box` — and without it the padding on a
  fixed-width frame fights its own `aspect-ratio`.
*/
.card-face,
.card-face *,
.card-face *::before,
.card-face *::after { box-sizing: border-box; }

.card-face {
  /* Fallback so a face is never invisible if a surface forgets to set one. */
  --card-unit: 0.5rem;
  --card-text-scale: 1;

  --card-ink: #0c1018;
  --card-ink-dim: #4a5666;
  --card-paper: #f6f9fc;
  --card-paper-edge: #cfdbe6;
  --card-void: #05070e;
  --card-yellow: #f3df3d;
  --card-cyan: #6ecff0;
  --card-green: #7ac943;

  position: relative;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  font-family: "Avenir Next Condensed", "Roboto Condensed", "Arial Narrow",
               system-ui, -apple-system, sans-serif;
  /* A face is a card: it never inherits the page's line height or colour. */
  line-height: 1.3;
  color: var(--card-ink);
  /*
    Cut corners rather than rounded ones — the galactic event template cuts all
    four at 45 degrees, and it is the detail that most makes a rectangle read as
    a TI4 card rather than as a panel.
  */
  clip-path: polygon(
    calc(var(--card-unit) * 1.6) 0, calc(100% - var(--card-unit) * 1.6) 0,
    100% calc(var(--card-unit) * 1.6), 100% calc(100% - var(--card-unit) * 1.6),
    calc(100% - var(--card-unit) * 1.6) 100%, calc(var(--card-unit) * 1.6) 100%,
    0 calc(100% - var(--card-unit) * 1.6), 0 calc(var(--card-unit) * 1.6));
}

/* --------------------------------------------------------------- agenda ---- */
/*
  Landscape — see the note at the top of the file. Keeps every mark that makes
  the template an agenda card: the black title banner with its bottom corners
  chamfered in yellow, the LAW / DIRECTIVE tab hanging into the chamfer, and the
  pale body panel over a faint circular emblem.
*/

.card-face-agenda {
  aspect-ratio: 2130 / 1243;
  width: calc(var(--card-unit) * 50);
  padding: calc(var(--card-unit) * 1.3);
  /*
    The starfield border, without a starfield: a deep navy ground with a cold
    blue bloom down each side, which is what the template's art actually reads
    as at card size.
  */
  background:
    radial-gradient(ellipse at 0% 45%, rgba(45, 130, 200, 0.55), transparent 55%),
    radial-gradient(ellipse at 100% 45%, rgba(45, 130, 200, 0.55), transparent 55%),
    linear-gradient(160deg, #0d1c33, #050a14 60%);
}

/*
  The banner and the tab are each a yellow shape with a black one nested inside
  it — that is where the template's yellow chevron edge comes from. The inner
  element repeats the outer's `clip-path` at a box shrunk by its padding, which
  leaves a near-uniform yellow rule along every angled cut.

  A pseudo-element would be tidier markup and does not work: an absolutely
  positioned child paints *after* its parent's own text, so the black fill would
  cover the title. Hence a real element.
*/
.card-banner,
.card-banner-fill {
  /* One polygon in one place, so the two shapes cannot drift apart. */
  clip-path: polygon(0 0, 100% 0, 100% 62%, 94% 100%, 6% 100%, 0 62%);
}
.card-banner {
  flex: 0 0 auto;
  background: var(--card-yellow);
  padding: 0 0 calc(var(--card-unit) * 0.28);
}
.card-banner-fill {
  background: var(--card-void);
  padding: calc(var(--card-unit) * 0.9) calc(var(--card-unit) * 3)
           calc(var(--card-unit) * 1.9);
}

.card-face-agenda .card-name {
  margin: 0;
  text-align: center;
  text-transform: uppercase;
  font-size: calc(var(--card-unit) * 2.7);
  font-weight: 700;
  letter-spacing: 0.02em;
  line-height: 1.05;
  /*
    The template's title is a cyan-to-white vertical gradient. `background-clip`
    is the only way to get it, and the `color` beneath it is the fallback for a
    browser that will not clip text — so the fallback is the readable end of the
    gradient, not the dark one.
  */
  color: #eaf6ff;
  background: linear-gradient(100deg, var(--card-cyan) 0%, #ffffff 62%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}

.card-tab,
.card-tab-fill {
  clip-path: polygon(0 0, 100% 0, 92% 100%, 8% 100%);
}
.card-tab {
  flex: 0 0 auto;
  align-self: center;
  /* Hangs into the banner's chamfer, and over the body panel's top edge. */
  margin-top: calc(var(--card-unit) * -1.5);
  position: relative;
  z-index: 2;
  min-width: 34%;
  background: var(--card-yellow);
  padding: 0 0 calc(var(--card-unit) * 0.28);
}
.card-tab-fill {
  display: block;
  background: var(--card-void);
  padding: calc(var(--card-unit) * 0.42) calc(var(--card-unit) * 3)
           calc(var(--card-unit) * 0.52);
  text-align: center;
  text-transform: uppercase;
  font-size: calc(var(--card-unit) * 1.45);
  font-weight: 700;
  letter-spacing: 0.09em;
  color: var(--card-yellow);
  line-height: 1.1;
}

.card-face-agenda .card-body {
  flex: 1 1 auto;
  min-height: 0;
  position: relative;
  overflow: hidden;
  margin-top: calc(var(--card-unit) * -1.2);
  padding: calc(var(--card-unit) * 2.2) calc(var(--card-unit) * 2)
           calc(var(--card-unit) * 1);
  /*
    A flat sheen rather than a radial one. A radial highlight in the middle of
    the panel lands concentric with the emblem behind it and the two together
    read as a bullseye pointed at the text.
  */
  background: linear-gradient(158deg, #ffffff, var(--card-paper) 46%,
                              var(--card-paper-edge) 100%);
  display: flex;
  flex-direction: column;
}

/*
  The template's watermark: a large, very pale ring device behind the text. Two
  rings and a glow, at an opacity where it reads as texture rather than as
  something you are meant to look at.
*/
.card-emblem {
  position: absolute;
  left: 50%;
  top: 50%;
  height: 132%;
  aspect-ratio: 1;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  /*
    Concentric rings rather than one: the template's device is a ring inside a
    ring and it is the repetition that reads as machinery. All of it very pale —
    at this opacity it is texture, not something anybody is meant to look at.
  */
  border: calc(var(--card-unit) * 0.5) solid rgba(94, 148, 196, 0.1);
  box-shadow:
    inset 0 0 0 calc(var(--card-unit) * 2.2) rgba(94, 148, 196, 0.035),
    inset 0 0 0 calc(var(--card-unit) * 2.6) rgba(94, 148, 196, 0.075),
    inset 0 0 0 calc(var(--card-unit) * 9) rgba(94, 148, 196, 0.03),
    inset 0 0 0 calc(var(--card-unit) * 9.4) rgba(94, 148, 196, 0.065);
  pointer-events: none;
}

/* ------------------------------------------------------ galactic event ---- */
/*
  Landscape, 2232 x 1347. Blue frame, a black title bar with an angled trailing
  edge, and the COMPLEXITY strip along the bottom right.
*/

.card-face-event {
  aspect-ratio: 2130 / 1243;
  width: calc(var(--card-unit) * 50);
  padding: calc(var(--card-unit) * 1.3);
  background:
    radial-gradient(ellipse at 8% 30%, rgba(70, 165, 235, 0.5), transparent 45%),
    radial-gradient(ellipse at 96% 70%, rgba(70, 165, 235, 0.42), transparent 45%),
    linear-gradient(150deg, #10315a, #061021 70%);
}

.card-face-event .card-titlebar {
  flex: 0 0 auto;
  width: 74%;
  background: var(--card-void);
  /*
    The template's angled trailing edge. Measured in `--card-unit` and not in
    `em`: nothing sets a font-size on the face itself, so an `em` here would
    resolve against whatever the host page happens to use for body text and the
    angle would change between the library and the television.
  */
  clip-path: polygon(0 0, 100% 0, calc(100% - var(--card-unit) * 2.6) 100%, 0 100%);
  padding: calc(var(--card-unit) * 0.7) calc(var(--card-unit) * 4)
           calc(var(--card-unit) * 0.7) calc(var(--card-unit) * 1.6);
}

.card-face-event .card-name {
  margin: 0;
  color: #ffffff;
  font-size: calc(var(--card-unit) * 2.1);
  font-weight: 600;
  letter-spacing: 0.01em;
  line-height: 1.1;
}

.card-face-event .card-body {
  flex: 1 1 auto;
  min-height: 0;
  position: relative;
  overflow: hidden;
  /*
    The generous bottom padding is not whitespace for its own sake: the panel's
    bottom-right corner is clipped away and text laid into that corner is simply
    cut in half. The padding keeps the prose out of it. Found by reading a
    galactic event on the television whose last line ended mid-word.
  */
  padding: calc(var(--card-unit) * 1.4) calc(var(--card-unit) * 1.6)
           calc(var(--card-unit) * 3.6);
  background: linear-gradient(135deg, #ffffff, var(--card-paper) 40%,
                              var(--card-paper-edge) 100%);
  /*
    Bottom-right corner cut away, and the complexity strip sits in the gap it
    leaves — on the frame, as the template has it. The cut has to be large
    enough to clear the whole strip: an undersized one puts a black bar half on
    the paper, which reads as a mistake rather than as part of the frame.
  */
  clip-path: polygon(0 0, 100% 0, 100% 72%, 74% 100%, 0 100%);
  display: flex;
  flex-direction: column;
}

/* ------------------------------------------------------------- prose ----- */
/*
  The only thing `--card-text-scale` touches. It multiplies a base that is
  already a multiple of `--card-unit`, so a face at any size shrinks its long
  cards by the same proportion.
*/

.card-prose {
  flex: 1 1 auto;
  min-height: 0;
  position: relative;
  z-index: 1;
  overflow: hidden;
  /*
    Centred vertically. The template top-aligns, but the template's card is
    portrait and mostly full; a short agenda on a landscape face top-aligned
    leaves a void that reads as a rendering fault rather than as a card.

    `safe center` is the important half: if a card ever does overflow, a plain
    `center` clips the *top* of the text, which is the worst possible place. The
    unprefixed value stays first as the fallback for browsers that drop the
    `safe` keyword.
  */
  display: flex;
  flex-direction: column;
  justify-content: center;
  justify-content: safe center;
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  font-size: calc(var(--card-unit) * 1.4 * var(--card-text-scale));
  font-weight: 600;
}

/* The seeded text carries meaningful paragraph breaks straight from the wiki. */
.card-prose p,
.card-vote-text { margin: 0 0 0.7em; white-space: pre-line; }
.card-vote-text { display: block; margin: 0; }
.card-prose p:last-child { margin-bottom: 0; }

.card-elect {
  color: var(--card-ink-dim);
  font-weight: 700;
}
.card-elect-label {
  text-transform: uppercase;
  letter-spacing: 0.09em;
  font-size: 0.8em;
  color: #8a6a1f;
  margin-right: 0.4em;
}

/*
  FOR and AGAINST, side by side. On a portrait card these are a hanging label on
  a stacked pair; with the width to spare they become two columns, each headed,
  which is how the outcomes are actually compared — and it roughly doubles the
  size the text can be set at.

  A vertical rule between them rather than a wide gap: the columns must not read
  as two separate cards.
*/
.card-votes {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.2em;
  margin-top: 0.6em;
}
.card-vote + .card-vote {
  padding-left: 1.2em;
  border-left: 1px solid rgba(12, 16, 24, 0.18);
}
.card-vote-label {
  display: block;
  margin-bottom: 0.15em;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  font-size: 0.8em;
  font-weight: 800;
  color: #8a6a1f;
}

/* --------------------------------------------------------------- foot ---- */

.card-foot {
  flex: 0 0 auto;
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: calc(var(--card-unit) * 0.8);
  margin-top: calc(var(--card-unit) * 0.8);
  font-size: calc(var(--card-unit) * 0.85);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--card-ink-dim);
}
.card-product { opacity: 0.85; }
.card-removed { color: #a2412f; font-weight: 700; }
.card-mark {
  margin-left: auto;
  font-size: calc(var(--card-unit) * 1.5);
  color: var(--card-ink);
  letter-spacing: 0;
}

/* The COMPLEXITY strip: three pips lit up to the wiki's own 1-3 rating. */
/*
  Spans the foot of the face so its two halves land on the two surfaces: the
  product at the left, in dark ink on the pale panel, and the complexity strip
  at the right, in the cut corner where the frame shows through.

  It does **not** take a light colour. An earlier version set the whole foot to
  white for the strip's sake and made the product invisible on the paper beside
  it — the strip carries its own colours, so the foot does not need to.
*/
.card-face-event .card-foot {
  position: absolute;
  left: calc(var(--card-unit) * 2.6);
  right: calc(var(--card-unit) * 1.3);
  bottom: calc(var(--card-unit) * 1.1);
  margin: 0;
}

.card-complexity {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: calc(var(--card-unit) * 0.35);
  background: var(--card-void);
  color: #ffffff;
  padding: calc(var(--card-unit) * 0.3) calc(var(--card-unit) * 0.7);
  border-radius: calc(var(--card-unit) * 0.25);
}
.card-complexity-label { margin-right: calc(var(--card-unit) * 0.3); }
.card-pip {
  width: calc(var(--card-unit) * 1.5);
  height: calc(var(--card-unit) * 0.72);
  border-radius: calc(var(--card-unit) * 0.18);
  background: #2b3140;
}
.card-pip-lit { background: var(--card-green); }

/* -------------------------------------------------------------- stamp ---- */
/*
  A decided card keeps its text — the room needs to know what the law says, not
  only that it passed — so the outcome is struck over the face rather than
  replacing it. Angled, translucent, and `pointer-events: none` so it can never
  swallow a click in the library.
*/
.card-stamp {
  position: absolute;
  /*
    Low and to the right, not across the middle. The prose is centred in the
    panel, so a stamp in the centre lands on the words — on a television that
    reads as a rendering fault, and on the one card it matters for it hides the
    sentence somebody is trying to check.
  */
  left: 70%;
  top: 80%;
  transform: translate(-50%, -50%) rotate(-11deg);
  padding: calc(var(--card-unit) * 0.4) calc(var(--card-unit) * 1.4);
  border: calc(var(--card-unit) * 0.35) solid rgba(162, 65, 47, 0.75);
  border-radius: calc(var(--card-unit) * 0.5);
  color: rgba(162, 65, 47, 0.85);
  font-size: calc(var(--card-unit) * 2);
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  white-space: nowrap;
  pointer-events: none;
}
