/* Fonts, heading treatment and header chrome all come from the base
   (sxds-rf.css) plus Alex's header block below — mirroring
   artist-admin-branding.css so this portal renders identically.
   Removed 2026-era local overrides: the @font-face for "Founders
   Condensed" (base ships "Founders-Condensed" via var(--font-headline)),
   the global uppercase/font-family heading rule, and the black-header /
   white-logo / yellow-nav-pill branding. */

div.field-information p{
margin-top: -.9em;
margin-bottom: 1.5em;
color: #606060;
font-size: .875em;
}
button#wf-btn-submit:hover,
a.mdBtnR-primary:hover{
background-color: #ffca51 !important;
border-color: #ffca51 !important;
}
button#wf-btn-submit:hover span,
a.mdBtnR-primary:hover span{
color: black !important;
}
nav#content-nav ul li a img {
    display: none;
}

/* Begin Alex */
/* Header — copied from the "Begin Alex" block in artist-admin-branding.css.
   Marker kept so the two files stay greppable against each other. */
.rf-org-header-container .header-interior {
  max-width: 1240px !important;

  @media (min-width: 1200px) {
    max-width: 1440px !important;
    padding: 0 !important;
  }
}
.rf-org-header-container .header-logo,
.rf-org-header-container .header-logo-link,
.rf-org-header-container .header-logo-img {
  max-width: 300px !important;
}
div.rf-org-header-container header {
    position: fixed;
    border-bottom: 1px solid rgb(216, 216, 216);
    padding: 0 20px;
}
div#rf-content {
  margin-top: 80px;
}

/* The configured logo asset (sessions-portal_...svg) is the WHITE wordmark
   drawn for the old black header. On the now-white header it is invisible,
   so force it black. STOPGAP: the real fix is a black logo asset, the way
   Artist Admin has artist-admin-logo-black_...svg — swap the branding
   profile's logo and this filter can go. brightness(0) is idempotent, so it
   stays correct if a black asset is swapped in first.
   The explicit height is also required: this SVG has no intrinsic
   width/height, so without it img#logo-url renders 0x0. */
img#logo-url {
    height: 1.5rem;
    vertical-align: top;
    width: auto;
    filter: brightness(0);
}
/* Nav items have no gap of their own; without this the links run together.
   Verified live: with the rule margin-left is 40px and Contact/Deadlines sit
   100px apart; without it both go to 0 and collapse to 60px. Artist Admin does
   not need this because its header nav renders with a different structure. */
@media (min-width: 1100px) {
    .rf-org-header-container header nav > ul > li {
        position: relative;
        margin-left: 40px;
    }
}

/* ===========================
   PORTAL HEADING OVERRIDES — local mirror
   ===========================
   sxds-rf.css ships a shared heading scale gated on [class*="portal-page"] /
   [class*="portal-task"] (see its "PORTAL HEADING OVERRIDES" block). This
   workflow's URI is `session-production-guide`, so its body classes are
   ...-guide-page-home / -guide-task / -guide-tasks and never match that hook —
   which is why headings here rendered at Alex's bare h1 40px instead of the
   24px every other portal gets.

   Mirrored verbatim against this portal's slug, in @layer base for the same
   cascade behaviour as the original. If the workflow URI is ever renamed to
   contain "portal", this whole block becomes redundant and should be deleted. */
/* Black primary nav pill, matching Artist Admin. MUST be layered: the RainFocus
   workflow stylesheet styles this pill with a layered !important, and for
   !important declarations layer order reverses, so an unlayered !important here
   loses (verified live: unlayered = still outlined, @layer base = black).
   Artist Admin gets this from its RF branding profile with no CSS at all -
   set the action-button colour there and this block can go. */
@layer base {
  nav#content-nav a.primary-nav-action {
    background-color: #000 !important;
    color: #fff !important;
  }
}

@layer base {
  [class*="session-production-guide-task"] h1,
  [class*="session-production-guide-page"] h1 {
    font-size: 24px !important;
    line-height: 1.2 !important;
  }
  [class*="session-production-guide-task"] h2,
  [class*="session-production-guide-page"] h2 {
    font-size: 24px !important;
    line-height: 1.2 !important;
  }
  [class*="session-production-guide-task"] h2 {
    text-transform: none !important;
  }
  [class*="session-production-guide-task"]:not([class*="session-production-guide-tasks"]) h1 {
    text-transform: none !important;
  }
  [class*="session-production-guide-task"]:not([class*="session-production-guide-tasks"]) h2 {
    text-transform: uppercase !important;
  }
  [class*="session-production-guide-task"] h3 {
    font-size: 18px !important;
    line-height: 1.2 !important;
  }
  [class*="session-production-guide-tasks"] h3 {
    text-transform: uppercase !important;
  }
  [class*="session-production-guide-page"] h3 {
    font-size: 20px !important;
    line-height: 1.2 !important;
  }
  [class*="session-production-guide-page"] h5 {
    font-size: 16px !important;
    line-height: 1.2 !important;
    font-weight: normal !important;
    text-transform: none !important;
  }
  [class*="session-production-guide-task"] .keep-bullets,
  [class*="session-production-guide-page"] .keep-bullets {
    margin: 0 !important;
  }
}

/* ===========================
   TASK DETAIL HEADING HIERARCHY — local divergence from the mirror above
   ===========================
   The mirror hands a task detail page h1 24px sentence-case, h2 24px UPPERCASE
   and h3 18px. Measured live on sxsw27, that inverts twice:

     - The panel title h2 ("SPEAKERS", 24px uppercase) reads bigger and heavier
       than the page h1 above it (the session title, 24px sentence case).
       Alex diagnosed the same illusion in artist-admin-branding.css
       ("at equal size the uppercase h2 reads bigger than the h1") and fixed it
       there by shrinking the section heading, not by touching the h1.
     - A config text-block h3 ("Confirmed Session Information", 18px in the
       CONDENSED face) reads smaller than the RF field labels underneath it
       ("Title", 16px in the TEXT face, weight 600) -- 18px of condensed is
       optically narrower than 16px of text, so 18 > 16 on paper loses on
       screen. 20px is the first step that reads bigger than the labels.

   Scoped by ROLE rather than by tag, which is how artist-admin does it: the RF
   panel header (.md-frame-header .md-headline) and the RF config rich-text
   block (.rf-text-container). Deliberately NOT bare `h3` -- the speaker roster
   group headings below are h3s at 18px uppercase and must stay under the 20px
   panel title, so they are left out of the bump.

   Note this goes WIDER than the artist-admin precedent, on purpose. Alex scoped
   his to one task (body.task-photos); these two apply to EVERY task detail page
   in this portal, because the inversion is in the shared scale rather than in
   one page's markup. So every panel title and every config rich-text h3 on a
   task page moves, not just the two that were reported. Swept live before
   shipping; see the commit for which tasks were checked.

   Anchored on `body`, not left bare: [class*=] is evaluated per element, so an
   unanchored selector would also match any inner wrapper whose own class
   contained the singular slug -- which would defeat the :not() guard below and
   leak onto the tasks LIST. The mirror above can afford the bare form because
   its sizes are uniform across list and detail; these are not.

   :not() excludes the plural tasks LIST, whose own scale (h1 40px via ::before,
   h2 24px session title, h3 18px uppercase row titles) already reads correctly.

   @layer base + !important + higher specificity, same cascade reasoning as the
   mirror -- the panel-title selector is (0,4,2) and the rich-text one (0,3,2),
   both beating the mirror's [class*="session-production-guide-task"] h2 / h3 at
   (0,1,1), and both sit later in the same layer so they win on order too.
   The RULE outlives the mirror -- it would still be wanted if the workflow
   URI were renamed to contain "portal" and the mirror deleted -- but these two
   selectors key off the same URI slug, so re-slug them along with it rather than
   leaving them behind. */
@layer base {
  /* Panel title: below the page h1, uppercase kept (house style, and it keeps
     the 18px uppercase roster headings below it). */
  body[class*="session-production-guide-task"]:not([class*="session-production-guide-tasks"]) .md-frame-header .md-headline h2 {
    font-size: 20px !important;
  }
  /* Config text-block section headings: above the 16px field labels. */
  body[class*="session-production-guide-task"]:not([class*="session-production-guide-tasks"]) .rf-text-container h3 {
    font-size: 20px !important;
  }
}
body .rf-overlay-new ul li{
    display: list-item;
    list-style-position: outside;
    margin-left: 2em;
    font-size: .9em;
    margin-bottom: .3em;
}
body .rf-overlay-new p,
body .rf-overlay-new p:last-child {
    margin: .9em 0 .9em 0;
    font-size: .9em;
}
.rf-overlay-new ul, .rf-overlay-new ol{
    margin-bottom: 0 0 .9em 0;
    font-size: .9em;
}
body .rf-overlay-new.rf-overlay-bottom.rf-overlay-centered.rf-tooltip {
       transform: translateX(-5%) translateY(0%);
}
body .rf-overlay-new.rf-overlay-top.rf-overlay-centered.rf-tooltip {
       transform: translateX(-5%) translateY(-100%);
}
body .rf-overlay-new.rf-has-arrow.rf-overlay-bottom.rf-tooltip:after{
       transform: translateX(-36%) rotate(45deg);
    left: 4%;
}
body .rf-overlay-new.rf-has-arrow.rf-overlay-top.rf-tooltip:after{
       transform: translateX(-36%) rotate(225deg);
      left: 4%;
}
.rf-checkbox-container span.text-info {
    color: red !important;
    display: block;
    margin-bottom: .3em;
}


