﻿/* ============================================================
   SKINS
   A skin is pure CSS. MainLayout puts one class on the layout
   root (see PtSkin.CssClass) and nothing else in the app knows
   which skin is active. "Classic" is the absence of a skin --
   it deliberately has no rules here, so it renders exactly as
   it always has.

   Loaded LAST in App.razor so these rules win specificity ties
   against the components' own isolated CSS.
   ============================================================ */

/* ============================================================
   skin-evidencewall -- "The Evidence Wall"
   A detective's corkboard: pinned index cards, typewriter type,
   rubber-stamped roles, Intrigue tallied in red pencil.
   ============================================================ */

.skin-evidencewall{
  --cork:      #8a6134;
  --cork-dk:   #5e3f1f;
  --cork-lt:   #a9793f;
  --card:      #f4efe2;
  --card-2:    #e6dfcd;
  --card-ink:  #2b2620;
  --pencil:    #b3231f;
  --stamp-g:   #2f6b40;
  --stamp-r:   #a81f22;
  --manila:    #d9b878;
  --manila-dk: #b8934f;

  --type: "Special Elite", "Courier New", monospace;
  --mono: "Courier Prime", "Courier New", monospace;

  --grain: 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.75' numOctaves='4'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");

}

/* ============================================================
   GAMEPLAY ONLY
   The skin dresses the BOARD, not the site. Everything that
   paints the page itself is gated on .pt-screen -- the gameplay
   root -- so the room list, the words page, settings, connect
   and the lobby all stay Classic. The rules further down need no
   gate: they target pt-* elements that exist only during a game.
   ============================================================ */
.skin-evidencewall:has(.pt-screen){
  min-height:100vh;
  color:#f4efe2;
  /* cork: speckle + fibre + a pool of desk-lamp light */
  background-color:var(--cork);
  background-image:
    radial-gradient(circle at 20% 25%,rgba(0,0,0,.16) 0 1.5px,transparent 2px),
    radial-gradient(circle at 68% 60%,rgba(255,255,255,.10) 0 1px,transparent 1.5px),
    radial-gradient(circle at 45% 85%,rgba(0,0,0,.13) 0 1px,transparent 1.5px),
    radial-gradient(140% 110% at 50% 0%,rgba(255,226,170,.20),transparent 60%),
    linear-gradient(180deg,var(--cork-lt),var(--cork) 45%,var(--cork-dk));
  background-size:19px 19px,13px 13px,29px 29px,cover,cover;
  background-attachment:scroll,scroll,scroll,fixed,fixed;
}

