
:root{
  /* THE SEASON DRESS.
     Every value in this block is rewritten on <html> by applyTheme() in app.js
     from the preset named in the Garden record — see window.EDEN_THEMES in
     data.js. What is written here is Season Two, so a browser that never
     reaches the record, or reaches it slowly, still paints the right season
     rather than flashing the wrong one. Anything a colour cannot carry lives at
     the foot of this file under html[data-season="one"]. */
  --bg:#07061a;--bg-top:#0b0826;--bg-bottom:#040311;
  --bg-glow:rgba(138,99,255,.26);--veil-glow:rgba(170,140,255,.13);
  --panel:#120f2e;--panel2:#1a1640;--text:#f0eaff;--muted:#b9b2cb;
  /* Gold is not a season: both paintings are gilded, so the frames, headings and
     rules that follow the artwork stay gold through a change of dress. */
  --gold:#e5c978;--green:#71e49b;--cyan:#56d9ff;--danger:#ff8f9e;
  --line:rgba(160,111,245,.28);--shadow:0 28px 80px rgba(0,0,0,.42);
  /* The accent set is what the artwork itself is lit by — Season One's garden
     was lit lime, Season Two's tree electric blue and violet. --accent-rgb is
     the same colour as three numbers, for the rgba() glows and washes. */
  --accent:#a879f7;--accent-bright:#6fd7ff;--accent-pale:#ecdfff;
  --label:#b9a6ff;--label-dim:#a49bd6;
  --accent-rgb:168,121,247;--green-rgb:113,228,155;
  /* Every box on every page. --card-* is the floor of a card, --card-lift-* the
     same floor raised a shade for the One Field card, --surface the sunken
     inside of an input or a well, --scrim the translucent sheet under the
     header and the Council's note, and --ink the dark type that sits on gold. */
  --card-top:rgba(28,23,72,.95);--card-bottom:rgba(13,10,36,.96);
  --card-lift-top:rgba(42,34,96,.96);--card-lift-bottom:rgba(18,14,50,.97);
  --surface:#0a0820;--ink:#0a0820;--scrim:rgba(10,8,34,.78);
  /* The type inside the plates over the front-page artwork, which is lit by the
     painting behind it rather than by the page. */
  --plate-text:#e9e4f2;--plate-text-dim:#ddd7ea;--plate-title:#f2ecff;
  /* The photograph behind every view. Season One stood in the garden; Season
     Two is above it, so the image gives way to the gradient underneath. */
  --backdrop:none;--backdrop-opacity:0
}
*{box-sizing:border-box}
html{scroll-behavior:smooth}
body{margin:0;min-height:100vh;background:
radial-gradient(circle at 50% 0,var(--bg-glow),transparent 27%),
linear-gradient(180deg,var(--bg-top) 0,var(--bg) 58%,var(--bg-bottom) 100%);
color:var(--text);font-family:Inter,system-ui,sans-serif}
button,input,textarea{font:inherit}
button{cursor:pointer}
.hidden{display:none!important}
.boot{position:fixed;inset:0;display:grid;place-content:center;text-align:center;background:var(--bg-bottom);z-index:100}
.boot-mark{font-size:3rem;color:var(--green);filter:drop-shadow(0 0 16px var(--green));animation:pulse 1.5s infinite}
.boot-title{font-family:Cinzel,serif;letter-spacing:.24em;margin-top:16px}
.boot-line{width:min(72vw,360px);height:3px;background:var(--surface);margin-top:20px;overflow:hidden}
.boot-line span{display:block;width:45%;height:100%;background:var(--green);animation:load 1.5s ease-in-out forwards}
@keyframes load{to{width:100%}} @keyframes pulse{50%{transform:scale(1.08);opacity:.7}}
.app{min-height:100vh}
/* One sticky element for the bar and the menu together, so the menu can never be
   pinned at a guessed offset that a taller bar then covers. */