@media screen and (max-width:500px){
    body .rf-overlay-new.rf-overlay-bottom.rf-overlay-centered.rf-tooltip,
    body .rf-overlay-new.rf-overlay-top.rf-overlay-centered.rf-tooltip {
           transform: none;
           left: 6% !important;
          max-width: 84% !important;
            min-width: auto !important;
    }
}
body .rf-overlay-new.rf-overlay-top.rf-overlay-centered.rf-tooltip {
       transform: translateX(0%) translateY(-100%);
       left: 6% !important;
       max-width: 84% !important;
        min-width: auto !important;
}

body .rf-overlay-new.rf-has-arrow.rf-overlay-bottom.rf-tooltip:after,
body .rf-overlay-new.rf-has-arrow.rf-overlay-top.rf-tooltip:after{
      left: 8%;
}
.rf-tooltip ul {
    margin-top: 10px;
}
body .rf-tooltip ul li {
    margin-bottom: 10px;
}

.description li{
    margin-bottom: 5px;
    list-style-type: disc !important;
    margin-left: 35px;
}
.description ul {
    margin-bottom: 20px;
}
.wf-form-element-div li {
    list-style-position: outside !important;
    margin-left: 15px;
    margin-bottom: 10px;
}
/* Task forms: uniform field widths -- PAGE AND MODAL.

   RF sizes every .wf-form-element-div to its own content, so each select, text
   input and textarea renders at a different width. Measured live on sxsw27
   before this rule: 189-435px across the change-request tasks, 176-503px inside
   the speaker modal, and a 197px box around the read-only Description textarea
   on Current Session Information. The width sits on the wrapper -- the control
   just fills it -- so a uniform width on the wrapper is what evens them out.
   600px matches artist-admin (artist-admin-branding.css), which is the look
   we're matching here.

   Unlike the "clean up speaker information" block below, this one is NOT
   prefixed with #rf-content: the participant/speaker-request modal is exactly
   where the ragged widths are worst, and the body still carries the task class
   while the modal is open, so the plain body-class scope reaches it.

   Deliberately hidden fields are safe, but for two different reasons -- worth
   keeping straight if you ever debug why a field is or isn't hiding:

     - Select Role (div#wf-1761086587411001etxW, below) wins an actual
       width-vs-width fight. It is a bare unlayered #id rule, so it outranks
       these class-based selectors on specificity and keeps its 1px.
     - Everything else (#wf-1788198753772001aNyJ, #wf-1748024194176001hUAJ and
       friends, in the speaker-modal @layer base block near the end of this
       file) is display:none. The box is out of layout entirely, so no width
       from any selector can bring it back.

   Verified live in the speaker-reviewed modal: all of them stayed at 0x0 or
   1x1 with this rule active.

   Checkboxes and radios are left alone on purpose, same as artist-admin. The
   task LIST page (...-tasks, which contains the ...-task substring) renders no
   .wf-form-element-div at all, so it needs no :not() guard.

   This block used to carry an exception restoring width:auto to the session title
   on the two leader review tasks. It was a hedge against a future in which RF
   rendered that attribute with a real input inside, which would have forced an
   out-of-flow box to 600px and overlapped the content below it. The title is in
   flow now (see the block near the end of this file), so a 600px cap would just
   wrap the text like any other field -- the hazard the hedge existed for is gone,
   and the exception went with it. For the record it does not match today either:
   probed live on both pages, div#wf-formSession-title matches none of the three
   selectors above -- a read-only attribute renders as .rf-read-only holding a
   .readOnly-value and a bare input[type=hidden], with no .rf-input wrapper for the
   third selector to find. */
body[class*="session-production-guide-task"] .wf-form-element-div:has(textarea),
body[class*="session-production-guide-task"] .wf-form-element-div:has(select),
body[class*="session-production-guide-task"] .wf-form-element-div:has(.rf-input input) {
    width: 600px !important;
    max-width: 100% !important;
}
/* Clean up speaker information -- PAGE ONLY.

   These ids are attributes that render BOTH as a read-only speaker line on the task
   page and as real form fields inside the participant modal. Unscoped, this block
   reached the modal too: it hid the "Email" label and put a stray " - " above the
   input, which is what an organizer was seeing instead of a labelled field.

   #rf-content is what separates them. RainFocus portals the modal out as a direct
   child of <body>, outside #rf-content entirely (verified live), so prefixing these
   selectors keeps the display treatment on the page and off the form. */
#rf-content div#wf-1748023947712001PX7R,
#rf-content div#wf-1748024120344001d5V8,
#rf-content div#wf-1748024194176001hUAJ,
#rf-content div#wf-1748026528838001HKbD,
#rf-content div#wf-1748026547938001llHE,
#rf-content div#wf-1748026630617001uWZL,
#rf-content div#wf-1748265644664001YlUS,
#rf-content div#wf-1748265967418001DvV0,
#rf-content div#wf-1748265994988001uyZt,
#rf-content div#wf-1748268999281001YB81,
#rf-content div#wf-1748269020128001KqQq,
#rf-content div#wf-1748269040813001KTXU
{
   display: inline-block;
   padding-right: 5px;
}
/* label */
#rf-content div#wf-1748023947712001PX7R label,
#rf-content div#wf-1748024120344001d5V8 label,
#rf-content div#wf-1748024194176001hUAJ label,
#rf-content div#wf-1748026528838001HKbD label,
#rf-content div#wf-1748026547938001llHE label,
#rf-content div#wf-1748026630617001uWZL label,
#rf-content div#wf-1748265644664001YlUS label,
#rf-content div#wf-1748265967418001DvV0 label,
#rf-content div#wf-1748265994988001uyZt label,
#rf-content div#wf-1748268999281001YB81 label,
#rf-content div#wf-1748269020128001KqQq label,
#rf-content div#wf-1748269040813001KTXU label{
   display: none;
}
/* inner divs */
#rf-content div#wf-1748023947712001PX7R div,
#rf-content div#wf-1748024120344001d5V8 div,
#rf-content div#wf-1748024194176001hUAJ div,
#rf-content div#wf-1748026528838001HKbD div,
#rf-content div#wf-1748026547938001llHE div,
#rf-content div#wf-1748026630617001uWZL div,
#rf-content div#wf-1748265644664001YlUS div,
#rf-content div#wf-1748265967418001DvV0 div,
#rf-content div#wf-1748265994988001uyZt div,
#rf-content div#wf-1748268999281001YB81 div,
#rf-content div#wf-1748269020128001KqQq div,
#rf-content div#wf-1748269040813001KTXU div{
   display: inline-block;
   padding-top: 0px;
}
/* email */
#rf-content div#wf-1748024194176001hUAJ:before,
#rf-content div#wf-1748026630617001uWZL:before,
#rf-content div#wf-1748265994988001uyZt:before,
#rf-content div#wf-1748269040813001KTXU:before {
    content: " - ";
}

/* remove boxes around comments */
#wf-1756220313237001ylk0 .md-frame {
    background-color: #EEEEEE;
}
h3 {
    margin-bottom: 10px !important;
    margin-top: 20px !important;
}
/* Add border above comments section */
div#wf-temp_a1757099137052{
    border-top: 1px solid;
    border-color: var(--rf-brand-color-border);
    padding-top: 30px;
    margin-top: 30px;
}
/* Gray out read-only text areas and text boxes.

   Kept, even though it looks dead. Probed live: no #wf-formSession-Abstract exists on
   any of the three pages that render the read-only Description textarea. But the
   wf-formSession-* namespace is exactly what the two TRACK-LEADER review tasks use --
   see #wf-formSession-title near the end of this file, scoped to precisely those two
   pages -- and those tasks only appear once a change request is pending, so there was
   no way to open one and check. Deleting this on the strength of three pages that are
   not the likely ones risks stripping the grey off an EDITABLE box and making it read
   as more editable, which is the exact inverse of what the block below is for.
   Where the field IS read-only the block below supersedes this anyway (a layered
   !important beats an unlayered normal declaration), so keeping it costs nothing.
   Delete it once someone can open Review/Approve Description Change Request with a
   live request and confirm the id is absent. */