/* ---------- chrome ------------------------------------------ */
.skin-evidencewall:has(.pt-screen) .navbar{
  background:linear-gradient(178deg,#2c2519,#1a150d)!important;
  border-bottom:3px solid var(--manila-dk);
}
.skin-evidencewall:has(.pt-screen) .pt-brand{
  font-family:var(--type);letter-spacing:.04em;text-transform:uppercase;
}
/* the navbar fit is handled unskinned in the mobile block below, so the
   user button stays reachable in every skin */
/* ============================================================
   THE BRIEFING CARD
   Body text must never sit on bare cork -- it is unreadable, and
   on an evidence wall nothing floats anyway. The four chrome rows
   (status, score, author sequence, counts) are given a shared
   paper surface and zero gap so they read as ONE pinned card,
   with dark ink on light stock.
   ============================================================ */
/* ONE sheet of paper for the whole briefing. Every gap between the
   rows inside it must die, or it reads as a stack of bands: the rows
   carry Bootstrap mb-2/mb-3 margins and the column adds a flex gap. */
.skin-evidencewall .pt-brief{
  display:block;
  position:relative;z-index:1;
  background:linear-gradient(178deg,var(--card),var(--card-2));
  color:var(--card-ink);
  padding:.75rem .8rem .5rem;
  box-shadow:0 10px 22px -10px rgba(0,0,0,.65),0 2px 3px rgba(0,0,0,.3);
}
.skin-evidencewall .pt-brief > *{
  margin:0!important;
  background:none;
  --bs-gutter-x:0;
}
/* (the briefing carries no pin -- it reads as the wall's header, not as
   another pinned scrap, and the pin collided with the status text) */
/* The counts have moved onto the board, so this row is the timer alone.
   Bootstrap draws it as .progress.h-100, which needs a DEFINITE parent
   height: centring this row (which the old chips needed) collapsed the
   column to its content and the bar measured 0x0. Give the bar a real
   height of its own instead of depending on the parent -- and beat the
   .h-100 utility, which is !important. */
/* ONE height for the whole row -- bar, pause button and clock. The clock was
   inline font-size:2em with a 25px icon button and a ~12px bar beside it, so
   the three sat at wildly different sizes. --pt-timer-h is 1.6rem: the same
   1.6 vs 2.0 em ratio, i.e. 20% off the old clock text. */
.skin-evidencewall .pt-timer-row{
  --pt-timer-h:1.6rem;
  align-items:center;
}
.skin-evidencewall .pt-timer-row > .col{flex:1 1 auto;width:auto;max-width:none;min-width:0}
.skin-evidencewall .pt-timer-row .progress{
  height:var(--pt-timer-h)!important;
  border-radius:3px;background:rgba(43,38,32,.22);
}
/* the pause/resume button: a square the same height, icon scaled to fit */
.skin-evidencewall .pt-timer-row .btn-pause-resume{
  height:var(--pt-timer-h);width:var(--pt-timer-h);
  padding:0;border-radius:3px;
  display:inline-flex;align-items:center;justify-content:center;
}
.skin-evidencewall .pt-timer-row .btn-pause-resume svg{
  width:72%;height:72%;
}
/* the clock -- beats the component's inline font-size/line-height */
.skin-evidencewall .pt-timer-row > .col-auto[style*="font-size"]{
  font-size:var(--pt-timer-h)!important;
  line-height:var(--pt-timer-h)!important;
}
.skin-evidencewall .pt-status-row > *{padding-bottom:0!important}
.skin-evidencewall .pt-stage{margin-top:.55rem}

/* ink, not cream -- everything here is on paper now */
.skin-evidencewall .pt-status,
.skin-evidencewall .pt-status .display-6,
.skin-evidencewall .pt-score-row,
.skin-evidencewall .pt-author-seq,
.skin-evidencewall .pt-timer-row{color:var(--card-ink)}
.skin-evidencewall .pt-status{min-height:0!important}

/* the clue: the loudest thing on the briefing, but still ink on paper */
.skin-evidencewall .pt-clue-banner{
  font-family:var(--type);text-transform:uppercase;letter-spacing:.03em;
  color:var(--card-ink);line-height:1.1;
  font-size:clamp(1.25rem,3.6vw,2.1rem);
}
/* keep secondary chrome quieter than the clue */
.skin-evidencewall .pt-score-row,
.skin-evidencewall .pt-author-seq{
  font-family:var(--mono);font-size:.78rem;
}
.skin-evidencewall .pt-author-seq{color:#6d655a}

/* The story log was a 300px window sitting inside a column that ALSO
   scrolled -- a small box you scrolled inside a box. Give it most of the
   column instead. It keeps its own scroller on purpose: PtLogPanel calls
   scrollToEnd on this element to pin the newest entry, which stops working
   if the column becomes the only thing that scrolls. */
.skin-evidencewall .pt-log-window{
  max-height:min(48vh,520px);
}

/* ============================================================
   STRUCTURAL DEFAULTS -- these apply to EVERY skin including
   Classic, and exist only to make the extra wrappers inert.
   display:contents means Classic's box tree is exactly what it
   was before the wrappers were added.
   ============================================================ */
.pt-screen,
.pt-brief,
.pt-board-col,
.pt-run{display:contents}
.pt-ribbon,
.pt-nameplate{display:none}

/* ---- THE OUTLINE SHEET (every skin) -------------------------
   Author-only. A sheet laid over the board and turned as one
   object: the Author turns the SHEET, the words never move.
   Rotation is ONE transitionable property, so it animates for
   free AND nothing is recomputed -- the marks ride the sheet and
   arrive over different words by geometry alone.

   The rings deliberately reuse PtPalette.ColorblindStyle's exact
   borders -- dashed green for a Lead, solid red for the Red
   Herring -- so the shape cue is the same one the revealed
   squares use, and here it turns with the sheet.               */
.pt-grid-container{position:relative}

.pt-outline{
  display:grid;position:absolute;inset:0;z-index:14;pointer-events:none;
  grid-auto-rows:1fr;
  /* inherit, NEVER re-declare: the board's gap can use container units
     that resolve against a different container down here, which puts the
     sheet's cells on different centres than the cards. */
  gap:inherit;
  transform-origin:50% 50%;
  transform:rotate(var(--pt-turn,0deg));
  /* a touch of overshoot, so it settles like a real sheet */
  transition:transform .44s cubic-bezier(.34,1.36,.5,1);
  /* Fully transparent and borderless. The sheet used to carry a faint wash
     and a hairline edge; both read as a square sweeping over the board as it
     turned, which fought the marks. Only the rings should appear to move. */
  background:none;
  outline:0;
  filter:none;
}
.pt-outline i{position:relative}
/* The mark is a SQUARE WASH over the whole cell, because the sheet rotates:
   the shape has to be identical at 0/90/180/270 or it changes as it turns.
   A circle qualifies but its arc reaches furthest on the diagonals -- exactly
   where the Intrigue badge and info button sit -- and any band or rounded
   rectangle is not rotationally symmetric at all. A full-cell square is
   invariant AND occludes nothing: it tints the card, and the word, the
   Intrigue and the info button all read straight through it.
   Loose Ends carry no mark: neutral is the absence of one. */
.pt-outline i::after{
  content:"";
  position:absolute;inset:0;
  border-radius:2px;
  box-sizing:border-box;
}
.pt-outline i[data-cell="G"]::after{background:rgba(46,158,79,.30)}
.pt-outline i[data-cell="R"]::after{background:rgba(209,52,47,.30)}
/* colourblind mode adds the ring, in the same weights and styles
   PtPalette.ColorblindStyle uses on a revealed card */
.pt-outline[data-colorblind="true"] i[data-cell="G"]::after{
  border:3px dashed #2e9e4f;
}
.pt-outline[data-colorblind="true"] i[data-cell="R"]::after{
  border:4px solid #d1342f;
}
/* While the sheet is up it OWNS the pattern: the cards keep neither
   their tint nor their colourblind ring, or the cue sits statically on
   the squares while the sheet turns. --pt-plain-card is whatever an
   unmarked card looks like in this skin. */
.pt-grid-container:has(.pt-outline) .pt-card{
  background:var(--pt-plain-card,#e8e8e8)!important;
  outline:0!important;
}

/* The plate row holds only the two team plates now (the card-count chips are
   gone), so it is skin-only like the plates themselves. */
.pt-nameplates{display:none}

/* ---------- the board --------------------------------------- */
.skin-evidencewall .pt-card{
  /* overflow stays VISIBLE so the pushpin head shows whole, including
     the half that sits above the card's top edge -- clipping it made
     the pins read as semicircles stuck to the paper. The card's own
     texture layers are inset:0 and so never overflow anyway. */
  overflow:visible;
  position:relative;height:100%;min-height:0;
  border:0;border-radius:0;
  background:linear-gradient(174deg,var(--card),var(--card-2))!important;
  color:var(--card-ink)!important;
  box-shadow:0 8px 18px -6px rgba(0,0,0,.6),0 2px 3px rgba(0,0,0,.3);
  transition:transform .2s cubic-bezier(.2,.8,.2,1),box-shadow .2s;
}
/* the ruled lines and red margin of an index card */
.skin-evidencewall .pt-card::before{
  content:"";position:absolute;inset:0;pointer-events:none;opacity:.45;z-index:0;
  background-image:
    linear-gradient(90deg,transparent 12%,rgba(179,35,31,.32) 12%,rgba(179,35,31,.32) calc(12% + 1px),transparent calc(12% + 1px)),
    repeating-linear-gradient(180deg,transparent 0 14px,rgba(159,184,207,.5) 14px 15px);
}
/* the pushpin every card hangs from */
.skin-evidencewall .pt-card::after{
  content:"";position:absolute;top:-6px;left:50%;margin-left:-8px;z-index:6;
  width:16px;height:16px;border-radius:50%;
  background:radial-gradient(circle at 35% 30%,#fff0a8,#d8a01e 55%,#7a5606);
  box-shadow:0 3px 5px rgba(0,0,0,.5),inset 0 -1px 2px rgba(0,0,0,.3);
}
/* The cards hang STRAIGHT. They used to carry a slight random tilt, which
   was charming on its own but cannot survive the Outline: the sheet's square
   wash is axis-aligned and rotates in exact 90 degree steps, so a card at
   -1 degree can never line up with the square laid over it. Straight cards
   also mean the gutter no longer has to absorb crossing corners. */
.skin-evidencewall .pt-card:hover{
  transform:translateY(-5px);
  box-shadow:0 18px 30px -8px rgba(0,0,0,.7),0 0 0 2px rgba(179,35,31,.35);
  z-index:10;
}

.skin-evidencewall .pt-card .card-body{
  position:relative;z-index:3;
  display:flex;align-items:center;justify-content:center;
  padding:14% 8% 10%;min-width:0;
}
/* The base style is white-space:nowrap, which CLIPS longer words
   ("WALKIE TALKIE" came out as "LKIE TALK"). Let them wrap, and
   size them off the board's width so they scale with the cards. */
.skin-evidencewall .pt-card .card-title{
  font-family:var(--type);text-transform:uppercase;letter-spacing:.02em;
  text-shadow:.6px .6px 0 rgba(43,38,32,.2);
  white-space:normal;
  /* break-word, not anywhere: only split a word that genuinely cannot
     fit, and hyphenate it when we do -- "WHISTLEBL/OWER" read as a bug */
  overflow-wrap:break-word;
  hyphens:auto;
  line-height:1.02;
  margin:0;
  /* vw fallback first, for the same reason as the board's gap */
  font-size:clamp(.5rem,1.5vw,1.25rem);
  font-size:clamp(.5rem,4.1cqw,1.25rem);
}

/* Intrigue, circled in red pencil */
.skin-evidencewall .pt-token-badge{
  background:transparent!important;color:var(--pencil)!important;
  font-family:"Caveat","Segoe Script",cursive;font-weight:700;font-size:1.15rem;
  border:2px solid var(--pencil);
  border-radius:48% 52% 47% 53%/53% 47% 52% 48%;
  transform:rotate(-7deg);
  width:1.7rem;height:1.7rem;display:grid;place-items:center;
}

/* ---- roles, keyed off data-cell/data-fill from PtWordCard ----
   Tints are the Author's private preview; solids are scored.    */
.skin-evidencewall .pt-card[data-fill="tint"][data-cell="G"]{
  background:linear-gradient(174deg,#dfead9,#cbdcc2)!important;
}
.skin-evidencewall .pt-card[data-fill="tint"][data-cell="R"]{
  background:linear-gradient(174deg,#f0dcd6,#e0c2ba)!important;
}
.skin-evidencewall .pt-card[data-fill="solid"][data-cell="G"]{
  background:linear-gradient(174deg,#3f7f52,#245335)!important;
  color:#eaf6ea!important;
}
.skin-evidencewall .pt-card[data-fill="solid"][data-cell="R"]{
  background:linear-gradient(174deg,#bc2d2b,#7d1214)!important;
  color:#fdeeee!important;
}
/* a Loose End that changed hands: claimed, but never green */
.skin-evidencewall .pt-card[data-fill="solid"][data-cell="N"]{
  background:linear-gradient(174deg,#5c5346,#3b352c)!important;
  color:#efe9dc!important;
}
.skin-evidencewall .pt-card[data-fill="solid"]::before{opacity:.13}
.skin-evidencewall .pt-card[data-fill="solid"] .card-title{
  text-shadow:1px 1px 0 rgba(0,0,0,.35);
}
.skin-evidencewall .pt-card[data-fill="solid"] .pt-token-badge{
  color:#f2ecdd!important;border-color:#f2ecdd;
}
/* the pin takes the role's colour once the role is known */
.skin-evidencewall .pt-card[data-cell="G"]:not([data-fill="plain"])::after{
  background:radial-gradient(circle at 35% 30%,#9ce4ae,#2f6b40 55%,#123320);
}
.skin-evidencewall .pt-card[data-cell="R"]:not([data-fill="plain"])::after{
  background:radial-gradient(circle at 35% 30%,#ff8e86,#a81f22 55%,#5a0d0f);
}

/* an emptied cell: sun-faded cork and an abandoned pinhole */
.skin-evidencewall .pt-empty-cell{
  aspect-ratio:1;border:0;border-radius:0;
  background:linear-gradient(174deg,rgba(255,232,190,.12),rgba(255,232,190,.04))!important;
  box-shadow:inset 0 0 0 1px rgba(255,240,210,.13),inset 0 2px 9px rgba(0,0,0,.3);
  position:relative;
}
.skin-evidencewall .pt-empty-cell::after{
  content:"";position:absolute;top:0;left:50%;margin-left:-4px;
  width:8px;height:8px;border-radius:50%;
  background:radial-gradient(circle at 50% 50%,#31200e 0 3px,rgba(0,0,0,.22) 4px,transparent 5px);
}

/* ============================================================
   ONE SCREEN, NEVER SCROLLING
   The play screen is exactly one viewport tall and clips. The
   board is sized from the space actually left over, so it always
   fits whole; only the side columns scroll, inside themselves.
   ============================================================ */
/* Pin the content box to whatever the navbar leaves, and drop its top
   padding, so the one-screen budget has no magic numbers in it beyond the
   navbar's own fixed 60px. :has() scopes this to the game screen only --
   every other page in this skin keeps its normal padding and scrolling.
   Where :has() is unsupported this degrades to a slightly scrollable
   page, not a broken one. */
.skin-evidencewall .content:has(.pt-screen){
  padding-top:0;
  /* vh FIRST as the fallback: an engine without dvh ignores the second line
     and still gets a bounded height. Without this the whole chain below goes
     auto, and the board -- which is capped by the space left over -- sizes
     itself from WIDTH instead and runs off the bottom of the screen. */
  height:calc(100vh - 60px);
  height:calc(100dvh - 60px);
  overflow:hidden;
}
.skin-evidencewall .pt-screen{
  height:100%;
  display:flex;flex-direction:column;
  overflow:hidden;
}
.skin-evidencewall .pt-screen > .text-center{flex:0 0 auto;padding-top:.25rem!important}
.skin-evidencewall .pt-play{
  flex:1 1 auto;min-height:0;
  display:flex;flex-direction:column;
  gap:clamp(.25rem,.8vw,.5rem);
  padding:clamp(.3rem,.9vw,.6rem);
  overflow:hidden;
}
.skin-evidencewall .pt-play > *{flex:0 0 auto}
.skin-evidencewall .pt-play .pt-status{min-height:0!important}

/* the stage takes whatever the chrome above did not */
.skin-evidencewall .pt-stage{
  flex:1 1 auto;min-height:0;
  display:grid;margin:0;
  gap:clamp(.3rem,.9vw,.55rem);
  grid-template-columns:1fr 1fr;
  grid-template-rows:minmax(0,1fr) minmax(0,auto);
}
/* unwind Bootstrap's column sizing -- grid places these now */
.skin-evidencewall .pt-stage > *{
  padding:0;width:auto;max-width:none;flex:none;min-width:0;
}
.skin-evidencewall .pt-board-cell{grid-column:1/-1;grid-row:1;min-height:0}
.skin-evidencewall .pt-board-cell > div{height:100%;min-height:0;margin-bottom:0!important}

/* the two writers'-room columns scroll INSIDE themselves, so the
   page itself never does.
   overflow-x is pinned to hidden on purpose: setting only overflow-y
   makes the other axis compute to auto, which put a horizontal
   scrollbar under every team box. */
.skin-evidencewall .pt-stage > .side-column{
  min-height:0;
  overflow-y:auto;
  overflow-x:hidden;
  overscroll-behavior:contain;
  /* Below the 3-column breakpoint these sit UNDER the board, so every
     pixel they take is a pixel off a board that is already the
     height-constrained element. Keep them to a peek -- they scroll. */
  max-height:clamp(110px,16vh,180px);
  max-height:clamp(110px,16dvh,180px);
  scrollbar-width:thin;
}
/* Bootstrap's rows carry negative gutters that push their content
   wider than the column and were what overflowed in the first place */
.skin-evidencewall .pt-stage > .side-column > .row{
  margin-left:0;margin-right:0;
}
.skin-evidencewall .pt-stage > .side-column > .row > [class*="col-"]{
  padding-left:0;padding-right:0;
}
/* Placed by the order-xxl-* classes, which encode the INTENDED left/right
   order, rather than by :nth-child -- that broke the moment the ribbon
   <svg> was added as a child and shifted every index by one. */
.skin-evidencewall .pt-stage > .side-column.order-xxl-1{grid-column:1;grid-row:2}
.skin-evidencewall .pt-stage > .side-column.order-xxl-3{grid-column:2;grid-row:2}

/* ---- phones: the board IS the game --------------------------
   Everything dropped here is either repeated elsewhere on screen
   (the counts chips, the team plates) or is teaching prose that
   has done its job by the second chapter. No CONTROL is hidden --
   the clue box, the rotate button, the twist toggle, the stop and
   pass buttons and the timer all stay. */
/* ============================================================
   PHONES -- EVERY SKIN, Classic included
   The word grid is the fixed point: always the full width, always
   square. Everything else gives ground, and the page scrolls if it
   must. These rules are structural, so they are deliberately NOT
   scoped to a skin.
   ============================================================ */
@media(max-width:699px){
  /* ---- the navbar must FIT, with the user button reachable --------
     Brand + the Room/Players/Words/Settings list + the user button add
     up to ~444px, past a 402px phone. Pin the brand and the user button
     at the two ends and let ONLY the middle list scroll, so the user
     button is always at the right edge instead of pushed off it (which
     also widened the body and shifted the whole page left). Unskinned,
     so it fixes Classic too. */
  .navbar > .container{flex-wrap:nowrap;gap:.2rem;min-width:0}
  .navbar-brand{flex:0 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .navbar-nav.me-auto{
    flex:1 1 auto;min-width:0;flex-wrap:nowrap;
    overflow-x:auto;overflow-y:hidden;
    scrollbar-width:none;-ms-overflow-style:none;
  }
  .navbar-nav.me-auto::-webkit-scrollbar{display:none}
  .navbar-nav.navbar-right{flex:0 0 auto}

  /* teaching prose and duplicated labels go; controls never do */
  .pt-coach{display:none}
  .pt-chapter-team{display:none}
  .pt-twist-note{display:none}
  /* who is writing and who is next STAYS on the first screen -- it drives the
     next decision. Only shrunk, never hidden. */
  .pt-author-seq{display:block;font-size:.62rem;line-height:1.25}
  .pt-status .display-6,
  .pt-clue-banner{font-size:clamp(1.1rem,6vw,1.5rem)}
  .pt-chapter{font-size:.66rem}

  /* Keep the page gutters lean, but reserve 8px inside each side of the board
     column: colorblind rings extend up to 6px beyond the outer cards and were
     clipped when those cards sat directly against the viewport. Bootstrap
     .row carries negative side margins, so those remain neutralized to avoid
     widening and shifting the page. The DESCENDANT selector is deliberate:
     briefing rows sit under .pt-brief (display:contents), so a `> .row` child
     selector never reached them. */
  .pt-play{padding-left:.2rem!important;padding-right:.2rem!important}
  .pt-play .row{margin-left:0!important;margin-right:0!important;--bs-gutter-x:0}
  .pt-board-cell{padding-left:.5rem!important;padding-right:.5rem!important}

  /* the grid: full width and square, in every skin */
  .pt-grid-container{width:100%;aspect-ratio:1;grid-auto-rows:1fr}

  /* the clue controls, compact */
  .pt-clue-input .form-control,
  .pt-clue-input .btn{font-size:.9rem;padding:.2rem .5rem}
  .form-check-label{font-size:.85rem}
  /* PtGamePlay reserves min-height:2.2rem here so the layout does not jump
     when a clock appears; on a phone that is 17px of nothing above the bar */
  .pt-timer-row{min-height:1.15rem!important}

  /* ---- teams: one compact strip each, not a card ----------------
     The box was ~136px of mostly whitespace: a wrapping two-line team
     name, an oversized score and two labelled rows. It is now a single
     line -- name and score -- with the member pills tucked under it.
     The pill colour already says which team a member is on, so the
     Author:/Guessers: labels go and the pencil carries the role. */
  .pt-team-box{
    display:flex;flex-wrap:wrap;align-items:center;
    gap:.15rem .35rem;
    padding:.3rem .45rem!important;margin-bottom:.25rem!important;
  }
  .pt-team-box .team-header{
    font-size:.82rem!important;font-weight:700;line-height:1.15;
    white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
    max-width:62%;order:1;
  }
  .pt-team-box .pt-team-box-score{
    position:static!important;order:2;margin-left:auto;
    font-size:1rem!important;line-height:1;font-weight:700;
  }
  .pt-team-box .pt-team-line{order:3;flex:0 0 100%;line-height:1.2}
  .pt-team-box .pt-role-label{display:none}
  .pt-team-box .badge{
    font-size:.62rem!important;padding:.18em .5em;
    margin-left:0!important;margin-right:.2rem;
  }

  /* ---- the log and chat go FULL WIDTH -----------------------------
     They live inside a side column, so on a phone they were trapped in
     half the screen with cork wasted beside them. display:contents
     dissolves the columns and promotes their rows into the stage, where
     the team boxes (first row of each column) take half each and
     everything after them spans the lot. `order` drives grid
     auto-placement, so both team boxes land together on one line even
     though a log sits between them in source order.
     Both properties are set on purpose: the Evidence Wall stage is a
     grid (grid-column applies, flex is ignored) and Classic's is a
     Bootstrap flex row (the reverse). */
  .pt-stage > .side-column{display:contents}
  .pt-stage > .side-column > .row:first-child{
    order:1;flex:0 0 50%;max-width:50%;
  }
  .pt-stage > .side-column > .row:not(:first-child){
    order:2;grid-column:1/-1;flex:0 0 100%;max-width:100%;
    /* Classic's stage is a Bootstrap row, so these inherit gutters that
       inset the log ~36px from the board's edges */
    margin-left:0!important;margin-right:0!important;
  }
  .pt-stage > .side-column > .row:not(:first-child) > [class*="col-"]{
    padding-left:0!important;padding-right:0!important;
  }
  /* both team boxes take the height of the taller one, whatever the
     member counts -- the row stretches them, the box fills its column */
  .pt-stage > .side-column > .row:first-child > [class*="col-"]{
    display:flex;flex-direction:column;
  }
  .pt-stage > .side-column > .row:first-child .pt-team-box{
    flex:1 1 auto;margin-bottom:0!important;
  }

  /* ---- skin-specific: unwind the Evidence Wall one-screen clamp --- */
  .skin-evidencewall .pt-play{padding:.2rem;gap:.2rem}
  .skin-evidencewall .pt-stage{
    column-gap:.25rem;
    /* Colorblind card outlines extend beyond the Plot; leave them clear of
       the team strip instead of letting the two surfaces crowd each other. */
    row-gap:.75rem;
  }
  .skin-evidencewall .pt-team-box{border-radius:3px}
  /* Each team row already occupies one of the stage's two equal grid tracks.
     The shared mobile rule's 50% max-width is for Classic's flex row; keeping
     it here halves the row a second time and leaves a wide cork gap between
     the team boxes. Fill the assigned grid track instead. */
  .skin-evidencewall .pt-stage > .side-column > .row:first-child{
    width:100%;max-width:none;
  }

  /* ---- THE BOARD IS THE FIXED POINT ---------------------------------
     On a phone the grid is ALWAYS the full width and always square; the
     rest of the UI fits around it, and the page scrolls if it must.
     Previously the board was capped by leftover height, so a tall status
     block (the Reveal, say) squeezed it to ~72% of the width and left
     cork down both sides. Height no longer gets a vote here. */
  .skin-evidencewall .content:has(.pt-screen){height:auto;overflow:visible}
  .skin-evidencewall .pt-screen{height:auto}
  .skin-evidencewall .pt-play{overflow:visible}
  /* the stage must now grow to its content: leaving the board's row at 1fr of
     a collapsed height made the board overflow its row and paint straight
     over the team columns beneath it */
  .skin-evidencewall .pt-stage{
    flex:0 0 auto;min-height:auto;
    grid-template-rows:auto auto;
  }
  /* container-type:size means this element's height is computed WITHOUT its
     contents -- with height:auto that collapses it to 0 and the board spills
     over the team columns. It must be dropped here, and the extra .pt-stage
     is needed to outrank the base rule further down the file. */
  .skin-evidencewall .pt-stage .pt-board-col{
    container-type:normal;
    height:auto;
    min-height:0;
    display:block;
  }
  .skin-evidencewall .pt-stage .pt-run{width:100%}
  .skin-evidencewall .pt-stage .pt-grid-container{
    width:100%!important;
    height:auto!important;
    aspect-ratio:1;
    max-height:none;
  }
  /* the columns take their natural height now; the log scrolls with the page */
  .skin-evidencewall .pt-stage > .side-column{
    max-height:none;overflow:visible;
  }

  /* the briefing: the controls, nothing else */
  .skin-evidencewall .pt-brief{padding:.4rem .35rem .25rem}
  .skin-evidencewall .pt-timer-row{--pt-timer-h:1.15rem}
}

/* From tablet up the timer is a centred element, not a full-width rule: it
   sat hard against the left edge while everything else in the briefing was
   centred. margin needs !important to beat .pt-brief > * { margin:0 }. */
@media(min-width:700px){
  .skin-evidencewall .pt-timer-row{
    max-width:min(620px,62%);
    margin-left:auto!important;
    margin-right:auto!important;
  }
}

@media(min-width:1100px){       /* tablet landscape and up: three columns */
  .skin-evidencewall .pt-stage{
    grid-template-columns:minmax(170px,1fr) minmax(0,2.3fr) minmax(170px,1fr);
    grid-template-rows:minmax(0,1fr);
  }
  .skin-evidencewall .pt-board-cell{grid-column:2;grid-row:1}
  .skin-evidencewall .pt-stage > .side-column{max-height:none}
  .skin-evidencewall .pt-stage > .side-column.order-xxl-1{grid-column:1;grid-row:1}
  .skin-evidencewall .pt-stage > .side-column.order-xxl-3{grid-column:3;grid-row:1}
}

/* ---- the run of wall: nameplate, board, ribbon over both ---- */
.skin-evidencewall .pt-board-col{
  display:grid;justify-items:center;align-items:start;
  container-type:size;height:100%;min-height:0;
}
.skin-evidencewall .pt-run{
  --plate:clamp(22px,3.6vw,32px);
  /* stretch, so the plate row spans the board's width and the far plate
     lands at the board's far edge; the board keeps its explicit size */
  display:grid;justify-items:stretch;position:relative;
}

/* The board is sized from the leftover space and keeps its CELLS
   square (--pt-cols/--pt-rows come from PtWordGrid), because the
   Outline rotates 90Â° over it. */
.skin-evidencewall .pt-grid-container{
  --pt-ar:calc(var(--pt-cols,3) / var(--pt-rows,3));
  width:min(100cqw,calc((100cqh - var(--plate)) * var(--pt-ar)));
  height:min(calc(100cqh - var(--plate)),calc(100cqw / var(--pt-ar)));
  /* Hard guard, independent of container queries: percentages resolve against
     .pt-board-col, whose height is definite from the stage's 1fr row. If cqh
     ever fails to resolve, this still stops the board overflowing the column
     rather than letting it run past the bottom of the page. */
  max-width:100%;
  max-height:100%;
  grid-auto-rows:1fr;
  /* vw FIRST. If an engine cannot resolve cqw the second declaration is
     invalid and dropped -- and a dropped gap is not cosmetic: the cards are
     pinned at a ~1 degree tilt, so with no gutter their corners cross and
     every card overlaps its neighbours. */
  gap:clamp(.25rem,.8vw,.85rem);
  gap:clamp(.25rem,2cqw,.85rem);
  margin-bottom:0!important;
  container-type:inline-size;
  /* the Outline sheet overlays this box exactly */
  position:relative;
}
@supports not (container-type:size){
  /* No size container queries: fall back to viewport units AND pin the ratio,
     or grid-auto-rows:1fr on an auto height lets the rows grow to their
     content and the board overflows the screen. */
  .skin-evidencewall .pt-grid-container{
    width:min(100%,calc(46vh * var(--pt-ar)));
    width:min(100%,calc(46dvh * var(--pt-ar)));
    height:auto;
    aspect-ratio:var(--pt-ar);
  }
  .skin-evidencewall .pt-card .card-title{font-size:clamp(.7rem,1.5vw,1.25rem)}
}

/* the two plates the ribbons are tied off to -- one per team, each on
   the side its team box sits on, each pinned in its own colour */
.skin-evidencewall .pt-nameplates{
  display:flex;justify-content:space-between;align-items:center;
  width:100%;height:calc(var(--plate) - 7px);margin-bottom:7px;
}
.skin-evidencewall .pt-nameplate{
  display:inline-flex;align-items:center;gap:.4rem;height:100%;
  padding:0 .6rem 0 .45rem;
  background:linear-gradient(178deg,var(--manila),var(--manila-dk));
  font-family:var(--mono);font-size:clamp(.46rem,1.3vw,.58rem);
  letter-spacing:.16em;text-transform:uppercase;color:#2c2519;white-space:nowrap;
  box-shadow:0 3px 8px -3px rgba(0,0,0,.6);
  transform:rotate(-.9deg);transform-origin:left center;
  border-left:4px solid var(--pt-team-color,#a81f22);
}
/* the far plate mirrors, so its pin sits nearest its own team box */
.skin-evidencewall .pt-nameplate-end{
  flex-direction:row-reverse;
  padding:0 .45rem 0 .6rem;
  transform:rotate(.9deg);transform-origin:right center;
  border-left:0;border-right:4px solid var(--pt-team-color,#a81f22);
}
/* the pin each ribbon starts from, in that team's colour */
.skin-evidencewall .pt-nameplate-pin{
  width:12px;height:12px;border-radius:50%;flex:0 0 auto;
  background:radial-gradient(circle at 35% 30%,
    color-mix(in srgb, var(--pt-team-color,#c0201d) 45%, white),
    var(--pt-team-color,#c0201d) 60%,
    color-mix(in srgb, var(--pt-team-color,#c0201d) 55%, black));
  box-shadow:0 2px 4px rgba(0,0,0,.5),inset 0 -1px 2px rgba(0,0,0,.3);
}

/* ---- THE RIBBON --------------------------------------------
   This chapter's chain of reasoning, drawn by pt-ribbon.js: tied
   off at the room's pin, then pin to pin through every word
   selected in the order it was picked. The Scoop continues the
   same string, dashed -- the board cannot say who took a word,
   because a Scooped Lead is still a green Lead.               */
.skin-evidencewall .pt-stage{position:relative}
.skin-evidencewall .pt-ribbon{
  display:block;position:absolute;inset:0;width:100%;height:100%;
  overflow:visible;pointer-events:none;z-index:12;
}
/* stroke colour is set per run, from the team box's --pt-team-color */
.skin-evidencewall .pt-ribbon .pt-ribbon-run{
  fill:none;stroke-width:2.6;stroke-linecap:round;stroke-linejoin:round;
  filter:drop-shadow(0 2px 2px rgba(0,0,0,.5));
}
.skin-evidencewall .pt-ribbon .pt-ribbon-pin{
  stroke:rgba(0,0,0,.32);stroke-width:1;
  filter:drop-shadow(0 2px 3px rgba(0,0,0,.45));
}

/* ---- THE OUTLINE SHEET -------------------------------------
   Author-only. A sheet of acetate laid over the board and pinned
   through its centre. The Author turns the SHEET, not the words --
   on a wall the words are pinned and the overlay is not.

   Rotation is ONE transitionable property, so it animates for
   free AND nothing is recomputed: the marks ride the sheet and
   arrive over different words by geometry alone.              */
/* the sheet itself is defined once, for every skin, up in the base
   section -- this only says what an unmarked card looks like here */
.skin-evidencewall .pt-grid-container{
  --pt-plain-card:linear-gradient(174deg,var(--card),var(--card-2));
}

/* ---------- side panels: manila folders and a legal pad ------ */
.skin-evidencewall .side-column .card,
.skin-evidencewall .pt-score-panel{
  border:0;border-radius:0;
  background:linear-gradient(178deg,var(--manila),var(--manila-dk))!important;
  color:#2c2519!important;
  box-shadow:0 8px 18px -6px rgba(0,0,0,.55),0 1px 2px rgba(0,0,0,.3);
}
.skin-evidencewall .pt-chat-surface{
  padding:.45rem .55rem .55rem!important;
  border:0;border-radius:0;
  background:linear-gradient(178deg,var(--card),var(--card-2))!important;
  color:var(--card-ink)!important;
  box-shadow:0 8px 18px -6px rgba(0,0,0,.55),0 1px 2px rgba(0,0,0,.3);
}
.skin-evidencewall .side-column .card-header{
  background:transparent!important;border-bottom:1px solid rgba(44,37,25,.25);
  font-family:var(--type);text-transform:uppercase;letter-spacing:.03em;
}