.topnav{position:sticky;top:0;z-index:40}
.topbar{display:flex;justify-content:space-between;align-items:center;padding:14px clamp(16px,4vw,42px);background:var(--scrim);backdrop-filter:blur(18px);border-bottom:1px solid var(--line)}
.brand{display:flex;align-items:center;gap:12px;background:none;border:0;color:var(--text);text-align:left}
.brand-mark{font-size:1.7rem}.brand strong{font-family:Cinzel,serif;letter-spacing:.08em}.brand small{display:block;color:var(--muted);margin-top:2px}
.menu-btn{display:none;border:1px solid var(--line);background:var(--panel);color:var(--text);border-radius:10px;padding:8px 11px}
.nav{display:flex;gap:7px;justify-content:center;padding:11px 14px;border-bottom:1px solid rgba(255,255,255,.05);background:var(--scrim);backdrop-filter:blur(14px)}
.nav button{border:0;background:transparent;color:var(--muted);padding:9px 12px;border-radius:999px}
.nav button:hover,.nav button.active{color:var(--ink);background:var(--gold)}
main{width:min(1180px,calc(100% - 32px));margin:0 auto}
.view{display:none;padding:clamp(38px,7vw,78px) 0}.view.active{display:block}
.hero{display:grid;grid-template-columns:1.1fr .9fr;align-items:center;min-height:64vh;gap:32px}
.kicker{color:var(--gold);font-size:.75rem;letter-spacing:.22em;font-weight:700;text-transform:uppercase}
h1,h2,h3{font-family:Cinzel,serif}h1{font-size:clamp(2.5rem,7vw,5.6rem);line-height:.94;margin:12px 0 18px}h2{font-size:clamp(1.8rem,4vw,3rem);margin:8px 0 14px}
.hero p,.page-head p{color:var(--muted);font-size:1.08rem;line-height:1.65;max-width:680px}
.hero-actions,.vault-actions{display:flex;gap:12px;flex-wrap:wrap;margin-top:25px}
.primary,.ghost,.danger{border-radius:999px;padding:13px 20px;border:1px solid transparent;font-weight:700}
.primary{background:linear-gradient(90deg,#d8b95c,#f0dc9c);color:var(--ink)}
.ghost{background:transparent;border-color:var(--line);color:var(--text)}
.danger{background:rgba(255,93,78,.12);border-color:rgba(255,143,130,.45);color:#ffb2a8}
.wide{width:100%}
.tree-stage{position:relative;min-height:430px;display:grid;place-items:center}
.tree{font-size:clamp(10rem,24vw,18rem);position:relative;z-index:2;filter:drop-shadow(0 0 28px rgba(var(--green-rgb),.28))}
.tree-glow{position:absolute;width:70%;aspect-ratio:1;border-radius:50%;background:radial-gradient(circle,rgba(var(--green-rgb),.23),transparent 67%);filter:blur(8px)}
.roots{position:absolute;bottom:50px;width:80%;height:2px;background:linear-gradient(90deg,transparent,var(--gold),transparent);box-shadow:0 0 30px var(--gold)}
.status-grid,.directive-grid,.field-grid,.admin-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:16px}
.status-card,.directive,.field-card,.timeline-card,.admin-card,.vault-card,.ballot-card{background:linear-gradient(145deg,var(--card-top),var(--card-bottom));border:1px solid var(--line);border-radius:22px;box-shadow:var(--shadow)}
.status-card{padding:22px}.status-card span{display:block;color:var(--gold);font-size:.75rem;letter-spacing:.12em;text-transform:uppercase}.status-card strong{display:block;font-family:Cinzel,serif;font-size:1.25rem;margin:10px 0}.status-card small{color:var(--muted)}
.section-head{display:flex;justify-content:space-between;align-items:end;margin:58px 0 18px}
.directive{padding:21px}.directive .icon{font-size:1.7rem}.directive h3{margin:13px 0 8px}.directive p{color:var(--muted);line-height:1.5;margin:0}
.page-head{margin-bottom:32px}.page-head.centered{text-align:center}.page-head.centered p{margin-inline:auto}
.field-grid{grid-template-columns:repeat(2,1fr)}
.field-card{padding:24px;overflow:hidden;position:relative}.field-card:before{content:"";position:absolute;inset:0 0 auto 0;height:4px;background:var(--field)}
.field-top{display:flex;justify-content:space-between;gap:15px}.field-card h3{font-size:1.45rem;margin:6px 0}.field-score{font-size:2rem;font-family:Cinzel,serif;color:var(--gold)}
.roster{display:flex;flex-wrap:wrap;gap:8px;margin-top:17px}.chip{padding:8px 10px;border-radius:999px;background:rgba(255,255,255,.05);color:var(--muted);font-size:.88rem}
.score-list{display:grid;gap:14px}.score-row{display:grid;grid-template-columns:58px 1fr auto;align-items:center;gap:16px;background:var(--panel);border:1px solid var(--line);border-radius:18px;padding:16px 18px}
.rank{font-family:Cinzel,serif;font-size:1.5rem;color:var(--gold)}.bar{height:9px;background:var(--surface);border-radius:99px;overflow:hidden;margin-top:9px}.bar span{display:block;height:100%;background:linear-gradient(90deg,var(--green),var(--cyan));border-radius:99px}
.timeline-card{margin-top:30px;padding:24px}.timeline{display:grid;gap:17px;margin-top:18px}.timeline-item{border-left:2px solid var(--gold);padding-left:17px}.timeline-item small{color:var(--gold)}.timeline-item p{color:var(--muted);margin:6px 0 0}
.council-stage{display:grid;grid-template-columns:90px 1fr 90px;align-items:center;max-width:820px;margin:0 auto}.torch{text-align:center;font-size:3rem;filter:drop-shadow(0 0 18px #ff9d35);animation:flicker 1.2s infinite alternate}@keyframes flicker{to{transform:scale(.93) rotate(2deg)}}
.ballot-card{padding:clamp(24px,5vw,48px)}.closed-state{text-align:center}.seal{font-size:3rem;color:var(--gold)}.candidate-list{display:grid;gap:11px;margin:18px 0}.candidate-btn{width:100%;text-align:left;border:1px solid rgba(255,255,255,.12);background:rgba(255,255,255,.025);color:var(--text);padding:15px;border-radius:14px}.candidate-btn.selected{border-color:var(--green);box-shadow:0 0 0 2px rgba(var(--green-rgb),.12)}
.input-label{display:block;color:var(--gold);margin:15px 0 8px;font-size:.88rem}.text-input,.text-area{width:100%;background:var(--surface);border:1px solid rgba(255,255,255,.16);border-radius:12px;padding:13px 14px;color:var(--text);outline:none}.text-input:focus,.text-area:focus{border-color:var(--green)}.text-area{min-height:125px;resize:vertical}
.form-status{min-height:22px;text-align:center;color:var(--muted);margin-top:12px}.form-status.good{color:var(--green)}.form-status.bad{color:var(--danger)}
.vault-card{width:min(500px,100%);margin:0 auto;padding:35px;text-align:center}.keyhole-zone{width:190px;height:230px;margin:0 auto;position:relative;display:grid;place-items:center;outline:none}.lock-ring{position:absolute;width:165px;height:165px;border-radius:50%;border:3px solid rgba(229,201,120,.55);box-shadow:0 0 0 10px rgba(0,0,0,.2),0 0 24px rgba(229,201,120,.14)}.keyhole{width:82px;height:122px;background:#020503;clip-path:polygon(50% 0,66% 10%,74% 25%,70% 42%,100% 100%,0 100%,30% 42%,26% 25%,34% 10%)}#glyphPreview{position:absolute;width:76px;height:108px;object-fit:contain;opacity:0;filter:drop-shadow(0 0 10px var(--cyan));transition:.4s}#glyphPreview.visible{opacity:1}
.vault-reveal{max-width:680px;margin:25px auto 0;padding:38px;text-align:center;background:radial-gradient(circle,rgba(var(--green-rgb),.15),var(--card-bottom));border:1px solid var(--gold);border-radius:24px}.vault-reveal img{width:90px;filter:drop-shadow(0 0 15px var(--cyan))}.claim-box{margin:24px auto 0;max-width:430px;padding:18px;border:1px dashed var(--cyan);border-radius:14px}.claim-box small{display:block;color:var(--gold);letter-spacing:.14em;text-transform:uppercase}.claim-box strong{display:block;color:var(--cyan);font-size:1.25rem;margin-top:8px}
.journal-list{display:grid;gap:18px}.journal-entry{background:linear-gradient(145deg,var(--card-top),var(--card-bottom));border:1px solid var(--line);border-radius:20px;padding:26px}.journal-entry time{color:var(--gold);font-size:.8rem;letter-spacing:.12em}.journal-entry blockquote{font-family:Cinzel,serif;font-size:clamp(1.15rem,2.4vw,1.55rem);line-height:1.6;margin:16px 0 0;color:#eee5cb}
.admin-grid{grid-template-columns:repeat(2,1fr)}.admin-card{padding:24px}.admin-card h3{margin-top:0}.danger-card{border-color:rgba(224,90,90,.55)}.danger-card h3{color:var(--danger)}.danger-card .primary{background:linear-gradient(90deg,#8f3a34,#c9615a);color:#1a0a08}.toggle-row{display:flex;justify-content:space-between;align-items:center;padding:11px 0;color:var(--muted)}.code-output{white-space:pre-wrap;background:var(--surface);border-radius:12px;padding:14px;min-height:90px;color:var(--green)}.totals{display:grid;gap:9px;margin:14px 0}.total-row{display:flex;justify-content:space-between;background:rgba(255,255,255,.04);padding:10px 12px;border-radius:10px}
.vote-ledger{display:grid;gap:9px;margin:14px 0;max-height:420px;overflow-y:auto}.vote-ledger-row{display:grid;grid-template-columns:1fr auto;gap:4px 12px;align-items:center;background:rgba(255,255,255,.04);padding:11px 12px;border-radius:10px}.vote-ledger-row.pending{opacity:.6}.vote-ledger-row strong{overflow-wrap:anywhere}.vote-ledger-row small{display:block;color:var(--muted);font-size:.78rem;margin-top:3px}.vote-ledger-vote{text-align:right;color:var(--green);font-weight:700;overflow-wrap:anywhere}.vote-ledger-row.pending .vote-ledger-vote{color:var(--muted);font-weight:400}
.ballot-step.hidden{display:none}
.keeper-picker{display:grid;gap:6px;max-height:260px;overflow-y:auto;background:var(--surface);border:1px solid rgba(255,255,255,.16);border-radius:12px;padding:10px}.keeper-check{display:flex;align-items:center;gap:10px;padding:7px 9px;border-radius:9px;cursor:pointer;overflow-wrap:anywhere}.keeper-check:hover{background:rgba(255,255,255,.05)}.keeper-check input{accent-color:var(--green);width:16px;height:16px;flex:none}.keeper-check:has(input:checked){background:rgba(var(--green-rgb),.1);color:var(--green)}
footer{display:flex;justify-content:space-between;gap:20px;color:#7f9184;border-top:1px solid rgba(255,255,255,.06);padding:24px clamp(16px,4vw,42px);font-size:.85rem}
@media(max-width:850px){.hero{grid-template-columns:1fr}.tree-stage{min-height:290px}.status-grid,.directive-grid{grid-template-columns:1fr}.field-grid,.admin-grid{grid-template-columns:1fr}.council-stage{grid-template-columns:1fr}.torch{display:none}
/* Hangs off the bottom of the sticky wrapper rather than a fixed offset, so the
   menu follows the bar's real height and stays with it while the page scrolls. */
.nav{position:absolute;top:100%;right:12px;left:12px;display:none;flex-direction:column;background:var(--panel);border:1px solid var(--line);border-radius:16px;padding:12px;box-shadow:0 26px 64px rgba(0,0,0,.62)}.nav.open{display:flex}.menu-btn{display:block}.nav button{text-align:left}.score-row{grid-template-columns:42px 1fr}.score-row>strong{grid-column:2}.hero h1{font-size:3.4rem}}


/* Day 1 hyperrealistic Eden treatment */
body::before{
  content:"";
  position:fixed;
  inset:0;
  z-index:-2;
  background:
    linear-gradient(180deg,rgba(3,9,6,.24),rgba(3,8,5,.92)),
    var(--backdrop) center 12% / cover no-repeat fixed;
  opacity:var(--backdrop-opacity);
}
body::after{
  content:"";
  position:fixed;
  inset:0;
  z-index:-1;
  pointer-events:none;
  background:
    radial-gradient(circle at 50% 22%,var(--veil-glow),transparent 26%),
    linear-gradient(90deg,rgba(0,0,0,.5),transparent 26%,transparent 74%,rgba(0,0,0,.5));
}
.hero{
  position:relative;
  overflow:hidden;
  border:1px solid rgba(229,201,120,.2);
  border-radius:28px;
  padding:clamp(22px,4vw,48px);
  background:
    linear-gradient(90deg,rgba(3,12,8,.94) 0%,rgba(5,16,11,.72) 48%,rgba(5,13,9,.3) 100%),
    url("eden-garden-dashboard.png") center / cover no-repeat;
  box-shadow:0 35px 100px rgba(0,0,0,.55);
}
.hero::before,.hero::after{
  content:"";
  position:absolute;
  width:190px;
  height:125%;
  top:-12%;
  pointer-events:none;
  opacity:.7;
  background:
    radial-gradient(ellipse at 50% 10%,#5f8f52 0 7%,transparent 8%),
    radial-gradient(ellipse at 24% 24%,#6f9e5b 0 6%,transparent 7%),
    radial-gradient(ellipse at 72% 36%,#477b43 0 7%,transparent 8%),
    radial-gradient(ellipse at 35% 55%,#6d9954 0 6%,transparent 7%),
    linear-gradient(92deg,transparent 42%,rgba(73,104,54,.9) 45% 52%,transparent 55%);
  filter:drop-shadow(0 0 14px rgba(49,102,56,.45));
  animation:vineFlow 7s ease-in-out infinite alternate;
}
.hero::before{left:-72px;transform:rotate(-5deg)}
.hero::after{right:-72px;transform:scaleX(-1) rotate(-5deg);animation-delay:-3s}
@keyframes vineFlow{
  from{translate:0 -6px;rotate:-1deg}
  to{translate:8px 12px;rotate:2deg}
}
.tree-stage{opacity:.02;pointer-events:none}
.status-card,.directive,.field-card,.timeline-card,.admin-card,.vault-card,.ballot-card{
  backdrop-filter:blur(10px);
}
.nav button[data-route="council"]::before{content:"🏛 ";}

.council-entry-note{
  margin:0 auto 22px;
  max-width:760px;
  padding:15px 18px;
  border:1px solid rgba(229,201,120,.28);
  border-radius:14px;
  background:var(--scrim);
  color:var(--muted);
  text-align:center;
}
.council-entry-note strong{color:var(--gold)}

.admin-help{color:var(--muted);line-height:1.5;margin-top:-4px}#codeNamesDrift{color:#ffb2a8;background:rgba(255,93,78,.1);border:1px solid rgba(255,143,130,.35);border-radius:12px;padding:10px 12px;margin:10px 0 0;font-size:.9rem}.placement-selects{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px 14px}.placement-select{appearance:auto}.challenge-history{display:grid;gap:10px;margin:12px 0 16px}.challenge-record{border:1px solid rgba(255,255,255,.1);background:rgba(255,255,255,.035);border-radius:12px;padding:12px}.challenge-record strong{display:block;color:var(--gold);margin-bottom:7px}.challenge-record-list{display:grid;gap:5px;color:var(--muted);font-size:.9rem}.challenge-record-list span{display:flex;justify-content:space-between;gap:12px}@media(max-width:650px){.placement-selects{grid-template-columns:1fr}}

.point-value-grid,.opportunity-add{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px 12px}
.opportunity-list,.reputation-board,.points-ledger{display:grid;gap:9px;margin:12px 0 16px}
.opportunity-row,.reputation-row,.ledger-row{display:grid;align-items:center;gap:9px;border:1px solid rgba(255,255,255,.1);background:rgba(255,255,255,.035);border-radius:12px;padding:10px 12px}
.opportunity-row{grid-template-columns:1fr 88px 88px auto}
.icon-button{border:1px solid rgba(255,143,130,.38);background:rgba(255,93,78,.08);color:#ffb2a8;border-radius:9px;padding:9px 10px}
.reputation-row,.ledger-row{grid-template-columns:1fr auto}
.reputation-row strong{color:var(--gold)}
.ledger-row small{display:block;color:var(--muted);margin-top:4px}
.ledger-amount.positive{color:var(--green)}.ledger-amount.negative{color:var(--danger)}
.ledger-card{grid-column:1/-1}
/* The roster boxes. Two to a row on a wide panel, one on a phone, and shorter
   than the panel's default textarea because six or seven handles is the whole
   contents of a Field — a 125px box would be mostly empty space, four times. */
.roster-editor{display:grid;gap:2px 18px;margin-top:4px}
.roster-editor .text-area{min-height:0}
.roster-field .input-label{margin-top:12px}
.journal-admin-list{display:grid;gap:9px;margin-top:16px}
.journal-admin-row{display:flex;justify-content:space-between;align-items:flex-start;gap:12px;border:1px solid rgba(255,255,255,.1);background:rgba(255,255,255,.035);border-radius:12px;padding:10px 12px}
.journal-admin-row strong{color:var(--gold)}
.journal-admin-row small{display:block;color:var(--muted);margin-top:4px;line-height:1.5}
.journal-admin-row .icon-button{flex:none}
@media(min-width:900px){.roster-editor{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(max-width:700px){.point-value-grid,.opportunity-add{grid-template-columns:1fr}.opportunity-row{grid-template-columns:1fr 90px}}


/* FINAL EXACT DASHBOARD */
#home{padding:0!important}
/* The artwork is sideways-scrolled inside this box on narrow screens. Scrolling
   the page itself instead used to slide the header out from over the content. */
.final-dashboard-scroll{width:100%}
.final-dashboard{
  position:relative;
  width:100%;
  max-width:1536px;
  margin:0 auto;
  aspect-ratio:1612/975; /* must match eden-dashboard-s2.png or every overlay drifts */
  overflow:hidden;
  background:var(--bg);
}
.final-dashboard-art{
  position:absolute;inset:0;
  width:100%;height:100%;
  object-fit:contain;display:block;
}
/* Above the artwork and below every live plate and the sticky header — these are
   invisible boxes, and at the header's own z-index they took its clicks. */
.dash-hit{
  position:absolute;z-index:10;border:0;background:transparent;padding:0;cursor:pointer
}
.dash-hit:hover{background:rgba(var(--accent-rgb),.06)}
.dash-hit:focus-visible{outline:2px solid var(--accent-bright);outline-offset:-2px}

/* Hit boxes are measured against the 1612x975 artwork. Season Two repainted the
   scene but kept both nav bars on the same grid, so these carried over unchanged
   — every cell was re-measured against the new file and lands inside its frame.
   ADMIN, the bar's second-from-right painted cell, has no box on purpose:
   Control is unlisted and reached by a hand-typed #letsgrow2day. CONTROL ROOM
   beside it does have one — it now opens #control-room, the closed-door sign,
   rather than the Remembering Gate. */
.top-home,.top-fields,.top-board,.top-council,
.top-vault,.top-journal,.top-control{top:1.44%;height:6.77%}
.top-home{left:18.49%;width:8.81%}
.top-fields{left:27.48%;width:8.93%}
.top-board{left:36.6%;width:10.55%}
.top-council{left:47.52%;width:9.68%}
.top-vault{left:57.57%;width:9.74%}
.top-journal{left:67.49%;width:10.86%}
.top-control{left:87.22%;width:11.97%}

/* "Enter the Garden" and "Read Journal" are real buttons inside the live plates
   below, not hit boxes — Season Two paints neither of them. */

/* The leaf at the right-hand end of the painted "Keeper's Remaining" heading. */
.keepers-leaf{left:85.24%;top:45.13%;width:2.61%;height:3.08%}

.bottom-home,.bottom-fields,.bottom-board,
.bottom-council,.bottom-journal,.bottom-vault{top:87.59%;height:10.97%}
.bottom-home{left:1.36%;width:10.48%}
.bottom-fields{left:13.28%;width:11.85%}
.bottom-board{left:26.05%;width:11.73%}
.bottom-council{left:38.71%;width:11.6%}
.bottom-journal{left:51.3%;width:12.03%}
.bottom-vault{left:64.27%;width:11.66%}

/* THE LIVE PLATES
   Season One's painting had its values baked in, so every plate below was an
   opaque box with its own gold border, sat on top to hide them. Season Two
   paints empty frames instead — so these are transparent and frameless, and
   what shows behind the live numbers is the artwork's own panel and its own
   gilding. Drawing a second border here would double every frame on the page.

   Each rectangle is measured off eden-dashboard-s2.png: the panel interiors are
   flat near-black, which is what makes them findable to the pixel. Panels whose
   heading is painted into the artwork start their content below it rather than
   drawing the heading again. */
.live-fields-panel,.live-countdown,.live-keepers,.live-weather,.live-message,.live-journal{
  position:absolute;z-index:20;
  background:transparent;border:0;
  color:var(--plate-text);
}
/* The painted headings are already on the artwork, so the plates' own headings
   are for screen readers only. Kept in the DOM rather than deleted: the panels
   are landmarks, and a region with no name is a worse page to listen to. */
.live-fields-panel>h2,.live-keepers>h2,.live-weather>h2,.live-message>h2,.live-journal>h2{
  position:absolute;width:1px;height:1px;margin:-1px;padding:0;
  overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0
}
/* Painted interior runs 49.64%-83.49%; "THE FOUR FIELDS" is painted across the
   top of it and ends at 53.13%, so the rows start below that. */
.live-fields-panel{left:1.36%;top:53.90%;width:26.92%;height:29.59%;padding:0 1.6%;display:flex;flex-direction:column}
/* gap rather than per-row margin so the four rows divide the space exactly. */
.live-field-rows{display:grid;grid-template-rows:repeat(4,1fr);gap:7px;flex:1 1 auto;min-height:0}
.live-field-row{
  display:grid;grid-template-columns:clamp(24px,2.6vw,42px) 1fr clamp(38px,4.2vw,64px);
  align-items:center;gap:clamp(4px,.8vw,10px);
  border:1px solid rgba(255,255,255,.09);padding:0 clamp(4px,.8vw,10px);min-height:0
}
.live-field-row .field-icon{font-size:clamp(13px,1.6vw,26px);line-height:1}
.live-field-row .field-name{font-family:Cinzel,Georgia,serif;font-size:clamp(10px,1.15vw,15px)}
.live-field-row .field-points{text-align:right;font-family:Cinzel,Georgia,serif}
.live-field-row .field-points strong{display:block;font-size:clamp(11px,1.7vw,28px);line-height:1.15}
.live-field-row .field-points small{display:block;font-size:clamp(6px,.62vw,10px);line-height:1.2}

/* The numbers only. Painted interior runs 56.31%-70.05% with the heading painted
   at 57.95%-59.18%; the plate that covers that heading is a separate rectangle
   below, so this starts underneath it. */
.live-countdown{left:35.67%;top:59.70%;width:24.50%;height:10.35%;padding:0 1.5%;text-align:center;display:flex;flex-direction:column;justify-content:center}
/* "CURRENT CHALLENGE ENDS IN" before the season, "SEASON TWO BEGINS IN" during
   it. The painted words underneath cannot say both, so this is the one opaque
   plate left on the page: the panel interior is flat #040b0c across the whole
   strip, measured off the file, so the fill disappears into it. */
.live-countdown-label{
  position:absolute;z-index:21;left:35.67%;top:57.60%;width:24.50%;height:1.95%;
  display:grid;place-content:center;
  background:#040a0b;color:var(--label);font-family:Cinzel,Georgia,serif;
  letter-spacing:.06em;font-size:clamp(7px,.72vw,12px);line-height:1;white-space:nowrap
}
.live-countdown-values{display:grid;grid-template-columns:repeat(4,1fr);margin-top:clamp(3px,.6vw,9px)}
.live-countdown-values div{border-right:1px solid rgba(211,181,86,.2)}
.live-countdown-values div:last-child{border-right:0}
.live-countdown-values strong{display:block;font-family:Cinzel,Georgia,serif;font-size:clamp(18px,2.5vw,40px);line-height:1}
.live-countdown-values span{display:block;color:var(--label-dim);font-size:clamp(7px,.62vw,11px);margin-top:clamp(2px,.5vw,7px)}

/* Painted interior 44.10%-57.23%, heading ends 47.59%. */
.live-keepers{left:71.96%;top:48.30%;width:26.74%;height:8.93%;padding:0 1.8%;display:flex;flex-direction:column;justify-content:center}
.live-keepers strong{display:block;font-family:Cinzel,Georgia,serif;font-size:clamp(20px,2.2vw,34px);line-height:1;color:var(--accent-bright)}
.live-keepers small{display:block;color:var(--label-dim);font-size:clamp(7px,.62vw,10px);margin-top:3px}
/* The figures stand beside the number rather than beneath it: this panel is the
   shallowest of the live plates, and a second line inside it would push the
   label below the painted frame. The row is centred on the number's own middle
   and the figures are sized so a full Garden still fits on one line inside the
   narrowest the panel ever gets — the dashboard stops shrinking at 760px, where
   the plate is about 176px of usable width. */
.live-keepers-count{display:flex;align-items:center;gap:clamp(4px,.7vw,12px);min-width:0}
.live-keeper-figures{display:flex;flex-wrap:wrap;align-content:center;gap:clamp(1px,.2vw,3px);flex:1 1 auto;min-width:0}
.keeper-figure{
  /* Both dimensions rather than an aspect-ratio: the two clamps hold the
     figure's 10:16 proportions at every stop, and nothing has to support
     aspect-ratio for the row to come out right. */
  flex:none;width:clamp(5px,.62vw,10px);height:clamp(8px,.99vw,16px);
  fill:var(--accent);opacity:.92
}
/* Only the sprite's definition, never drawn: the figures are <use> of it. */
.svg-sprite{position:absolute;width:0;height:0;overflow:hidden}

/* Painted interior 60.10%-82.46%, heading ends 63.59%. */
.live-weather{left:71.77%;top:64.30%;width:26.92%;height:18.16%;padding:0 1.4%;display:flex;flex-direction:column}
/* flex:1 + min-height:0 gives the grid the whole panel below the painted heading,
   so the readings can never spill past the frame the way a fixed calc() let them. */
.live-weather-grid{display:grid;grid-template-columns:repeat(4,1fr);flex:1 1 auto;min-height:0}
.live-weather-grid>div{display:grid;place-content:center;text-align:center;border-right:1px solid rgba(211,181,86,.2);padding:0 2px;min-width:0}
.live-weather-grid>div:last-child{border-right:0}
.live-weather-grid span{font-size:clamp(15px,1.4vw,22px);line-height:1.1}
.live-weather-grid strong{display:block;font-family:Cinzel,Georgia,serif;font-size:clamp(13px,1.25vw,19px);line-height:1.2;white-space:nowrap}
.live-weather-grid small{display:block;font-size:clamp(7px,.6vw,10px);line-height:1.25;color:var(--plate-text-dim)}

/* The hero plate, in the top-left panel. Season One painted DAY 1 in here and
   this plate existed to cover it; the Season Two panel is painted empty, so the
   plate fills it instead and needs no fill of its own. Interior measured at
   11.38%-46.35% of the 1612x975 file. */
.live-hero{
  position:absolute;z-index:22;left:2.23%;top:11.38%;width:22.21%;height:34.97%;
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:clamp(2px,.45vw,8px);padding:0 3%;overflow:hidden;
  background:transparent;color:var(--plate-text);font-family:Cinzel,Georgia,serif;text-align:center
}
/* Before the Gates open there is no day to show, so the panel leads with the
   season instead and the countdown below carries the clock. The name is set at a
   size the panel can hold, since it is words rather than two digits. */
.live-hero.is-pre-season .live-hero-day{font-size:clamp(17px,2.15vw,36px);color:var(--plate-title)}
.live-hero.is-pre-season .live-hero-event{color:var(--accent)}
.live-hero-opens{
  margin:0;font-family:Cinzel,Georgia,serif;font-size:clamp(9px,.95vw,16px);
  line-height:1.4;letter-spacing:.04em;color:#e4dbc6
}
.live-hero-day{font-size:clamp(25px,3.5vw,58px);line-height:1;letter-spacing:.02em;color:var(--plate-title)}
.live-hero-event{font-size:clamp(11px,1.3vw,22px);line-height:1.15;letter-spacing:.02em;color:var(--accent);text-transform:uppercase}
.live-hero-rule{font-size:clamp(7px,.7vw,12px);line-height:1;color:#c9a94a}
.live-hero-enter{
  margin-top:clamp(3px,.7vw,11px);padding:clamp(5px,.8vw,13px) clamp(9px,1.5vw,26px);
  border:1px solid rgba(211,181,86,.72);border-radius:5px;background:rgba(255,255,255,.03);
  color:#f3ecd8;font-family:Cinzel,Georgia,serif;font-size:clamp(9px,1vw,17px);letter-spacing:.04em;white-space:nowrap
}
.live-hero-enter:hover{background:rgba(211,181,86,.15)}
.live-hero-enter:focus-visible{outline:2px solid var(--accent-bright);outline-offset:2px}

/* The plate in Fan Vote dress. Only the button changes weight — the DAY number,
   the frame and the plate's own black fill stay exactly as painted, so the front
   page reads as the same artwork with a different call on it. */
.live-hero.is-fan-vote .live-hero-event{color:#f0e08a}
.live-hero.is-fan-vote .live-hero-rule{color:var(--accent)}
.live-hero-vote{
  margin-top:clamp(3px,.7vw,11px);padding:clamp(6px,.9vw,14px) clamp(10px,1.7vw,28px);
  border:1px solid var(--accent-bright);border-radius:5px;background:rgba(var(--accent-rgb),.18);
  color:var(--accent-pale);font-family:Cinzel,Georgia,serif;font-size:clamp(10px,1.15vw,19px);
  letter-spacing:.06em;white-space:nowrap;cursor:pointer;
  animation:fanCallPulse 2.4s ease-in-out infinite
}
.live-hero-vote:hover{background:rgba(var(--accent-rgb),.34)}
.live-hero-vote:focus-visible{outline:2px solid var(--accent-bright);outline-offset:2px}
@keyframes fanCallPulse{50%{background:rgba(var(--accent-rgb),.34);box-shadow:0 0 18px rgba(var(--accent-rgb),.38)}}
/* A visitor who has asked for less motion gets the same sign without the pulse. */
@media(prefers-reduced-motion:reduce){.live-hero-vote,.home-fan-banner{animation:none}}

/* The banner tick sits on its own in the Fan Vote card rather than inside the
   roster picker, so it needs the border the picker would otherwise have given it. */
.fan-banner-check{
  margin:10px 0 4px;border:1px solid rgba(255,255,255,.16);background:var(--surface);
  font-family:Cinzel,Georgia,serif;letter-spacing:.02em
}

/* The banner above the artwork. Full width and outside the sideways-scrolling
   box, so it is the first thing on the page on a phone rather than something
   waiting off the right-hand edge. */
.home-fan-banner{
  display:flex;align-items:center;gap:clamp(8px,1.4vw,18px);width:100%;
  margin:0 0 10px;padding:clamp(10px,1.4vw,16px) clamp(12px,1.8vw,22px);
  border:1px solid var(--accent-bright);border-radius:12px;
  background:linear-gradient(120deg,rgba(var(--green-rgb),.16),rgba(var(--accent-rgb),.1));
  color:var(--accent-pale);text-align:left;cursor:pointer;
  animation:fanCallPulse 2.8s ease-in-out infinite
}
.home-fan-banner:hover{background:linear-gradient(120deg,rgba(var(--green-rgb),.28),rgba(var(--accent-rgb),.18))}
.home-fan-banner:focus-visible{outline:2px solid var(--accent-bright);outline-offset:2px}
.home-fan-banner-mark{font-size:clamp(20px,2.2vw,30px);line-height:1;flex:none}
.home-fan-banner-words{display:grid;gap:2px;flex:1 1 auto;min-width:0}
.home-fan-banner-words strong{
  font-family:Cinzel,Georgia,serif;font-size:clamp(13px,1.4vw,20px);letter-spacing:.03em;color:var(--plate-title)
}
.home-fan-banner-words small{font-size:clamp(10px,.9vw,13px);color:var(--label-dim)}
.home-fan-banner-cta{
  flex:none;font-family:Cinzel,Georgia,serif;font-size:clamp(11px,1.1vw,16px);letter-spacing:.08em;
  padding:clamp(5px,.7vw,10px) clamp(9px,1.2vw,16px);border:1px solid rgba(215,239,97,.7);border-radius:7px;
  white-space:nowrap
}
@media(max-width:560px){
  .home-fan-banner{flex-wrap:wrap}
  .home-fan-banner-cta{width:100%;text-align:center}
}
/* Below this width main itself runs edge to edge, so the banner insets itself
   rather than looking like it has fallen off the side of the page. */
@media(max-width:820px){
  .home-fan-banner{width:calc(100% - 16px);margin:0 8px 10px}
}

/* The artwork's bar paints "SEASON TWO" at x64-158, y55-66 of the 1612x975 file
   and leaves the strip to its right flat and empty out to the gold ornament at
   x297. This plate covers the painted words and runs into that empty strip, so
   it has room to read "SEASON TWO · DAY 12" without touching the gilding. It is
   hidden until the season is actually running — before then the painting already
   says the right thing on its own. See paintSeasonFace() in app.js. */
.live-brand-day{
  position:absolute;z-index:22;left:3.85%;top:5.13%;width:14.02%;height:2.46%;
  /* The plate starts a few pixels left of the painted words so it covers them
     cleanly; the padding puts the live line back on the painting's own margin. */
  padding-left:.30%;
  display:grid;place-content:center start;
  background:#03090a;color:var(--label);font-family:Cinzel,Georgia,serif;
  font-size:clamp(7px,.8vw,13px);letter-spacing:.05em;white-space:nowrap
}

/* TODAY'S MESSAGE
   Painted interior 72.82%-85.64%, heading ends 75.90%. The record's front-page
   message used to be drawn inside the hero plate because Season One's painting
   had these words baked in; the panel is empty now, so it is drawn here. */
.live-message{
  left:34.99%;top:76.60%;width:25.56%;height:9.04%;padding:0 2%;
  display:grid;place-content:center;text-align:center;overflow:hidden
}
/* Three lines is what the panel holds. A longer message is clipped rather than
   allowed to run past the painted frame. */
.live-message-text{
  margin:0;font-family:Inter,system-ui,sans-serif;font-size:clamp(9px,.9vw,15px);
  line-height:1.5;color:var(--plate-text-dim);
  display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;overflow:hidden
}

/* KEEPER'S JOURNAL
   Painted interior 11.28%-41.54%, heading ends 15.38%. Season One's painting had
   the latest entry and the Keeper's portrait in here; Season Two paints the frame
   and nothing else, so the newest entry is drawn live and the button below is a
   real button rather than a hit box over painted words. */
.live-journal{
  left:71.84%;top:16.10%;width:26.86%;height:25.44%;padding:0 2.4%;
  display:flex;flex-direction:column;align-items:flex-start;text-align:left;
  gap:clamp(3px,.5vw,9px);overflow:hidden
}
.live-journal-kicker{
  display:block;font-family:Cinzel,Georgia,serif;font-size:clamp(7px,.68vw,11px);
  letter-spacing:.12em;color:var(--label)
}
.live-journal-day{
  display:block;margin-top:clamp(2px,.35vw,6px);
  font-family:Cinzel,Georgia,serif;font-size:clamp(11px,1.35vw,23px);line-height:1.15;color:var(--plate-title)
}
/* Three lines, then it is cut: the panel is a taste of the entry, and the button
   below is how the whole thing is read. Three rather than five because the
   panel's floor is set by the artwork — at 760px wide it is only about 117px
   tall — while the type stops shrinking at its clamp minimums, and the button
   has to keep its place at every width in between. */
.live-journal-text{
  margin:clamp(3px,.5vw,8px) 0 0;font-family:Inter,system-ui,sans-serif;
  font-size:clamp(9px,.88vw,15px);line-height:1.5;color:var(--plate-text-dim);
  display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;overflow:hidden
}
/* overflow:hidden is the guarantee, not the line clamp. The button is flex:none
   below, so it keeps its height and the body is what gives way — and a body that
   clips can never paint over it, whatever the entry says or the font falls back to. */
.live-journal-body{flex:1 1 auto;min-height:0;width:100%;overflow:hidden}
/* Before the first entry is written there is no day and no quotation, only the
   line saying so — which reads as a note rather than as an entry. */
.live-journal-body.is-empty .live-journal-kicker,
.live-journal-body.is-empty .live-journal-day{display:none}
.live-journal-body.is-empty .live-journal-text{margin-top:0;font-style:italic;color:var(--plate-text-dim)}
.live-journal-btn{
  flex:none;margin-bottom:clamp(2px,.5vw,8px);
  padding:clamp(4px,.65vw,10px) clamp(8px,1.2vw,20px);
  border:1px solid rgba(211,181,86,.72);border-radius:5px;background:rgba(255,255,255,.03);
  color:#f3ecd8;font-family:Cinzel,Georgia,serif;font-size:clamp(8px,.85vw,14px);
  letter-spacing:.05em;white-space:nowrap;cursor:pointer
}
.live-journal-btn:hover{background:rgba(211,181,86,.15)}
.live-journal-btn:focus-visible{outline:2px solid var(--accent-bright);outline-offset:2px}

/* The bottom bar's last cell. Season One painted "TIME IN EDEN 9:41 AM DAY 1"
   into it and this plate covered that; Season Two leaves the cell empty, so the
   plate simply fills it. Interior measured at 77.98%/88.10%, 20.60%x10.05%. */
.live-time{
  position:absolute;z-index:24;left:77.98%;top:88.10%;width:20.60%;height:10.05%;
  display:grid;place-content:center;text-align:center;
  background:transparent;color:var(--plate-text);font-family:Cinzel,Georgia,serif
}
.live-time>small{display:block;font-size:clamp(8px,.7vw,12px);letter-spacing:.06em;color:#e2d8bc}
.live-time>strong{display:block;font-size:clamp(15px,1.5vw,25px);line-height:1.25;color:#f3dfa0;white-space:nowrap}
/* direct child only — the nested day-number span must stay inline or "DAY 1" breaks in two. */
.live-time>span{display:block;font-size:clamp(8px,.7vw,12px);color:var(--label-dim);white-space:nowrap}

@media(max-width:820px){
  main{width:100%!important}
  .final-dashboard-scroll{overflow-x:auto;-webkit-overflow-scrolling:touch}
  .final-dashboard{min-width:760px}
}

/* KEEPER PROFILES
   Every Keeper name in the terminal is an <a href="#keeper/handle">, so chips,
   reputation rows and ledger entries all need link treatment, not just colour. */
a.chip,a.reputation-row,.ledger-keeper{text-decoration:none;transition:background .18s,color .18s,border-color .18s}
a.chip{display:inline-flex;align-items:center;gap:8px;padding-left:5px;border:1px solid rgba(255,255,255,.08)}
a.chip:hover,a.chip:focus-visible{color:var(--ink);background:var(--gold);border-color:var(--gold)}
/* The portrait beside a Keeper's name — a monogram stands in until Control
   uploads one, so a roster never renders as a ragged mix of faces and text. */
.keeper-face{
  width:26px;height:26px;flex:0 0 26px;border-radius:50%;object-fit:cover;display:grid;place-content:center;
  background:rgba(229,201,120,.16);color:var(--gold);font-family:Cinzel,serif;font-size:.68rem;letter-spacing:.02em
}
a.chip:hover .keeper-face.is-monogram,a.chip:focus-visible .keeper-face.is-monogram{background:rgba(0,0,0,.22);color:var(--ink)}
.ledger-keeper .keeper-face{width:20px;height:20px;flex-basis:20px;font-size:.6rem}
a.reputation-row{color:inherit}
a.reputation-row:hover,a.reputation-row:focus-visible{border-color:var(--gold);background:rgba(229,201,120,.08)}
.ledger-keeper{display:inline-flex;align-items:center;gap:7px;color:var(--text);font-weight:700}
.ledger-keeper:hover{color:var(--gold)}
.back-link{display:inline-block;color:var(--muted);text-decoration:none;margin-bottom:22px;font-size:.92rem}
.back-link:hover{color:var(--gold)}

.keeper-head{display:flex;align-items:center;gap:clamp(16px,3vw,28px);flex-wrap:wrap}
.keeper-avatar{
  width:clamp(78px,10vw,112px);aspect-ratio:1;border-radius:50%;display:grid;place-content:center;overflow:hidden;position:relative;
  font-family:Cinzel,serif;font-size:clamp(1.6rem,3.4vw,2.5rem);color:var(--ink);
  background:radial-gradient(circle at 30% 25%,#fff8dd,var(--field));
  box-shadow:0 0 34px color-mix(in srgb,var(--field) 45%,transparent)
}
/* The monogram sits underneath, so a portrait that fails to load falls back to it. */
.keeper-avatar img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block}
.keeper-identity{flex:1 1 320px}
.keeper-identity .kicker{color:var(--field)}
.keeper-identity h1{font-size:clamp(2rem,5vw,3.4rem);margin:10px 0 12px;word-break:break-word}
.keeper-identity p{color:var(--muted);line-height:1.6;margin:0;max-width:620px}
.keeper-tags{display:flex;flex-wrap:wrap;gap:8px;margin-top:16px}
.keeper-tags .chip{color:var(--text)}
.field-chip{border-color:var(--field)!important}
.ballot-chip{color:#ffb2a8!important;border-color:rgba(255,143,130,.5)!important;background:rgba(255,93,78,.1)}
.ballot-chip:hover{color:var(--ink)!important;background:var(--danger)!important;border-color:var(--danger)!important}

.keeper-stats{display:grid;grid-template-columns:repeat(4,1fr);gap:14px;margin-top:34px}
.keeper-stats .status-card strong{font-size:1.6rem}
.keeper-panels{display:grid;grid-template-columns:1.35fr 1fr;gap:16px;align-items:start}
.keeper-panels .timeline-card{margin-top:30px}
.keeper-panels .roster{margin-top:16px}
@media(max-width:900px){.keeper-stats{grid-template-columns:repeat(2,1fr)}.keeper-panels{grid-template-columns:1fr}.keeper-panels .timeline-card{margin-top:16px}}
@media(max-width:520px){.keeper-stats{grid-template-columns:1fr}}

/* Control's portrait uploader */
.portrait-actions{display:flex;gap:10px;margin-top:16px}
.portrait-actions .primary,.portrait-actions .ghost{flex:1}
.portrait-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(74px,1fr));gap:10px;margin-top:12px}
.portrait-tile{margin:0;text-align:center}
.portrait-tile img{width:100%;aspect-ratio:1;object-fit:cover;border-radius:14px;border:1px solid var(--line);display:block}
.portrait-tile figcaption{color:var(--muted);font-size:.7rem;margin-top:6px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* Control's view of the mark the lock is currently set to */
.vault-admin-current{display:flex;gap:14px;align-items:center;margin:14px 0 4px;padding:12px;border:1px solid var(--line);border-radius:14px;background:rgba(255,255,255,.035)}
.vault-admin-current img{width:72px;height:72px;object-fit:contain;flex:none;border-radius:12px;background:rgba(0,0,0,.25);padding:8px}
.vault-admin-current>div{display:grid;gap:5px;min-width:0}
.ghost-link{color:var(--gold);font-size:.8rem;text-decoration:underline;text-underline-offset:3px;justify-self:start}


/* The Fan Vote. The leaf beside KEEPERS REMAINING is one of the two doors to the
   unlisted page, so — like the cloud sigil that opens the Mosaic — the button is
   stripped back to the bare glyph and has to stay pixel-identical to the plain
   leaf in the panel beside it. */
.leaf-sigil{padding:0;border:0;background:none;color:inherit;font:inherit;line-height:inherit}
.leaf-sigil:focus-visible{outline:2px solid var(--gold);outline-offset:2px;border-radius:4px}

.fan-team{display:flex;align-items:center;justify-content:center;gap:10px;padding:12px 16px;border:1px solid var(--field,var(--line));border-radius:14px;background:rgba(255,255,255,.035);color:var(--field,var(--gold));font-family:Cinzel,serif;font-size:1.05rem;text-align:center}
.fan-team small{display:block;color:var(--muted);font-family:Inter,sans-serif;font-size:.72rem;letter-spacing:.16em;text-transform:uppercase}
.fan-clock{margin:16px 0 4px;text-align:center;font-family:Cinzel,serif;font-size:clamp(1.6rem,5vw,2.3rem);color:var(--gold);letter-spacing:.06em}
.fan-clock small{display:block;color:var(--muted);font-family:Inter,sans-serif;font-size:.72rem;letter-spacing:.18em;text-transform:uppercase;margin-bottom:6px}
.fan-clock.urgent{color:var(--danger)}
.fan-candidate{display:flex;align-items:center;gap:14px}
.fan-face{position:relative;flex:none;width:44px;height:44px;border-radius:50%;overflow:hidden;background:rgba(255,255,255,.07);border:1px solid var(--line);display:grid;place-items:center;font-family:Cinzel,serif;color:var(--gold)}
.fan-face img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.fan-note{color:var(--muted);font-size:.8rem;text-align:center;margin:14px 0 0}

/* ============================================================
   KEEPER RANKINGS
   ============================================================ */

/* The sign on the front page. It sits outside the artwork, above the dashboard,
   for the same reason the ballot banner does: the artwork scrolls sideways on a
   phone and anything painted inside it can begin the visit off screen. The
   graphic carries its own frame and its own transparent background, so the
   button is only a hit box around it — no border, no plate, nothing to fight the
   gold edge already in the picture. */
.home-rankings-btn{
  display:block;width:100%;margin:0 0 14px;padding:0;
  background:none;border:0;cursor:pointer;line-height:0
}
.home-rankings-art{
  display:block;width:100%;height:auto;
  filter:drop-shadow(0 14px 30px rgba(0,0,0,.55));
  transition:transform .2s ease,filter .2s ease
}
.home-rankings-btn:hover .home-rankings-art{
  transform:translateY(-2px) scale(1.006);
  filter:drop-shadow(0 18px 38px rgba(0,0,0,.6)) brightness(1.05)
}
.home-rankings-btn:focus-visible{outline:2px solid var(--gold);outline-offset:4px;border-radius:14px}
@media(prefers-reduced-motion:reduce){
  .home-rankings-art,.home-rankings-btn:hover .home-rankings-art{transition:none;transform:none}
}
/* Below this width main runs edge to edge, so the sign insets itself rather than
   looking like it has fallen off the side of the page — as the banner does. */
@media(max-width:820px){
  .home-rankings-btn{width:calc(100% - 16px);margin:0 8px 12px}
}

/* The same graphic standing in for the page title on the rankings page itself,
   so arriving from the front page lands on the sign that was pressed. */
.rankings-banner{
  display:block;width:100%;max-width:820px;height:auto;margin:0 0 6px;
  filter:drop-shadow(0 14px 30px rgba(0,0,0,.5))
}

/* The CONTROL ROOM sign. The artwork is square and says everything the page has
   to say, so it is the whole page: centred, capped so it cannot tower past a
   tall window, and lifted off the background by the same shadow the other
   full-width plates use. No frame — the picture has its own doorway. */
.control-room-art{
  display:block;width:100%;max-width:min(900px,82vh);height:auto;margin:0 auto;
  border-radius:16px;
  filter:drop-shadow(0 18px 44px rgba(0,0,0,.6))
}
/* Below this width main runs edge to edge, so the sign insets itself rather than
   touching both sides of the screen. */
@media(max-width:820px){
  .control-room-art{width:calc(100% - 16px)}
}

/* The ranking rows reuse the Harvest Board's .score-row, but each one is a link
   to the Keeper it names, so it needs the same treatment a.reputation-row has. */
a.score-row{
  color:inherit;text-decoration:none;
  transition:background .18s,border-color .18s,transform .18s
}
a.score-row:hover,a.score-row:focus-visible{
  border-color:var(--gold);background:rgba(229,201,120,.08)
}
a.score-row:focus-visible{outline:2px solid var(--gold);outline-offset:2px}

/* ============================================================
   ONE FIELD · the merge
   ============================================================ */

/* Its own heading and its own full-width card below the grid of four, because it
   is the ground the four become rather than a fifth standing beside them. */
.one-field-section{margin-top:44px}
.one-field-head{margin-bottom:22px}
.one-field-head .kicker{color:var(--gold)}
.one-field-card{
  border-color:rgba(229,201,120,.5);
  background:linear-gradient(145deg,var(--card-lift-top),var(--card-lift-bottom))
}
.one-field-card:before{height:6px}
.one-field-card .field-score{font-size:2.4rem}

/* ============================================================
   KEEPER RECORDS · duplicate cleanup
   ============================================================ */

.duplicate-list{display:grid;gap:10px;margin:12px 0 16px}
.duplicate-group{
  display:grid;gap:9px;padding:11px 12px;border-radius:12px;
  border:1px solid rgba(255,255,255,.1);background:rgba(255,255,255,.035)
}
.duplicate-variants{display:flex;flex-wrap:wrap;gap:7px}
/* Every spelling found, with the points it is sitting on, so a merge can be read
   before it is pressed. The one that survives is marked in gold rather than
   chosen by hand: it is the spelling the rosters already use. */
.duplicate-variant{
  display:inline-flex;align-items:center;gap:7px;
  padding:6px 9px;border-radius:999px;font-size:.86rem;
  border:1px solid rgba(255,255,255,.14);background:rgba(255,255,255,.04);color:var(--muted)
}
.duplicate-variant b{color:var(--text);font-size:.82rem}
.duplicate-variant em{
  font-style:normal;font-size:.7rem;letter-spacing:.06em;text-transform:uppercase;color:var(--green)
}
.duplicate-variant.keeping{
  border-color:rgba(229,201,120,.6);background:rgba(229,201,120,.1);color:var(--gold)
}
.duplicate-variant.keeping b{color:var(--gold)}
.duplicate-actions{
  display:flex;align-items:center;justify-content:space-between;gap:10px;flex-wrap:wrap
}
.duplicate-actions small{color:var(--muted);font-size:.82rem}
.duplicate-actions small strong{color:var(--gold)}
.duplicate-actions .icon-button{flex:none}
#removeEmptyKeepers[disabled]{opacity:.45;cursor:not-allowed}


/* ============================================================
   THE DAY'S MESSAGE, IN EITHER DRESS
   ============================================================ */

/* Season One drew the day's message inside the hero plate, because its painting
   had no panel for one; Season Two paints TODAY'S MESSAGE its own frame, and
   .live-message fills it. The paragraph stays in the markup either way and the
   dress decides which of the two is showing, so neither season needs the other
   season's HTML. */
.live-hero-message{
  display:none;margin:0;
  font-family:Inter,system-ui,sans-serif;font-size:clamp(9px,.9vw,15px);
  line-height:1.5;color:var(--plate-text-dim);
  -webkit-box-orient:vertical;-webkit-line-clamp:4;overflow:hidden
}

/* ============================================================
   THE GARDEN'S DRESS · Control's card
   ============================================================ */

.theme-choices{display:grid;gap:9px;margin:12px 0 14px}
.theme-choice{
  display:flex;align-items:flex-start;gap:11px;padding:11px 12px;
  border:1px solid rgba(255,255,255,.12);border-radius:12px;
  background:rgba(255,255,255,.035);cursor:pointer
}
.theme-choice:hover{border-color:var(--accent);background:rgba(var(--accent-rgb),.08)}
.theme-choice:has(input:checked){border-color:var(--accent);background:rgba(var(--accent-rgb),.12)}
.theme-choice input{accent-color:var(--accent);width:16px;height:16px;flex:none;margin-top:4px}
.theme-choice strong{display:block;font-family:Cinzel,serif;font-size:.98rem}
.theme-choice small{display:block;color:var(--muted);font-size:.82rem;line-height:1.45;margin-top:4px}
.theme-actions{display:flex;gap:10px}
.theme-actions .primary,.theme-actions .ghost{flex:1}

/* ============================================================
   SEASON ONE · the dress that was kept
   ============================================================
   Colour travels as custom properties from the preset in data.js, so the only
   rules that need to live here are the ones a colour cannot carry: where each
   live panel sits on the artwork, and whether it covers the painting or sits
   inside it.

   Season One's painting had its values baked into it — DAY 1, the journal
   entry, TIME IN EDEN 9:41 AM — so every panel was an opaque plate with its own
   gilding, laid over the painted words and measured against
   eden-dashboard-final.png. Season Two paints empty frames instead, so its
   plates are transparent and frameless and the artwork's own gold shows
   through. Switching back is therefore a restoration, not a redesign: every
   rectangle below is the one this stylesheet carried before Season Two
   repainted the scene. */

/* The plates go back to being covers. */
html[data-season="one"] .live-fields-panel,
html[data-season="one"] .live-countdown,
html[data-season="one"] .live-keepers,
html[data-season="one"] .live-weather,
html[data-season="one"] .live-time{
  background:linear-gradient(145deg,rgba(15,19,14,.99),rgba(4,8,5,.99));
  border:1px solid rgba(211,181,86,.58);
  box-shadow:inset 0 0 0 4px rgba(0,0,0,.28),inset 0 0 26px rgba(0,0,0,.75)
}

/* Season Two's headings are painted into the artwork, so the plates' own are
   kept for screen readers only. Season One's frames were empty of words, so
   these come back out of the clip and are read with the eyes again. */
html[data-season="one"] .live-fields-panel>h2,
html[data-season="one"] .live-keepers>h2,
html[data-season="one"] .live-weather>h2{
  position:static;width:auto;height:auto;margin:0 0 10px;padding:0;
  overflow:visible;clip-path:none;white-space:normal;
  font-family:Cinzel,Georgia,serif;font-size:clamp(15px,1.45vw,24px)
}
html[data-season="one"] .live-keepers>h2{font-size:clamp(11px,1.15vw,17px);margin:0 0 2px}
html[data-season="one"] .live-weather>h2{font-size:clamp(12px,1.25vw,18px);margin:0 0 4px}
html[data-season="one"] .live-fields-panel>h2 span,
html[data-season="one"] .live-keepers>h2 span,
html[data-season="one"] .live-weather>h2 span{color:var(--accent)}

/* Neither of these panels existed in Season One: the day's message sat in the
   hero plate and the journal entry was part of the painting itself. */
html[data-season="one"] .live-message,
html[data-season="one"] .live-journal{display:none}
html[data-season="one"] .live-hero-message{display:-webkit-box}

/* The measured rectangles, against eden-dashboard-final.png. */
html[data-season="one"] .live-fields-panel{left:1.24%;top:48.92%;width:27.42%;height:34.97%;padding:1.7% 1.5%}
html[data-season="one"] .live-keepers{left:auto;right:1.24%;top:43.79%;width:27.17%;height:13.85%;padding:1.4% 1.8%}
html[data-season="one"] .live-weather{left:auto;right:1.24%;top:59.69%;width:27.17%;height:22.36%;padding:1.35% 1.4%}
html[data-season="one"] .live-hero{left:1.99%;top:11.08%;width:22.58%;height:34.36%;background:#040603}
html[data-season="one"] .live-brand-day{left:3.23%;top:4.72%;width:11.91%;height:3.28%;padding-left:.62%;background:#010301}
html[data-season="one"] .live-time{left:87.22%;top:87.99%;width:11.23%;height:10.15%}

/* The countdown. Its label is a plate of its own in either dress — it is a line
   that has to read two different ways and the words underneath it can only be
   painted one — but in Season One it sits inside the opaque plate rather than
   over bare artwork, so it loses its own fill and the values below make room
   for it. Percentage padding resolves against the artwork's width, which is
   what the rest of this file measures in too. */
html[data-season="one"] .live-countdown{
  left:34.86%;top:55.49%;width:25.81%;height:15.08%;padding:2.1% 1.5% 1.15%
}
html[data-season="one"] .live-countdown-label{
  left:34.86%;top:56.6%;width:25.81%;height:2.05%;z-index:23;
  background:none;font-size:clamp(8px,.72vw,12px)
}