div#wf-formSession-Abstract textarea{
       background-color: #EEEEEE;
}
/* Read-only textareas: print the value, don't draw a box around it.

   RainFocus renders a read-only attribute two different ways and nothing in the config
   says which you get: most come back as .rf-read-only wrapping a .readOnly-value div --
   the Title on Current Session Information, plain 16px Founders-Text in rgb(80,80,80) --
   but a long-text attribute comes back as a real <textarea readonly>. Same value, same
   permission, opposite affordance: a white box, 1px rgb(216,216,216), 4px radius,
   scrollbar. An organizer reads that as "type here" and cannot.

   Measured live on sxsw27: the Description on Current Session Information rendered
   600x81 around 214px of text, so two thirds of it sat behind a scrollbar as well as
   looking editable. On the EDU session the same box held one short line and was mostly
   empty, which reads even more like an unfilled field. Worst on Description Change
   Request, where the read-only "Current:" box and the editable "Request Change:" box
   under it were pixel-identical.

   Stripping the chrome is the whole fix. The font, size, colour and line-height already
   match .readOnly-value exactly, so with the box gone it renders as the same plain text
   the Title does -- nothing here restyles the type.

   THE WHOLE BLOCK IS GATED ON @supports, deliberately, and the gate is load-bearing
   rather than progressive-enhancement politeness. field-sizing:content is what lets the
   box grow to its content: a textarea's height comes from its rows attribute (3 here)
   and no CSS length can count lines. Strip the chrome WITHOUT it and the field keeps
   the 81px height and the scrollbar while losing the border, background and padding --
   i.e. the text still stops mid-sentence, but the frame that explained why it stopped
   is gone. That is worse than the box we started with. So where field-sizing is not
   supported this rule does nothing at all and the field renders exactly as it does
   today. Do not lift these declarations out of the @supports block.

   width is pinned to 100% because field-sizing:content sizes width to content too, and
   the 600px the form-width rule above puts on the wrapper is the width we want.

   No max-height on purpose. The textarea carries no maxlength (probed live: maxLength
   -1, a 625-character value), so a long description will render tall -- but tall is
   correct. It is the same text the instructional paragraphs above it render at full
   length, and any cap would reintroduce the "text mysteriously stops" problem this
   block exists to remove, now without a border to explain it.

   Keyed on textarea[readonly], not on .rf-read-only, and not on an id list.
   .rf-read-only was checked for and does not apply: it is present on this page five
   times but wraps a .readOnly-value div every time and never a textarea (probed live),
   because RF emits the textarea INSTEAD of that pairing. The readonly attribute is the
   only hook RF gives this state, and it is the thing that makes the box a lie. It
   covers the three places the attribute renders today (Current Session Information on
   both the Conference and the EDU session, and "Current:" on Description Change
   Request) and any read-only long-text attribute RF adds later.

   Probed live across every task page on both sessions: it reaches no editable box.
   "Request Change:" and Approval Comments on that same page keep their borders, the
   speaker modal holds no read-only textarea at all, and the decided-review fields near
   the end of this file are made inert with pointer-events, not readonly.

   Scoped to the whole portal, not to -task like the width rule above, and that is
   deliberate -- please do not "fix" it back. The ask was read-only textareas anywhere
   in this portal, and the leader review tasks (which only exist while a request is
   pending, so they could not be opened to measure) render this same attribute. Every
   non-task page was probed and renders no textarea at all, so the wider scope costs
   nothing today and covers the pages that could not be reached. Note the SPG LANDING
   page matches this selector too: its body class is
   sxsw-sxsw27-SPG-page-session-production-guide-landing, so the substring is present
   via the page slug even though the workflow URI is SPG. It renders no textarea either.

   The focus ring is deliberately left alone. The field is still tabbable, and a keyboard
   user landing on borderless text needs the ring more than a bordered one does.

   @layer base + !important, the portal cascade regime. */
@supports (field-sizing: content) {
  @layer base {
    body[class*="session-production-guide"] .wf-form-element-div textarea[readonly] {
      field-sizing: content !important;
      height: auto !important;
      overflow-y: hidden !important;
      background-color: transparent !important;
      border: 0 !important;
      border-radius: 0 !important;
      padding: 0 !important;
      width: 100% !important;
      resize: none !important;
      cursor: default !important;
    }
  }
}
/* Hide task description previews on task list page */
[class*="session-production-guide-tasks"] .task-listing-content>div{
   display: none;
}
/* Reduce spacing between tasks */
.task-listing-content h3{
    margin-top: 2px !important;
    margin-bottom: 0px !important;
}

/* alex test */
/* Session Image cropper: "Unsafe area" overlay. Keyed to the task's heading slug --
   was task-session-image---featured until the task was renamed "Session Image"
   (the rules silently stopped matching). Rename the task again, re-slug these. */
body.task-session-image .upload-file-area {
position:relative;
}

body.task-session-image .crop-image-uploader .rf-flex-frame>div {
position:relative;
}

body.task-session-image .crop-image-uploader .rf-flex-frame>div:nth-of-type(2) img {
max-width:unset !important;
max-height:unset !important;
width:100%;
}

body.task-session-image .crop-image-uploader .rf-flex-frame>div:nth-of-type(2)::after {
position:absolute;
top:1rem;
right:1rem;
width:240px;
border-radius:2rem;
height:40px;
background:#00000060;
font-weight:bold;
content:"Unsafe area";
z-index:2;
display:flex;
justify-content:center;
align-items:center;
color:white;
}

body.task-session-image .crop-image-uploader .rf-flex-frame>div:nth-of-type(2)::before {
position:absolute;
bottom:-2rem;
left:0;
width:auto;
height:40px;
font-weight:normal;
content:"Do not place subjects behind the unsafe area";
z-index:2;
display:flex;
justify-content:center;
align-items:center;
color:black;
}

/* end alex text */


div.rf-flex-initial:has(label[aria-describedby="View as Single List"]) {
    display: none;
}

/* Hide Technical nav link until January */
ul.nav li:nth-child(2) {
    display: none;
}
/* hide all task-oriented elements */
body:not(.task-leader) div.md-headline h2:nth-child(1) span[data-test="rf-badge"] {
    display: none;
}
body:not(.task-leader) .task-listing-status {
    display: none;
}
body:not(.task-leader) .task-filters {
    display: none;
}
body:not(.task-leader) div[data-test="rf-checkbox-wrapper-active-mark-complete"] {
    visibility: hidden;
}
/* ...and hidden from everyone on the eight change-request tasks: the organizer's four
   and the leader's review of each. sessions-portal.js holds the tick on those
   (reopenReviewTask/ensureMarkComplete), because filing a request and deciding one are
   each finished work that has to cross into complete for RainFocus to mail anyone. The
   box is therefore not a choice on these pages, and a control that silently re-ticks
   itself the moment it is cleared is worse than no control.

   visibility, not display, to match the rule above -- the footer reserves the gap so
   Save does not jump left when the box goes.

   Matched on slugs rather than .task-leader, which is on the tasks LIST too, where the
   box does not exist. Listed rather than globbed: the organizer's four share no prefix,
   and the deck task is "...deck-request-change" here against "...deck-request" on the
   review side. Everything not listed keeps its checkbox -- session info, tech info and
   the two image tasks are ordinary data entry someone may save half-finished.
   Keep in step with REOPEN_TASK_SLUGS in sessions-portal.js. */
body[class*="task-review/approve-"] div[data-test="rf-checkbox-wrapper-active-mark-complete"],
body.task-session-title-change-request div[data-test="rf-checkbox-wrapper-active-mark-complete"],
body.task-description-change-request div[data-test="rf-checkbox-wrapper-active-mark-complete"],
body.task-slideshare-deck-request-change div[data-test="rf-checkbox-wrapper-active-mark-complete"],
body.task-speakers div[data-test="rf-checkbox-wrapper-active-mark-complete"] {
    visibility: hidden;
}
/* Breathing room above the footer on the static pages (home, contact, technical,
   deadlines). The base zeroes .rfwf-body-content's bottom padding, so long pages
   run their last paragraph right into the footer. Unlayered on purpose: the base
   rule lives in @layer rainfocus and a @layer base copy loses to it on this page.
   50px is the amount picked by eye in DevTools on deadlines. "-page-" keeps the
   tasks and the SPG landing (…-SPG-page-session-production-guide-landing) out. */
body[class*="session-production-guide-page-"] .rfwf-body-content {
    padding-bottom: 50px;
}
/* Section break before the second h2 on the static pages. Contact and deadlines are
   each two page-builder sections (SXSW, then SXSW EDU), and every section's h2 has
   margin-top 0 -- so the EDU h2 sat 15px (just the last <p>'s margin) under the
   content above it, tighter than the 20px above each h3, and read as part of the
   previous section. 40px on any h2 that opens a section after the first one takes
   that gap to 55px; the first h2 on the page is untouched. */
@layer base {
  [class*="session-production-guide-page-"] .flex-box-section-full ~ .flex-box-section-full .keep-bullets > h2:first-child {
    margin-top: 40px !important;
  }
}
/* Underline links in bulleted lists (the contact page's "Links to Essential SXSW
   Event Information"). The base restores underlines on `.special-div p a` only --
   narrowed on purpose after a container-wide rule underlined every proposal title
   on Community Voting -- so the 12 list links there rendered as plain black text.
   .keep-bullets is the config class authored prose lists carry, which keeps RF's
   own card lists (ul.rf-card-list on home) out. Same layer + !important as the
   base rule, for the same reason: the RF workflow stylesheet's anchor rule beats
   anything weaker. */
@layer base {
  .special-div .keep-bullets li a:not([class*="mdBtnR"]):not(.button) {
    text-decoration-line: underline !important;
  }
}
[class*="session-production-guide-page-home"] ul.rf-card-list li:nth-child(2) {
    display: none;
}
[class*="session-production-guide-page-home"] ul.rf-card-list li:nth-child(3) {
    display: none;
}
/* Style all paragraph text */
 #special-div p{
  margin-bottom: 15px;
}
#special-div p a{
  font-size: 15px;
}
#special-div p u{
  font-size: 15px;
}
/* Hide add button for processed speaker change requests */
.task-processed-speaker-change-requests button.add-action{
display:none;
}
.task-processed-speaker-change-requests  button[aria-label="Delete Item"] {
    display: none;
}
.task-processed-speaker-change-requests .modal-footer{
   display: none;
}
.task-processed-speaker-change-requests .relative-select-container .rf-dropdown-trigger,
.task-processed-speaker-change-requests .relative-select-container .dropdown-icon-background {
    display: none !important;
}
.task-processed-speaker-change-requests  .relative-select-container .rf-selected-container {
  display: block !important;
}

/* Speakers joins the Processed Speaker Change Requests hide. The Speakers task
   ("Speaker Management") renders RF's standalone "Mark as complete" button rather than
   the checkbox, so the checkbox hide above misses it. sessions-portal.js still reopens
   this task on open (REOPEN_TASK_SLUGS) -- kept on purpose. */
body.task-processed-speaker-change-requests [data-analytics-name="mark-as-complete"],
body.task-speakers [data-analytics-name="mark-as-complete"]{
    display: none;
}
body.task-description-change-request #wf-1756220313237001ylk0 textarea,
body.task-session-title-change-request #wf-1756220313237001ylk0 textarea,
body.task-slideshare-deck-request-change #wf-1756220313237001ylk0 textarea{
   display: none;
}
#wf-1760203091600001x5ou{
   display:none;
}

div#wf-1761086587411001etxW {
  position: absolute !important;
  opacity: 0 !important;
  pointer-events: none !important;
  width: 1px !important;
  height: 1px !important;
  overflow: hidden !important;
  clip: rect(0, 0, 0, 0) !important;
  white-space: nowrap !important;
}
/* Relabels the card title to "All Sessions". Layered + !important for the same
   reason as the "Sessions" h1 below: if RF renders .rf-card-list-item-title as a
   heading tag, the PORTAL HEADING OVERRIDES mirror's layered !important would
   beat an unlayered, non-important font-size:0 and the real title would reappear
   next to the injected text. Layering costs nothing if it is a div. */
@layer base {
  body[class*="session-production-guide-page-home"] .rf-card-list-item-title {
    font-size: 0 !important;
  }

  body[class*="session-production-guide-page-home"] .rf-card-list-item-title::before {
    content: "All Sessions";
    font-size: 16px;
  }
}

/* Replaces the RF-supplied "Tasks" heading with "Sessions".
   MUST be in @layer base: the PORTAL HEADING OVERRIDES mirror above sets
   [class*="...-task"] h1 { font-size: 24px !important } and "-task" is a
   substring of "-tasks", so it matches this page too. Unlayered, that
   layered !important would beat the font-size:0 here and both strings
   would render ("SessionsTasks"). Inside @layer base this selector's
   higher specificity (0,1,2 vs 0,1,1) wins. */
@layer base {
  body[class*="session-production-guide-tasks"] h1 {
    font-size: 0 !important;
  }

  body[class*="session-production-guide-tasks"] h1::before {
    content: "Sessions";
    font-size: 40px;
  }
}
body.task-current-session-information .mark-complete-box{
   display: none;
}

div#wf-temp_a1760570681808,
div#wf-temp_a1760570649622 {
    display: none;
}
/* Track-leader review tasks: name the session being reviewed.

   Every session shows the track leader the same two task names, so the panel
   has to say WHICH session this is -- they are reading a lot of very similar
   copy. div#wf-formSession-title is RainFocus's read-only Title attribute and
   is already the first element inside the form, near the top of the panel,
   which is where that answer belongs.

   It used to be pulled out of flow (position:absolute; top:10px; left:20px;
   z-index:4) to pin it to the panel's top-left corner. That corner is exactly
   where the task-name h1 renders, so the two printed on top of each other --
   measured live on Review/Approve Description Change Request, the h1 occupied
   156-185px down the viewport and the title box 146-204px, both at left:169px.
   Identical numbers on Review/Approve Slideshare Deck Request.

   Left in flow instead of re-aiming the offsets: an out-of-flow box reserves no
   space, so any "sit it Npx below the heading" fix collides again the moment a
   task name or a session title wraps to another line. In flow the box is
   full-width and self-spacing -- verified live with a 150-character title, which
   stayed on one line and pushed nothing.

   The two pages do not land it in the same place, and that is RainFocus's doing,
   not this rule's: on the description task RF renders the instructions as a form
   element further down, so the title follows the h1 immediately (measured 209px vs
   the h1's 156-185px); on the slideshare task the instructions are a panel-level
   <p> BEFORE the form, so the title sits under that paragraph instead (269px).
   Both are above the fold. Welding it under the heading on both would mean hoisting
   the node in sessions-portal.js -- CSS cannot reorder it out of the form without
   dragging every other field with it.

   Hidden at the .rf-label wrapper, not just the <label> inside it: the wrapper is
   a block, so hiding only the label left an empty line above the title.

   The colour is load-bearing, not decoration: RainFocus paints .readOnly-value
   rgb(80,80,80), the same grey as the field labels around it, so an unstyled title
   reads as one more form value rather than as the answer to "which session is
   this?". var(--color-sx-dark) is #202020, which is exactly what the task-name h1
   above it computes to -- the title is that heading's subtitle, so it takes the
   heading's colour.

   @layer base + !important per the cascade note on the nav pill above. Two separate
   live measurements sit behind that, worth keeping straight:

     - Tried unlayered and un-!important first: font-size, weight, line-height and
       colour all took effect. On their own they would have been enough today.
     - Then probed font-family (var(--font-headline)) four ways, to find out why it
       was the one declaration that would not stick: unlayered normal LOST,
       unlayered !important LOST, @layer base normal LOST, @layer base !important
       WON. RF paints Founders-Text on .readOnly-value from a layer, and for
       !important declarations layer order reverses, so only a layered !important
       outranks it.

   The second result is why the first is not trusted: RF already owns a layered
   !important rule on this exact node, so the unlayered declarations survive only
   until RF extends that rule to cover them. Layering costs nothing and removes the
   trap.

   No font-family here on purpose: the h1's condensed face is available now that
   these are layered, but Founders-Text at 20px/600 already separates the title
   from both the heading and the 16px grey labels, and every declaration added is
   another one to keep winning. */
@layer base {
  body.task-review\/approve-description-change-request #wf-formSession-title .rf-label,
  body.task-review\/approve-slideshare-deck-request #wf-formSession-title .rf-label {
    display: none !important;
  }

  body.task-review\/approve-description-change-request #wf-formSession-title .readOnly-value,
  body.task-review\/approve-slideshare-deck-request #wf-formSession-title .readOnly-value {
    font-size: 20px !important;
    font-weight: 600 !important;
    line-height: 1.2 !important;
    color: var(--color-sx-dark) !important;
  }
}
/* Speakers task: shown to organizers as "Speaker Management" -- display only.

   The task keeps its RF name "Speakers" on purpose. sessions-portal.js slugs the
   heading TEXT into body.task-speakers, and ~30 rules in this file and the JS key
   off that class; renaming the task in RF (or rewriting the text with JS) would
   re-slug it and switch them all off. CSS only paints over the text, so the
   textContent the slugger reads stays "Speakers". (RF's translation for the task
   name is not editable, or that would have been the place.)

   Two places show the name:
     - Task page: the panel title h2. Scoped to the task-detail page slug the same
       way as the panel-title rule under TASK DETAIL HEADING HIERARCHY -- which it
       has to out-specify (0,5,2 vs 0,4,2) -- and so that a stale task-speakers
       class during a client-side route change cannot relabel the tasks list's
       session headers, which are the same .md-headline h2.
     - Tasks list: the row h3. Rows carry no task id (the wrapper id is a random
       uuid, re-minted every render -- verified live), so the row is found by the
       .spg-audience blocks in its hidden description preview. The Speakers task is
       the only one whose on-screen text has them today (1 of 32 rows, 2026-09-23);
       if that copy is moved to another task, or dropped from this one, this rule
       moves with it.

   visibility, not just font-size:0, so screen readers announce the new name
   rather than both. Sizes match the measured originals (20px panel title, 18px
   row); the uppercase, face and weight are inherited. */
@layer base {
  body.task-speakers[class*="session-production-guide-task"]:not([class*="session-production-guide-tasks"]) .md-frame-header .md-headline h2,
  li.rf-task-listing:has(.spg-audience) .task-listing-content > h3 {
    font-size: 0 !important;
    visibility: hidden;
  }

  body.task-speakers[class*="session-production-guide-task"]:not([class*="session-production-guide-tasks"]) .md-frame-header .md-headline h2::after {
    content: "Speaker Management";
    font-size: 20px;
    visibility: visible;
  }

  li.rf-task-listing:has(.spg-audience) .task-listing-content > h3::after {
    content: "Speaker Management";
    font-size: 18px;
    visibility: visible;
  }
}

/* Speakers task: relabel the participant list's "Add" button so it names what
   it actually starts - a request, not a direct add.

   Scoped to body.task-speakers: .add-action is the shared participant-list
   button and this portal renders it on Contacts, Members, Crew and the other
   roster tasks too, which must keep saying "Add".

   Targets the inner .mdBtnR-text span, not the button: the label lives in
   <span data-test="button-text" class="mdBtnR-text">, so font-size:0 on the
   button leaves the span at 14px and both strings render ("Request Speaker
   AddAdd" - verified live).

   Layered for the same reason as the nav pill above: RF's workflow stylesheet
   styles button.mdBtnR with a layered !important, so an unlayered !important
   loses on the button itself. It happens to win on the inner span today, but
   @layer base costs nothing here and survives RF extending that rule. */
@layer base {
  body.task-speakers button.add-action .mdBtnR-text {
    font-size: 0 !important;
  }

  body.task-speakers button.add-action .mdBtnR-text::before {
    content: "Request Speaker Add or Change";
    font-size: 14px;
  }

  /* ...and the modal it opens ("New Speaker Request") submits with RainFocus's
     "Add" too. The request can be an add or a replacement, so its confirm says so.
     body.speaker-add-modal is stamped by sessions-portal.js from the button that
     opened the modal -- the pencil's modal is the same markup on the same task.

     The span is a block with a fixed 18px line-height, so line-height is zeroed as
     well: font-size:0 alone leaves a strut line and the button grows 34px -> 39.5px
     (measured live on the leader's "Complete Request" relabel). */
  body.task-speakers.modal-open.speaker-add-modal .rf-default-modal .modal-footer button.confirm .mdBtnR-text {
    font-size: 0 !important;
    line-height: 0 !important;
  }

  body.task-speakers.modal-open.speaker-add-modal .rf-default-modal .modal-footer button.confirm .mdBtnR-text::before {
    content: "Request Speaker Add or Change";
    display: block;
    font-size: 14px;
    line-height: 18px;
  }
}

/* Speakers task, the roster pencil's modal only: hide Select Role.

   The role is not the portal user's to set from here -- the only change this modal
   offers them is a removal request, which sessions-portal.js's "Request to Remove
   Speaker" button makes for them.

   Gated on RainFocus's own modal-open, so it covers BOTH participant modals on this
   task -- the pencil's and the "Request Speaker Add or Change" flow's. An organizer never
   picks a role here: the add flow's role is chosen for them, and the pencil offers
   the removal request instead. That matters more now that the dropdown lists the
   track leader's decision roles too, which are not an organizer's to set.

   The track leader's own review task is a different body class, so their dropdown is
   untouched -- deciding is the whole point of their page.

   Visually hidden, NOT display:none. The button drives this dropdown by opening it
   and clicking an option, and RainFocus portals that option list out to
   #rf-select-results; a display:none widget never renders the list, so the role
   could never be picked. Same visually-hidden pattern as the
   div#wf-1761086587411001etxW rule above -- that one is unlayered and wins where
   it sits, this one needs the layer (see below).

   @layer base per the cascade note at the top of this file: on this portal RF
   reorders layers so an unlayered rule loses. */
@layer base {
  body.task-speakers.modal-open .rf-default-modal .rf-select.rf-single-select {
    position: absolute !important;
    opacity: 0 !important;
    pointer-events: none !important;
    width: 1px !important;
    height: 1px !important;
    overflow: hidden !important;
    clip: rect(0, 0, 0, 0) !important;
    white-space: nowrap !important;
  }

  /* The option list is portalled to the document root, so hiding the widget does
     not hide it -- it would flash on screen for the ~250ms the button spends
     picking the role. sessions-portal.js only carries this class while that runs.

     The CONTAINER has to be the thing hidden, not just the list inside it. The
     element that scrolls is .rf-scroll-frame, an ancestor of #rf-select-results,
     and RainFocus sizes the container off the trigger -- which the rule above has
     collapsed to 1px. So hiding only the list left the container painting a bare
     scrollbar: the ~16px strip down the middle of the review modal. */
  body.speaker-remove-request-running #rf-overlay-id .dropdown-results-container,
  body.speaker-role-picking #rf-overlay-id .dropdown-results-container,
  body.speaker-remove-request-running #rf-select-results,
  body.speaker-role-picking #rf-select-results {
    visibility: hidden !important;
  }
}

/* Speakers task: group the roster under a heading per role.

   sessions-portal.js stamps each row with its group, appends the three headings, and
   marks the body .speaker-roster on the two tasks that render this roster -- the
   organizer's "Speakers" and the track leader's "Review/Approve Speaker Request".
   Everything here is placement. Laid out with `order` rather than by moving nodes,
   so React's list keeps the DOM order RainFocus built it in -- see the note on
   groupSpeakerRoster() there.

   Headings are h3 so the PORTAL HEADING OVERRIDES mirror above sizes them (18px)
   against the panel's own h2 ("SPEAKERS"), which the TASK DETAIL HEADING HIERARCHY
   block above takes down to 20px -- so the roster headings still sit under it. Only
   the uppercase is local, because that mirror applies it on the tasks LIST but not
   on a task detail page. Their margins are deliberately left to that scale.

   @layer base + !important per the cascade note above. */
@layer base {
  body.speaker-roster .participants-page-body > .rfwf-panel-interior {
    display: flex !important;
    flex-direction: column !important;
  }

  body.speaker-roster .speaker-group-heading[data-group="current"] { order: 1 !important; }
  body.speaker-roster .participant-list-item.speaker-group-current { order: 2 !important; }
  body.speaker-roster .speaker-group-heading[data-group="pending"] { order: 3 !important; }
  body.speaker-roster .participant-list-item.speaker-group-pending { order: 4 !important; }
  body.speaker-roster .speaker-group-heading[data-group="reviewed"] { order: 5 !important; }
  body.speaker-roster .participant-list-item.speaker-group-reviewed { order: 6 !important; }

  /* A decided row carries its outcome the same way the comment thread does -- the
     same two tokens, the same left bar -- so the roster and the thread say the same
     thing in the same visual language. The role text beside it already says which,
     so the colour is reinforcement rather than the only signal. */
  /* !important on the padding as well as the border. Without it the padding lost to
     an unlayered rule and computed to 0, so the text sat hard against the bar with
     only the 4px border between them -- the border looked right because IT was
     important and the padding beside it silently was not. */
  body.speaker-roster .participant-list-item.speaker-decision-approved,
  body.speaker-roster .participant-list-item.speaker-decision-rejected {
    border-left: 4px solid !important;
    padding-left: 12px !important;
  }
  body.speaker-roster .participant-list-item.speaker-decision-approved {
    border-left-color: var(--color-light-green) !important;
  }
  body.speaker-roster .participant-list-item.speaker-decision-rejected {
    border-left-color: var(--color-putty) !important;
  }

  body.speaker-roster .speaker-group-heading {
    text-transform: uppercase !important;
  }

  /* The `hidden` attribute alone would lose to the flex container's own children
     rules, so an empty group's heading is hidden explicitly. */
  body.speaker-roster .speaker-group-heading[hidden] {
    display: none !important;
  }
}

/* Speakers task ONLY -- deliberately body.task-speakers, not body.speaker-roster.
   The track leader's copy of this roster keeps its pencil and trash: approving a
   request is their job, and these rules exist to stop an organizer doing in place
   what they are supposed to request.

   Leave each row only the control that is actually its own.

   A current speaker keeps the PENCIL and loses the TRASH. Taking a speaker off a
   confirmed session is a request a leader approves, not something done in place --
   that is what the pencil's "Request to Remove Speaker" button is for, and
   RainFocus's own delete would just drop the row, leaving no request and no record.
   (Precedent: the same button is already hidden on
   .task-processed-speaker-change-requests above.)

   A pending request always loses the PENCIL, and keeps the TRASH only when it is an
   ADD request. The pencil is never theirs -- a request has nothing left to edit, and
   since the pencil's modal is where a removal is requested, leaving it there would
   offer a removal request for a request. The trash is how someone withdraws a request
   they raised by mistake, which is theirs to do on an add and precisely not on a
   removal; the third rule below says why, and a pending removal is left with no
   controls at all as a result.

   Both rules ride the group classes sessions-portal.js stamps, which land on the
   first sync pass -- so on a cold load the hidden control is briefly visible before
   the stamp. The alternative is holding the whole roster hidden until the JS runs,
   which is worse on the far more common session that has no requests at all. */
@layer base {
  /* Fail CLOSED while a row is unstamped. The three rules below all key off classes
     sessions-portal.js writes in groupSpeakerRoster(), which is the LAST step of the
     sync pass -- and React owns this list, so every rebuild hands the rows back without
     their classes until the next pass lands. That is not only a cold-load flash: an
     unstamped row is the one and only state in which any of these trashes is live.

     It used to be a flash of a control that was merely early. It is not any more: with
     the trash now hidden on current, pending-remove AND reviewed rows, the only trash an
     unstamped row can offer is one of the two that delete a real speaker outright, with
     no request and no record behind it.

     So the default is "no trash", and the rules below are what hand it back. If the JS
     never runs at all, an organizer loses the ability to withdraw an add request, which
     is the recoverable direction to fail in -- the other one deletes a speaker. */
  body.task-speakers .participant-list-item:not([class*="speaker-group-"]) button[aria-label="Delete Item"] {
    display: none !important;
  }

  body.task-speakers .participant-list-item.speaker-group-current button[aria-label="Delete Item"] {
    display: none !important;
  }

  body.task-speakers .participant-list-item.speaker-group-pending button[aria-label="Edit Item"] {
    display: none !important;
  }

  /* The trash survives only on a pending ADD request, which is the only one it
     actually withdraws. That row's record was created BY the request -- the
     placeholder address is its whole reason to exist -- so deleting it takes the
     request away and nothing else with it.

     A pending REMOVE request is the opposite. It rides an existing speaker's own
     record, because the request IS their role, so the trash there does not withdraw
     anything: it deletes the speaker, which is exactly the outcome the request was
     raised to have a track leader approve. Leaving it would let any organizer skip the
     review entirely on the one row where the review matters most.

     This leaves a pending removal with no controls at all, which is the honest reading
     of it -- submitted, awaiting a decision, nothing left for the organizer to do. An
     organizer who raised one by mistake has no self-service way back; the leader
     rejects it instead, which returns the role to Speaker and is the same outcome a
     withdrawal would have reached. Jennifer's call (2026-09-01), taken over building a
     Withdraw control, on the grounds that mistakes here are rare and a wrongly deleted
     speaker is not recoverable from the portal at all. */
  body.task-speakers .participant-list-item.speaker-group-pending.speaker-request-remove button[aria-label="Delete Item"] {
    display: none !important;
  }

  /* A reviewed request keeps its PENCIL, because that is the only way an organizer
     can read the decision: the track leader's note is threaded on the speaker's own
     record, not on the session (verified live -- two speakers on one session have
     separate threads), so it is reachable nowhere else. The role dropdown is already
     hidden in their modal, and sessions-portal.js disables the modal's submit, so
     opening it is reading rather than editing.

     The trash still goes: withdrawing a decided request would destroy the record of
     the decision. */
  body.task-speakers .participant-list-item.speaker-group-reviewed button[aria-label="Delete Item"] {
    display: none !important;
  }

  /* The track leader's roster is close to the mirror image. They keep the trash on a
     CURRENT speaker -- a replacement agreed out of band is theirs to carry out, and
     making them go to the back end for it helps nobody -- but never on a request.

     A pending request is the organizer's to withdraw, and it is answered by approving
     or rejecting it, not by deleting it. Deleting a reviewed one would destroy the
     record of the decision along with the thread explaining it, which is the only
     place the organizer can read what was decided. */
  body.task-review\/approve-speaker-request .participant-list-item.speaker-group-pending button[aria-label="Delete Item"],
  body.task-review\/approve-speaker-request .participant-list-item.speaker-group-reviewed button[aria-label="Delete Item"] {
    display: none !important;
  }
}

/* Rolling comment threads: honour the line breaks, and mark a decision at a glance.

   RainFocus stores newlines in a comment body but renders it white-space:normal, so
   every line ran together (verified live -- the newlines were in the markup all
   along). pre-line restores them and still collapses stray spaces. It applies to
   comments people type as well, whose paragraph breaks were collapsing too.

   Markdown is NOT rendered here despite the md- class names -- "**bold**" posts as
   literal asterisks -- so line breaks are the only formatting available, and the
   message is written as plain lines rather than trying to fake more.

   The decision colours are a left accent bar plus a pale wash, keyed off the class
   sessions-portal.js stamps from the comment's first line. Colour only ever repeats
   what the text already says ("... -- Approved"), so nothing is lost without it.
   Both tints come from the base palette rather than new values, and each carries a
   plain fallback first for browsers without color-mix. */
@layer base {
  .wf-form-element-div .md-frame-body p {
    white-space: pre-line;
  }

  .wf-form-element-div .md-frame.review-decision-approved,
  .wf-form-element-div .md-frame.review-decision-rejected {
    border-left: 4px solid !important;
    margin-bottom: 8px;
  }

  /* !important because the "remove boxes around comments" rule above is UNLAYERED,
     and an unlayered normal declaration beats a layered one. Layered !important wins
     it back -- the same reversal the nav-pill block at the top of this file relies
     on. A comment nobody decided on keeps that rule's plain grey. */
  .wf-form-element-div .md-frame.review-decision-approved {
    border-left-color: var(--color-light-green) !important;
    background-color: #E9FAEC !important;
    background-color: color-mix(in srgb, var(--color-light-green) 22%, #fff) !important;
  }

  .wf-form-element-div .md-frame.review-decision-rejected {
    border-left-color: var(--color-putty) !important;
    background-color: #FCEEE9 !important;
    background-color: color-mix(in srgb, var(--color-putty) 22%, #fff) !important;
  }
}

/* Slideshare deck URLs: the link sessions-portal.js makes of them.

   The anchor is inline-block on its own line under the field rather than inline
   beside it, so a long URL wraps inside its own box instead of pushing the layout wide.

   Where RF draws the field read-only it prints the URL as plain text as well, so the
   same URL showed twice -- once dead, once live. The dead copy is hidden here rather
   than removed by the JS: .readOnly-value is React's own node, and detaching it both
   risks a removeChild error on the next re-render and cuts the characterData mutation
   that is how the observer learns the value changed. :has() gates this on the link
   actually being there, so a field holding something that is not a link still shows it.

   font-size is inherited rather than set: both hosts run at the 16px the rest of the
   task page's paragraphs and read-only values use, and the 14px this carried before
   made the link smaller than everything around it.

   Both !importants are load-bearing in principle: RF leaves an anchor rule unlayered
   on portal pages, and an unlayered normal declaration beats a layered one whatever
   the specificity -- which is why the plain @layer base underline lost and the link
   rendered with none at all (measured on the request-change task). Only
   text-decoration is contested today; font-size carries it so the same trick cannot
   quietly shrink the link later. Same pattern as artist-admin-branding.css. */
@layer base {
  a.sx-deck-link {
    display: inline-block;
    margin-top: 6px;
    max-width: 100%;
    overflow-wrap: anywhere;
    font-size: inherit !important;
    text-decoration: underline !important;
  }

  .wf-form-element-div:has(> a.sx-deck-link) .readOnly-value {
    display: none;
  }
}

/* Track leader's review task: the decision drives the role, so the role is not theirs
   to pick.

   Only two of the six roles are ever valid for a given row, and the other four would
   still look legitimate on the roster afterwards. sessions-portal.js derives the role
   from Speaker Request Review Status instead, and puts a line at the top of the modal
   saying what kind of request this is -- which the dropdown was the only thing
   carrying.

   The slug carries a "/", escaped here the same way the description and slideshare
   review blocks above escape theirs. */
@layer base {
  body.task-review\/approve-speaker-request.modal-open .rf-default-modal .rf-select.rf-single-select {
    position: absolute !important;
    opacity: 0 !important;
    pointer-events: none !important;
    width: 1px !important;
    height: 1px !important;
    overflow: hidden !important;
    clip: rect(0, 0, 0, 0) !important;
    white-space: nowrap !important;
  }

  /* ...but ONLY the role dropdown. Every CONFIGURED field renders as the same
     .rf-select.rf-single-select -- Pronouns, Country, State, Industry, Role
     (private), and the leader's own Speaker Request Review Status -- so the rules
     above were hiding seven controls to hide one, including the very dropdown a
     track leader decides with.

     The role widget is the only one RainFocus renders OUTSIDE a .wf-form-element-div,
     which is what separates it from anything placed on the form in config. Restoring
     them here rather than narrowing the hide keeps that distinction in one place. */
  body.task-speakers.modal-open .rf-default-modal .wf-form-element-div .rf-select.rf-single-select,
  body.task-review\/approve-speaker-request.modal-open .rf-default-modal .wf-form-element-div .rf-select.rf-single-select {
    position: static !important;
    opacity: 1 !important;
    pointer-events: auto !important;
    width: auto !important;
    height: auto !important;
    overflow: visible !important;
    clip: auto !important;
    white-space: normal !important;
  }

  /* The leader's Approval Comments is written for them when they pick a decision, so
     the compose box is not theirs to type in either. The posted history stays. */
  body.task-review\/approve-speaker-request.modal-open .rf-default-modal div#wf-1756220313237001ylk0 textarea {
    display: none !important;
  }

  /* No Add button on the review task. A track leader reviews what an organizer has
     asked for; adding a speaker from here would create one nobody requested, with no
     request behind it to decide on and nothing in the thread explaining where it came
     from. They can still edit or delete an existing row -- those act on something
     that already exists. */
  body.task-review\/approve-speaker-request button.add-action {
    display: none !important;
  }

  /* The modal's confirm button says "Add" -- RainFocus's label for the participant
     modal whatever it is doing. On a request the leader is finishing it, not adding
     anyone, so it reads "Complete Request". Pending requests only, via a class
     sessions-portal.js stamps once it knows the record: current speakers and
     already-decided requests keep RainFocus's label, and so does every modal for
     the moment before that class lands.

     Same inner-span swap as the Speakers "Request Speaker Add" relabel. The span is a
     block with a fixed 18px line-height, so font-size:0 alone leaves a strut line for
     the hidden text and the button grows 34px -> 39.5px (measured live); zeroing the
     span's line-height and giving the ::before its own keeps it level with Cancel. */
  body.task-review\/approve-speaker-request.modal-open.speaker-review-pending .rf-default-modal .modal-footer button.confirm .mdBtnR-text {
    font-size: 0 !important;
    line-height: 0 !important;
  }

  body.task-review\/approve-speaker-request.modal-open.speaker-review-pending .rf-default-modal .modal-footer button.confirm .mdBtnR-text::before {
    content: "Complete Request";
    display: block;
    font-size: 14px;
    line-height: 18px;
  }

  /* A track leader opens this modal for current speakers too -- they can edit one, or
     remove one outright, without any request having been raised. Nothing about a
     REVIEW applies to those records, so the decision fields come off.

     Gated on the role the record was OPENED with, never the one it currently carries:
     approving an add turns the chip into "Speaker" mid-flow, and hiding the status the
     leader had just set would read as the decision having been thrown away.
     sessions-portal.js decides that and carries the class. */
  body.task-review\/approve-speaker-request.speaker-review-current div#wf-1788198753772001aNyJ,
  body.task-review\/approve-speaker-request.speaker-review-current div#wf-1760380514740001i1Ve {
    display: none !important;
  }

  /* A request that has ALREADY been decided opens to be READ. Everything stays on screen --
     the decision it was given, the reason, the thread -- and the two decision fields simply
     stop taking input, so a track leader can see what happened without re-deciding it.

     Reversal is deliberately not offered, and taking the input away is what blocks it. It
     is redundant: a fresh request raised on the same person now clears the old verdict and
     reaches the leader normally, so a mistaken decision already has a working route back
     through the organizer. And it is the one path that fights RainFocus -- traced live on a
     rejected add request, the new decision holds for seconds and then dies the instant the
     derived role lands, because RainFocus reinitialises the status from the stored record
     when the role changes. What follows is worse than the reversal not being offered: this
     file's own withdrawal reads the reverted status as the leader taking it back and
     rewinds the role too, so nothing on screen says anything happened.

     pointer-events rather than the disabled property, which is a real difference: a
     disabled field is not submitted, so disabling the status would risk dropping it out of
     any save made from this modal. Inert is all that is wanted here, and inert is all this
     does -- the values stay exactly where they were, and the reason's words are selectable
     in the comment thread either way.

     Same gate as the rule above: the role the record was OPENED with, so a decision made in
     this session does not lock the modal it was just made in. */
  body.task-review\/approve-speaker-request.speaker-review-decided div#wf-1788198753772001aNyJ,
  body.task-review\/approve-speaker-request.speaker-review-decided div#wf-1760380514740001i1Ve {
    pointer-events: none !important;
  }

  /* Muted on the CONTROLS, not on their wrapper. opacity applies to the whole subtree, so
     dimming the wrapper would take the label and the note below down with it -- and the
     note is the one part of this that has to stay easy to read. */
  body.task-review\/approve-speaker-request.speaker-review-decided div#wf-1788198753772001aNyJ .rf-select,
  body.task-review\/approve-speaker-request.speaker-review-decided div#wf-1760380514740001i1Ve textarea {
    opacity: 0.62 !important;
  }

  /* Says where a reversal actually happens, rather than leaving a greyed-out field to be
     read as something broken. On the status label, because that is the control a leader
     goes looking for when they want to change their mind.

     Decided requests only -- on a pending one there is no decision to reverse and the line
     would be noise. text-transform is reset because the portal heading rules uppercase
     labels on this task, and this is a sentence. */
  body.task-review\/approve-speaker-request.speaker-review-decided div#wf-1788198753772001aNyJ .rf-label::after {
    content: "If you want to reverse this decision, please do it in FileMaker. The change will move back to RainFocus on the next sync.";
    display: block;
    margin-top: 5px;
    font-size: 0.85em;
    font-style: italic;
    font-weight: 400;
    line-height: 1.4;
    text-transform: none;
    letter-spacing: 0;
    color: #606060;
  }

  /* Speaker Request Review Status is the TRACK LEADER's field. An organizer never
     decides anything on it -- sessions-portal.js parks their request on it as "in
     review" so an outstanding request carries a status instead of a blank, and the
     leader's approve/reject replaces that. So it is hidden everywhere an organizer
     raises a request, which is now the roster modals only -- the two add-or-replace task
     pages this also covered were retired from the workflow in 2027.

     Hidden, not removed: display:none leaves the value in the form, and RainFocus
     submits what the form holds. */
  body.task-speakers.modal-open .rf-default-modal div#wf-1788198753772001aNyJ {
    display: none !important;
  }

  /* Approval Comments is one-way for an organizer. The posted history stays visible
     -- it is how they learn what the track leader decided -- but the compose box is
     hidden on every one of their modals, so the thread cannot become a channel
     anybody has to monitor. Only the textarea goes; the .md-frame entries beside it
     are the part worth reading. */
  body.task-speakers.modal-open .rf-default-modal div#wf-1756220313237001ylk0 textarea {
    display: none !important;
  }

  /* With the compose box gone, a thread nobody has written to is just a heading over
     nothing. :has() lets the whole field disappear until there is a comment to read.
     Organizer only -- the leader needs the empty box to write the first one. */
  body.task-speakers.modal-open .rf-default-modal div#wf-1756220313237001ylk0:not(:has(.md-frame)) {
    display: none !important;
  }

  /* A reviewed request is finished. Leaving the headshot upload, the daypass fields
     and the removal-request button on it offers an organizer choices that no longer
     exist -- the decision has already been made. The file-upload id carries a
     generated suffix, so it is matched on its stable prefix. */
  body.task-speakers.speaker-reviewed-modal .rf-default-modal div[id^="wf-formFileUpload"],
  body.task-speakers.speaker-reviewed-modal .rf-default-modal div#wf-1757294236717001sd8k,
  body.task-speakers.speaker-reviewed-modal .rf-default-modal div#wf-1757294700763001lK0y,
  body.task-speakers.speaker-reviewed-modal .rf-default-modal div#wf-temp_a1788111955240,
  body.task-speakers.speaker-reviewed-modal .rf-default-modal #speaker-remove-request {
    display: none !important;
  }

  /* wf-temp_a1788111955240 is the "Day Passes" heading and its two explanatory
     paragraphs -- a separate block from the two daypass FIELDS above it, which is why
     hiding those left the text behind.

     ⚠️ That is a GENERATED id, not an attribute id: re-creating the block in config
     will mint a new one and this selector will stop matching. The symptom is the Day
     Passes text reappearing on a reviewed request while the two inputs stay hidden --
     if that shows up, re-read the id rather than assuming the rule broke. */

  /* A reviewed request is finished, and an organizer reading one back has no need for
     the speaker's contact details -- asked for on data-privacy grounds (Katie).

     Gated on speaker-reviewed-modal, which sessions-portal.js sets only while the
     modal opened from a REVIEWED row is up. Not the whole task: an organizer adding a
     speaker has to type the address, and a current speaker's is theirs to see. And
     not the track leader's task at all -- they need the address to act on a request.

     The field is 1748024194176001hUAJ, "Email Address (private)" -- the attendee's
     actual address. Note it also appears in the "Clean up speaker information" list
     near the top of this file, which sets it inline-block UNLAYERED; a layered
     !important is what beats that, so this rule cannot lose its layer.

     Not the leader's two address fields ("Email", "Alt Email Address") -- those are
     on their form, not the organizer's, and they need them to act on a request.
     Daypass Request Email is left alone: it is about a daypass, not the speaker. */
  body.task-speakers.speaker-reviewed-modal .rf-default-modal div#wf-1748024194176001hUAJ {
    display: none !important;
  }
}

/* Schedule Grid */
th:nth-child(1)  .sql-report-table-header {
    min-width: 350px;
}
th:nth-child(2)  .sql-report-table-header,
th:nth-child(3)  .sql-report-table-header,
th:nth-child(4)  .sql-report-table-header,
th:nth-child(5)  .sql-report-table-header{
    min-width: 85px;
}
th:nth-child(5) .sql-report-table-header {
  min-width: 75px;
}
th:nth-child(7) .sql-report-table-header {
  min-width: 75px;
}
/* Fix with 1/9 branding changes */
.rfComp-canvas div.rf-label label{
    font-family: var(--font-primary) !important;
}
table[data-test="report-viewer"] th:nth-child(9), table[data-test="report-viewer"] td:nth-child(9) {
    display: none;
}

/* Speakers task: Conference and EDU on-screen text.

   The RainFocus config field for this task holds BOTH teams' copy, each wrapped
   in a .spg-audience block. sessions-portal.js reads the session's
   session.submission_type and marks the body .submission-conference or
   .submission-edu; these rules pick the block that matches.

   Deliberately additive -- both blocks are hidden and one is revealed, rather
   than both shown and one hidden. The class only lands after two /flow/ calls,
   so hiding the wrong block on arrival would show every EDU organizer a flash of
   the Conference wording first. Nothing shows until the answer is in, and
   sessions-portal.js guarantees an answer always arrives: every failure path
   there falls back to .submission-conference, so the panel cannot end up blank.

   The reveal carries both classes (.spg-audience.spg-audience-edu) to out-specify
   the hide rule outright rather than depending on source order.

   @layer base + !important per the cascade note at the top of this file. */
@layer base {
  body[class*="session-production-guide"] .spg-audience {
    display: none !important;
  }

  body.submission-conference .spg-audience.spg-audience-conference,
  body.submission-edu .spg-audience.spg-audience-edu {
    display: block !important;
  }

  /* Partner Programming formats. A block can carry a second limits list,
     .spg-limits.spg-limits-partner-programming, beside its standard one;
     sessions-portal.js marks the body .is-partner-programming in the same pass
     as the submission type, so the swap never flashes. Only the EDU block has
     the second list today -- a Conference+PP session keeps the Conference copy
     until a list is pasted into that block too, with no CSS change needed.

     The standard list is only hidden when its block actually HAS a partner list
     (:has), so a partner session can never end up with no limits at all. The
     reveal repeats the portal attribute to out-specify the hide outright. */
  body[class*="session-production-guide"] .spg-audience .spg-limits.spg-limits-partner-programming {
    display: none !important;
  }

  body.is-partner-programming[class*="session-production-guide"] .spg-audience .spg-limits.spg-limits-partner-programming {
    display: block !important;
  }

  body.is-partner-programming .spg-audience:has(.spg-limits-partner-programming) .spg-limits:not(.spg-limits-partner-programming) {
    display: none !important;
  }

  /* The config field now hands over real <ul>/<li> markup -- RainFocus accepted it
     (verified live 2026-09-17), so the old "one <p> per format" workaround and its
     margin rule are gone. What RF does strip is the markers and the indent, which
     left the formats reading as a run-on stack of flush-left lines: measured live,
     the <li> edge sat at the same x as the sibling <p>, i.e. no indent at all.
     Put both back. The base restores the marker for PanelPicker's panels
     (.rfwf-panel-interior ul li, sxds-rf.css) but not the indent, and that block
     is year-pinned to the sxsw27 participant pages, so it doesn't reach here.

     list-style is repeated on the <li> ON PURPOSE -- do not "simplify" it away.
     It looks redundant because list-style inherits, but RF sets it directly on
     the <li>, which beats inheritance: verified live 2026-09-17 by shipping the
     <ul> rule alone, where the <li> stayed list-style-type: none.

     Spacing below the list stays on .spg-limits so there's one owner of the gap;
     the <ul> keeps margin 0 rather than stacking a second one underneath. */
  body[class*="session-production-guide"] .spg-audience .spg-limits ul {
    list-style: disc outside !important;
    padding-left: 1.5rem !important;
    margin: 0 !important;
  }

  body[class*="session-production-guide"] .spg-audience .spg-limits li {
    list-style: disc outside !important;
    margin: 0 0 0.25rem !important;
  }

  body[class*="session-production-guide"] .spg-audience .spg-limits {
    margin: 0 0 1rem !important;
  }

  /* <strong> was already computing bold, but --font-body ("Founders-Text") ships a
     400 face only, so the browser was synthesising the weight and the bold labels
     came out smeared rather than set. The real 700 cut is its own family, which
     --font-button already points at. font-weight is stated as 700 rather than the
     base's 600 to name the real cut; both resolve to the same face, so this only
     shows in the Helvetica fallback. Scoped to .spg-audience on purpose: the
     portal's other bold text (CURRENT SPEAKERS, PENDING REQUESTS) is left alone,
     and the only bold runs inside the block are <strong> in a <p>, never in a
     heading, so no Founders-Condensed heading gets flipped to a normal width. */
  body[class*="session-production-guide"] .spg-audience strong,
  body[class*="session-production-guide"] .spg-audience b {
    font-family: var(--font-button) !important;
    font-weight: 700 !important;
  }
}

/* ===========================
   TASK FOOTER BUTTONS — black pills, matching PanelPicker
   ===========================
   Task pages rendered a form put their footer buttons ("Save", "Return to task
   list", "Mark as complete") on screen as EMPTY outlined boxes -- white text on
   a white background. Verified live 2026-09-02: the inner
   <span class="mdBtnR-text"> computed to rgb(255,255,255) while the <a> itself
   was black, so the label was there and simply invisible.

   Cause is in the base, not RainFocus. sxds-rf.css ships (@layer rainfocus):

     body #rf-content .special-div .rfwf-body-content form {
       .mdBtnR-outline-primary .mdBtnR-text { color: var(--color-white) !important; }
       .form-footer-actions button { background: var(--color-black); ...pill... }
     }

   The white-text half is scoped to a bare `body`, so it lands on EVERY portal;
   the black-pill half only fires inside .form-footer-actions. This portal's
   footer container is .workflow-footer-buttons (verified live:
   .form-footer-actions matches 0 elements here), so it collects the white text
   and never gets the dark background underneath it.

   That also explains why the bug looked intermittent: the Speakers task roster
   sits outside the <form>, so its footer buttons keep black text and render
   fine. Only form-bearing task pages break.

   Fix mirrors the base's own pill onto this portal's footer container, reusing
   the base's tokens so the two stay in step. Source is the
   .form-footer-actions button block (sxds-rf.css:1663) -- the portal-generic
   one, which is what PanelPicker renders; the .mdBtnR block at sxds-rf.css:3062
   is the same treatment but scoped to Partner Programming EDU's participant
   page, so it is a reference, not the rule being mirrored.

   DELETE THIS BLOCK once sxds-rf.css paints the pill wherever it paints the
   white label -- that is the real repair, and artist-admin-branding.css:518-535
   is already carrying its own hand-rolled copy of the same workaround.

   Scoped to .workflow-footer-buttons deliberately: .mdBtnR is RainFocus's
   generic button class, and the portal home has 10 of them as 18x18 grid
   column-options dropdown arrows (bg #f5f5f5, radius 4px). A bare .mdBtnR rule
   would turn every one of those into a black uppercase pill. The Speakers
   "Add" button (.mdBtnR-primary.add-action) also sits outside this container
   and is left alone -- it already renders black-on-white correctly.

   @layer base + !important per the cascade note at the top of this file: for
   !important declarations layer order reverses, so base beats the base file's
   own @layer rainfocus regardless of its much longer selector. */
@layer base {
  body[class*="session-production-guide"] .workflow-footer-buttons .mdBtnR {
    font-family: var(--font-button) !important;
    font-size: 0.875rem !important;
    font-weight: 600 !important;
    line-height: 1 !important;
    text-transform: uppercase !important;
    text-decoration: none !important;
    color: var(--color-white) !important;
    background: var(--color-black) !important;
    border-color: var(--color-black) !important;
    border-radius: 5rem !important;
    padding: 0.65rem 1rem !important;
    width: fit-content !important;
    position: relative !important;
    transition: all 0.25s cubic-bezier(0.075, 0.82, 0.165, 1) !important;
  }

  /* Redundant today and deliberately kept: on form pages the base already
     forces this span white, and off them it inherits white from the rule above
     (RainFocus's own .mdBtnR-text rule sets no colour -- its outline-variant
     one resolves var(--rf-comp-button-secondary-color), which is undefined on
     this event, so it dies at computed-value time). Stated explicitly so the
     label stays readable if the base's white-label rule is ever narrowed --
     which is exactly the repair being asked for above. */
  body[class*="session-production-guide"] .workflow-footer-buttons .mdBtnR .mdBtnR-text {
    color: var(--color-white) !important;
  }

  body[class*="session-production-guide"] .workflow-footer-buttons .mdBtnR:hover {
    background: var(--color-faded-black) !important;
    border-color: var(--color-faded-black) !important;
    text-decoration: none !important;
  }

  body[class*="session-production-guide"] .workflow-footer-buttons .mdBtnR:focus {
    outline: 4px solid var(--color-accent) !important;
  }

  body[class*="session-production-guide"] .workflow-footer-buttons .mdBtnR:active {
    top: 1px !important;
    background: var(--color-black) !important;
    outline: none !important;
  }
}

/* ===========================
   TASK FOOTER BAR — grey band, matching Artist Admin
   ===========================
   Mirrors artist-admin-branding.css:856-876 (RF-650) so the two portals'
   task footers read the same: a full-width grey band holding the buttons,
   with the mark-complete control on a white card inside it. Without this the
   Sessions Portal footer is a bare transparent strip with the buttons pushed
   to the right, which reads as unfinished next to Artist Admin.

   Verified live 2026-09-02 that the markup matches Artist Admin's exactly --
   div.workflow-footer-buttons > div.workflow-button-interior, with a
   .mark-complete-box for the "Mark as complete" / "Save" pair.

   Deliberately NOT in @layer base and with no !important: measured live,
   nothing else paints this container (it computed background rgba(0,0,0,0),
   radius 0, margin 0), so plain declarations win on their own. Keep it that
   way -- reach for the layered !important idiom only where something is
   actually being fought.

   The Artist Admin copy is unscoped (`div.workflow-footer-buttons`), which is
   safe there because each portal loads only its own file; scoped here anyway
   to match this file's convention. Both are candidates to delete if the grey
   footer band ever moves into sxds-rf.css. */
body[class*="session-production-guide"] div.workflow-footer-buttons {
  width: 100%;
  background: #EEE;
  border-radius: 8px;
  display: flex;
  justify-content: space-between;
  padding: 0;
  margin: 80px 0 0;
  flex-flow: row nowrap;
}

body[class*="session-production-guide"] div.workflow-footer-buttons div.workflow-button-interior {
  width: 100%;
  justify-content: space-between;
}

body[class*="session-production-guide"] div.workflow-footer-buttons .mark-complete-box {
  background: white;
  border-radius: 8px;
}
